SQL Cook: 3. 2장 연관된 여러 행 결합하기 ~

0

SQL_COOK

목록 보기
10/35
post-thumbnail

3. 2장 연관된 여러 행 결합하기

Q. 공통 열을 조인하거나 공통된 값을 공유하는 열을 조인하여, 여러 테이블에서 행을 반환하려고 한다.

예를 들어 부서값이 10인 모든 사원명과 각 사원의 부서위치 정보를 함께 표시하려하지만, 해당 데이터는 별도의 테이블에 저장되어 있다.

A. 두 테이블을 'DEPTNO'를 기준으로 조인한다.

select e.ename, d.loc
	from emp e, dept d
    where e.deptno = de.deptno
    	and e.deptno = 10
>>
ENAME	LOC
KING	NEW YORK
CLARK	NEW YORK
MILLER	NEW YORK

이는 JOIN의 한 가지 형태로, 더 정확하게는 내부 JOIN(INNER JOIN)의 한 형태인 동등 JOIN(EQUI-JOIN)이다.

  • 동등 JOIN은 조건이 동등한 것에 기반을 두는 JOIN형태다.
  • 반환된 각 행에는 각 테이블의 데이터가 포함된다.

개념적으로, JOIN의 결과셋은 다음과 같이 FROM절에 나열된 테이블에서 '데카르트 곱' 즉, '가능한 모든 행 조합'을 우선 생성하여 만들어진다.

무슨 말이냐 하면

select e.ename, d.loc
	from emp e, dept d
    where e.deptno = de.deptno
    # (위의 쿼리에서 and 자리)

일단 이까지만 돌려서 테이블을 생성한다는 뜻이다. (FROM절에 나열된 테이블부터 먼저 생성된다는 뜻)
이후 WHERE절의 식에서 결과셋을 제한하게 된다.

위 쿼리의 대체 해법은 명시적으로 JOIN절을 사용하는 것이다.

이 때, INNER 키워드는 선택사항이다.
즉, JOIN이라고만 써도 INNER JOIN과 같은 결과셋을 반환한다는 뜻이다.

select e.ename, d.loc
	# INNER JOIN이므로 두 칼럼의 값이 같은 행만 불러온다
	from emp e inner join dept d
    # 어떤 칼럼? 이에 대한 정보를 on에 써준다
    on e.deptno = d.deptno
    # 마지막으로 칼럼의 값을 조건으로 넣어준다
    where e.deptno = 10

WHERE절 대신 FROM절에 JOIN식을 사용하려면 JOIN절을 사용한다.


3. 3장 두 테이블의 공통 행 찾기

Q. 두 테이블 사이에서 공통된 행을 찾으려고 한다. 그런데 JOIN 할 수 있는 열이 여러 개다.

다음의 뷰 V를 예로 들어 살펴본다.

create view V
as
select ename, job, sal
	from emp
    where job = 'clerk';
    
select * from V;

>>
+--------+-------+------+
| ename  | job   | sal  |
+--------+-------+------+
| SMITH  | CLERK |  800 |
| ADAMS  | CLERK | 1100 |
| JAMES  | CLERK |  950 |
| MILLER | CLERK | 1300 |
+--------+-------+------+

view V는 직무가 'clerk'인 사원들의 정보를 반환하지만, 가능한 모든 'EMP' 테이블의 열은 표시하진 않는다.

이 때 view V의 행과 일치하는 'EMP' 테이블의 모든 사원의 'EMPNO', 'ENAME', 'JOB', 'SAL' 및 'DEPTNO'를 반환하려 고한다.

  • 반환하려고 하는 칼럼을 SELECT절에 집어넣는다
  • 'EMP' 테이블과 'V' 뷰를 조인한다
  • ON에 동일 칼럼 조건을 명시해준다
/* JOIN 사용 */
select e.empno, e.ename, e.job, e.sal, e.deptno 
	from emp e join v 
	on e.ename = v.ename 
	and e.job = v.job 
	and e.sal = v.sal;
>>
+-------+--------+-------+------+--------+
| empno | ename  | job   | sal  | deptno |
+-------+--------+-------+------+--------+
|  7369 | SMITH  | CLERK |  800 |     20 |
|  7876 | ADAMS  | CLERK | 1100 |     20 |
|  7900 | JAMES  | CLERK |  950 |     30 |
|  7934 | MILLER | CLERK | 1300 |     10 |
+-------+--------+-------+------+--------+
/* WHERE절에서 처리 */
select e.empno, e.ename, e.job, e.sal, e.deptno 
	from emp e, v
    where e.name = v.name
    and e.job = v.job
    and e.sal = v.sal
>>
+-------+--------+-------+------+--------+
| empno | ename  | job   | sal  | deptno |
+-------+--------+-------+------+--------+
|  7369 | SMITH  | CLERK |  800 |     20 |
|  7876 | ADAMS  | CLERK | 1100 |     20 |
|  7900 | JAMES  | CLERK |  950 |     30 |
|  7934 | MILLER | CLERK | 1300 |     10 |
+-------+--------+-------+------+--------+

Oracle Live SQL에서 Oracle의 INTERSECT를 사용해보고 싶은데 되질 않아서 답답했는데, 알고보니 Oracle에서는 WHERE절의 조건을 쓸 때 대소문자를 구별한다.

참고로 Maria는 그런 거 안 한다...

case: Oracle

# 그러고 나서 명시된 칼럼들을 포함하여 가져온다
select empno, ename, job, sal, deptno
	 from emp
    # 그 행들에 대해 아래의 칼럼세트만 뽑아낸다
	where (ename, job, sal) in (
	 # FROM이 돌아가고 나면 WHERE절이 돌아가는데
     # emp 테이블에서 가져온 칼럼들과
     select ename, job, sal from emp
	# 공통된 행들만 가져온다
    intersect
     # v에서 가져온 칼럼들을 비교해서
	 select ename, job, sal from v)

순서대로 보자면 일단

 select ename, job, sal from emp
intersect
 select ename, job, sal from v
>>

ENAME	JOB		SAL
ADAMS	CLERK	1100
JAMES	CLERK	950
MILLER	CLERK	1300
SMITH	CLERK	800

이렇게 가져온다.
ADAMS, JAMES, MILLER, SMITH가 INTERSECT의 반환 결과다.

이 상태에서 SELECT절에서 명시한 나머지 칼럼들(ADAMS, JAMES, MILLER, SMITH에 대한)을 붙이는 것이다.

INTERSECT는 집합 연산이며, 두 행 소스 중에 공통된 행을 반환한다. 따라서 같은 데이터 유형을 가진 항목 수를 비교해야 한다.

집합 연산으로 작업할 때, 기본적으로 중복 행은 반환하지 않기 때문이다.
즉, 중복으로 인해 버려지는 데이터가 생길 수 있다.


정리

  • 'JOIN'에는 두 가지가 있다.

    • 명시적으로 JOIN절을 쓸 수도 있고, WHERE절에서 조건으로 처리할 수도 있다.

    • FROM절에서 JOIN을 사용하고 싶다면 JOIN절을 사용하자

    • WHERE절에서 JOIN을 하겠다 하면 조건으로 처리하자

    • Oracle에서는 INTERSECT를 지원한다

      • 집합 연산이며 중복된 행을 반환하지 않기 때문에 사용에 주의가 필요하다

0개의 댓글