데이터베이스

데이터베이스_K_Digital_chapter05

강용민 2022. 8. 18. 14:25

하나의 테이블에 원하는 데이터가 모두 있다면 좋겠지만, 두 개의 테이블을 엮어야 원하는 결과가 나오는 경우도 많다.

이때, 조인을 사용하면 두 개의 테이블을 엮어 원하는 데이터를 추출할 수 있다.

 

chapter04에서 join의 사용법과 inner join(내부 조인)을 배웠었다.

이번에는 outer join(외부 조인)과 self join , 서브쿼리에 대해서 배워볼것이다

outer join(외부 조인)

outer join은 한쪽에만 데이터가 있어도 결과가 나온다. 즉, 한 테이블에 null값이라도 데이터를 추출한다.

outer join은 크게 left outer join, right outer join, full outer join으로 나눌 수 있다.

  • left outer join : 왼쪽 테이블의 모든 값이 출력되는 조인
  • right outer join : 오른쪽 테이블의 모든 값이 출력되는 조인
  • full outer join : 왼쪽 또는 오른쪽 테이블의 모든 값이 출력되는 조인

left outer join

left outer join은 왼쪽 테이블의 모든 값이 출력되는 조인으로, 표기법은 다음과 같다.

--오라클 방식 : 조인컬럼 오른쪽에 (+) 표시한다.
select s.name, p.name from student s, professor p
where s.profno = p.profno(+);
--ANSI 방식 : 테이블 조인시 left outer join을 명시한다.
select s.name, p.name from student s left outer join professor p
where s.profno = p.profno;

right outer join

right outer join 은 오른쪽 테이블의 모든 값이 출력되는 조인으로, 표기법은 다음과 같다.

--오라클 방식  조인컬럼 왼쪽에 (+)를 표시한다.
select s.name, p.name from student s, professor p
where s.profno(+) = p.profno;

--ANSI 방식 : 테이블 조인 시 right outer join를 명시한다.
select s.name, p.name from student s right outer join professor p
where s.profno = p.profno;

full outer join

양쪽 테이블의 모든 값이 출력되는 조인으로, 표기법은 다음과 같다.

--오라클 방식 : left outer join과 right outer join을 union한다.
select s.name,p.name from student s, professor p 
where s.profno = p.profno(+)
union
select s.name, p.name from student s, professor p
where s.profno(+) = p.profno;

--ANSI 방식 full outer join을 하면된다.
select s.name, p.name from student s full outer join professor p
on s.profno = p.profno;

문제

--교수별로 교수이름과 지도학생수를 출력하기
--지도학생이 없는 교수도 조회하도록 하기
select p.name,count(s.name) from professor p,student s 
where p.profno = s.profno(+)
group by p.name;

 

self join

self join은 조인되는 테이블이 같은 경우에 사용하는 조인이며, 테이블 이름은 반드시 별명을 설정해야한다.

또한 조회되는 모든 컬럼은 별명을 붙여야 한다.

select d1.dcode as 부서코드, d1.dname as 부서명, d1.pdept, d2.dname
from dept2 d1, dept2 d2
where d1.pdept = d2.dcode(+)
order by d1.dcode;

문제

--dept2 테이블에서 상위부서명, 하위부서의 갯수 출력
--모든 부서 조회하기
select d2.dname as "상위부서명" ,count(d1.dname) as 하위부서개수 
from dept2 d1, dept2 d2
where d1.pdept(+) = d2.dcode
group by d2.dname
order by 2 desc;

 

sub query(서브쿼리)

하나의 SQL 문에 포함되어 있는 또 다른 SQL문을 말한다.

sub query는 단일행서브쿼리, 다중행서브쿼리로 나눌 수 있다.

  • 단일행 서브 쿼리 : 서브쿼리의 결과가 1개인 경우.
    • 사용가능연산자 : =, <, <=, >, >=, <>
  • 다중행서브쿼리 : 서브쿼리의 결과가 여러개인 경우.
    • 사용가능연산자 : in, [any,all]

단일행 서브 쿼리

서브쿼리가 단일 행 비교 연산자와 함께 사용할 때는 서브쿼리의 결과 건수가 반드시 1건 이하여야 한다.

만약 결과가 2건 이상인 경우 오류가 발생한다.

--예시
select s.name, s.grade, s.deptno1, d.dname
from student s, department d
where s.deptno1=d.deptno
and s.grade > (select grade from student where name = '김진욱');

--교수테이블에서 김현정 교수보다 나중에 입사한 교수의 이름, 입사일, 학과명 출력하기
select p.name,p.hiredate,d.dname
from professor p, department d
where p.deptno = d.deptno
and p.hiredate > (select hiredate from professor 
                  where name ='김현정');

다중행 서브 쿼리

서브쿼리의 결과가 2건 이상 반환될 수 있다면 반드시 다중 행 비교 연산자와 함께 사용해야 한다.

다중 행 비교 연산자는 다음과 같다.

  • In : 서브쿼리의 결과에 존재하는 임의의 값과 동일한 조건을 의미한다.
  • All : 서브쿼리의 결과에 존재하는 모든 값을 만족하는 조건을 의미한다.
  • Any : 서브쿼리의 결과에 존재하는 어느 하나의 값이라도 만족하는 조건을 의미한다.
--emp2, dept2 테이블을 이용하여 근무지역이 서울지사인 모든사원의
--사번, 이름, 부서번호 조회하기

--join방식
select e.empno,e.name,e.deptno
from emp2 e, dept2 d
where e.deptno = d.dcode
and d.area = '서울지사';

--sub query방식
select empno,name,deptno
from emp2
where deptno in (select dcode from dept2 where area='서울지사');

문제

--emp2 테이블에서 과장직급의 최소 연봉자보다 연봉이 높은사람의
--이름, 직급, 연봉(pay) 조회하기
select name,position,pay from emp2
where pay > (select min(pay) from emp2 where position = '과장');

--학생 각 학년의 최대키를 가진 학생의 학년과 이름 키를 출력하기
--1학년 중 최대키를 가진 학생의 이름 키 출력하기
select grade,name,height from student
where (grade,height) in 
(select grade, max(height) from student group by grade);

--교수 중 학과별로 입사일이 가장 빠른 교수의 교수번호, 이름, 학과명 출력
select d.dname,p.profno, p.name 
from professor p join department d
on p.deptno = d.deptno 
and (p.deptno,p.hiredate) in 
	(select deptno,min(hiredate) from professor 
    	group by deptno)
order by d.dname;

 

테스트

/*
 1. 고객테이블과 상품테이블을 조인하여 준비할 상품의 이름과, 필요수량을 출력하기.
  단 수량이 많은 순으로 정렬하기

[결과]
상품명                                                         상품수량
------------------------------------------------------------ ----------
샴푸세트                                                              3
참치세트                                                              3
세차용품세트                                                          3
벽걸이TV                                                              2
주방용품세트                                                          2
산악용자전거                                                          2
노트북                                                                2
LCD모니터                                                             2
양쪽문냉장고                                                          1

*/
select gi.gname as 상품명,count(gi.gname) as 상품수량 from gogak go , gift gi
where go.point between gi.g_start and g_end
group by gi.gname
order by 상품수량 desc;

/*
2.  교수테이블에서 교수번호, 교수이름,입사일 자신보다 입사일이 빠른사람의 인원수를 출력하기
    모든 교수정보가 조회되도록 하고, 입사일이 빠른순으로 정렬하기

[결과]
   PROFNO NAME                                     HIREDATE COUNT(P2.NAME)
---------- ---------------------------------------- -------- --------------
      1001 김명선                                   90/06/23              0
      3001 김도형                                   91/10/23              1
      4001 심슨                                     91/10/23              1
      2013 이창익                                   92/04/29              3
      4005 바비                                     95/09/18              4
      2012 장혜진                                   95/11/30              5
      1002 김명신                                   97/01/30              6
      3002 나한열                                   07/07/01              7
      1003 김자바                                   08/03/22              8
      4003 나몰라                                   09/12/01              9
      4006 비                                       10/06/28             10
      4007 김태희                                   11/05/23             11
      2011 엄호선                                   11/09/01             12
      3003 김현정                                   12/02/24             13
      4004 아이유                                   19/01/28             14
      4002 최슬기                                   19/08/30             15
*/
select p1.profno,p1.name,p1.hiredate,count(p2.name)
from professor p1, professor p2
where p1.hiredate > p2.hiredate(+)
group by p1.profno, p1.name, p1.hiredate
order by count(p1.hiredate) ;
/*
3. emp 테이블에서 사원번호,사원명,직업,상사번호,상사이름,상사의직업을 출력하기.
   모든 사원이 조회되도록 한다.
  [결과]
  사원번호 사원명               사원직업             상사번호      상사명               상사직업
---------- -------------------- ------------------ ---------- -------------------- ------------------
      7369 SMITH                CLERK                    7902        FORD                 ANALYST
      7499 ALLEN                SALESMAN              7698       BLAKE                MANAGER
      7521 WARD                SALESMAN             7698        BLAKE                MANAGER
      7566 JONES                MANAGER               7839       KING                 PRESIDENT
      7654 MARTIN              SALESMAN              7698       BLAKE                MANAGER
      7698 BLAKE                MANAGER               7839       KING                 PRESIDENT
      7782 CLARK                MANAGER               7839      KING                 PRESIDENT
      7788 SCOTT                ANALYST                 7566      JONES                MANAGER
      7839 KING                 PRESIDENT
      7844 TURNER               SALESMAN             7698      BLAKE                MANAGER
      7876 ADAMS                CLERK                    7788     SCOTT                ANALYST
      7900 JAMES                CLERK                     7698      BLAKE                MANAGER
      7902 FORD                 ANALYST                  7566     JONES                MANAGER
      7934 MILLER               CLERK                    7782       CLARK                MANAGER
*/
select e1.empno,e1.ename,e1.job,e1.mgr,e2.ename,e2.job
from emp e1, emp e2
where e1.mgr = e2.empno(+)
order by e1.empno;

/*
4. 부서테이블(department)에서 공과대학에 소속된 학과이름을 출력
[결과]
DNAME
------------------------
소프트웨어공학과
컴퓨터공학과
멀티미디어공학과
화학공학과
전자공학과
기계공학과
*/
select * from department;
select dname from department
where part in (select deptno from department 
              where part = (select deptno from department where dname = '공과대학')
              );
/*
5.학생테이블에서 전공학과가 101번인 학과의 평균몸무게보다  몸무게가 많은 학생들의 이름과 몸무게, 학과명 출력
[결과]
NAME                     WEIGHT   DNAME
-------------------- ----------  -------------------------------------
홍길동                       72       컴퓨터공학과
이사랑                       64       멀티미디어공학과
나학생                       83       전자공학과
누구야                       70       기계공학과
일지매                       72       컴퓨터공학과
김진욱                       70       멀티미디어공학과
안광훈                       82       전자공학과
노정호                       62       문헌정보학과
안은수                       63       전자공학과
인영민                       69       전자공학과
김주현                       81       멀티미디어공학과
*/
select s.name,s.weight,d.dname from student s join department d
on s.deptno1 = d.deptno 
and s.weight > (select avg(weight) from student where deptno1 = '101'); 

/*
6. 교수테이블의 심슨교수와 같은 입사일에 입사한 교수 중  김명선교수 보다 월급을 적게받는 교수의 이름, 급여, 입사일 출력
[결과]
NAME                                            PAY HIREDATE
---------------------------------------- ---------- --------
김도형                                          530 91/10/23
*/
select name,pay,hiredate from professor 
where pay< (select pay from professor where name = '김명선') 
and hiredate = (select hiredate from professor where name = '심슨');
/*
7.101번 학과 학생들의 평균 몸무게 보다  몸무게가 적은 학생의  학번과,이름과, 학과번호, 몸무게를 출력
[결과]
    STUDNO NAME                    DEPTNO1     WEIGHT
---------- -------------------- ---------- ----------
      9413 조아해                      103         52
      9511 이서진                      101         48
      9512 유해진                      102         42
      9513 오나라                      202         55
      9514 구유미                      301         58
      9515 몰라두                      201         54
      9614 김문호                      201         51
      9711 이윤나                      101         48
      9715 허우                        103         51
*/
select studno,name,deptno1,weight from student
where weight < (select avg(weight) from student where deptno1 = '101');

/*
8.  9712학생과 학년이 같고 키는 9713학생보다  큰 학생의 이름, 학년, 키를 출력
[결과]
NAME                      GRADE     HEIGHT
-------------------- ---------- ----------
안은수                        1        175
김주현                        1        179
*/
select name,grade,height from student
where grade = (select grade from student where studno = '9712') 
and height > (select height from student where studno = '9713');
/*
9. 컴퓨터정보학부에 소속된 모든 학생의 학번,이름, 학과번호 출력
   학과번호 순으로 정렬하여 출력하기
[결과]
      학번 이름                   학과번호
---------- -------------------- ----------
      9511 이서진                      101
      9411 홍길동                      101
      9611 일지매                      101
      9711 이윤나                      101
      9412 이사랑                      102
      9512 유해진                      102
      9612 김진욱                      102
      9714 김주현                      102
      9413 조아해                      103
      9715 허우                        103
*/
select studno,name,deptno1 from student
where deptno1 in (select deptno from department where part = (select deptno from department where dname = '컴퓨터정보학부'));

/*
10. 4학년학생 중 키가 제일 작은 학생보다 키가 더 작은 학생의 학번,이름,키를 출력
[결과]
    STUDNO NAME                     HEIGHT
---------- -------------------- ----------
      9511 이서진                      164
      9512 유해진                      161
      9514 구유미                      160
      9614 김문호                      166
      9711 이윤나                      162
      9715 허우                         163
*/
select studno,name,height from student where height < (select min(height) from student where grade = 4);


/*
11. 학생 중에서 생년월일이 가장 빠른 학생의 학번, 이름, 생년월일을 출력
[결과]
    STUDNO NAME                 BIRTHDAY
---------- -------------------- --------
      9412 이사랑               75/02/24
*/
select studno,name,birthday from student
where birthday = (select min(birthday) from student);
/*
12.학년별로 평균체중이 가장 적은 학년의 학년과 평균 몸무게를 출력
[결과]
     GRADE AVG(WEIGHT)
---------- -----------
         3        51.4
*/
select grade,평균 from (select grade,평균 from (select grade,avg(weight) as "평균" from student group by grade)) s1,(select min(최소값) as 최소값 from (select grade,avg(weight) as "최소값" from student group by grade)) s2 where s1.평균 = s2.최소값 ;

 

[참조]

https://hongong.hanbit.co.kr/sql-%EA%B8%B0%EB%B3%B8-%EB%AC%B8%EB%B2%95-joininner-outer-cross-self-join/#iLightbox[gallery2091]/0 

https://mozi.tistory.com/233