공대생의 공부흔적

[SQL#4] 여러 relation을 포함하는 쿼리: UNION, INTERSECT, EXCEPT 본문

Database & Big Data/SQL

[SQL#4] 여러 relation을 포함하는 쿼리: UNION, INTERSECT, EXCEPT

생대공 2024. 3. 15. 16:19

참고: Database Systems: The Complete Book (2nd edition)

지금까지는 하나의 relation에 대한 쿼리만 다루었다. 이번 글에서는 쿼리에 여러 개의 relation을 포함하는 경우 쿼리를 작성하는 법에 대해 알아볼 것이다.

데이터를 하나의 table에만 저장하는 경우 데이터 교환이 쉽고 join에 대한 비용을 회피할 수 있지만, 여러 개의 table에 나누어 저장하는 경우 데이터 업데이트가 쉽고 table에 대한 query가 더 빨라 런타임에서 이득을 볼 수 있다.


여러 relation을 포함하는 쿼리

다음과 같은 relation이 존재한다고 가정하자.

Movies(title, year, length, genre, studioName, producerCertNum)
MovieExec(name, address, certNum, netWorth)

이때, 쿼리의 FROM 구문에 다음과 같이 여러 개의 relation을 리스트로 넣을 수 있다. 즉, Movies의 title이 'Star Wars'인 영화 producerCertNum과 동일한 certNum을 갖는 MovieExec 튜플의 name을 찾고자 하는 것이다.

SELECT	name
FROM	Movies, MovieExec
WHERE	title = 'Star Wars' AND producerCertNum = certNum;

만약 다음과 같이 여러 relation에서 attirbute 이름이 동일한 경우라면,

MovieStar(name, address, gender, birthdate)
MovieExec(name, address, certNum, netWorth)

R.A notation을 사용할 수 있다.

SELECT	MovieStar.name, MovieExec.name
FROM	MovieStar, MovieExec
WHERE	MovieStar.address = MovieExec.address;

또한, 동일한 relation에서 여러 개의 튜플을 참조하고 싶은 경우 다음처럼 tuple variable을 사용할 수 있다.

SELECT	Star1.name, Star2.name
FROM	MovieStar Star1, MovieStar Star2
WHERE	Star1.address = Star2.address AND Star1.name < Star2.name;

예를 들어, 다음과 같은 relation을 바탕으로  'Alice'와 'Bob'이 모두 나오는 영화 제목를 찾는다고 하면,

Movies(title, year, length, genre, studioName)
StarsIn(movieTitle, movieYear, starName)

R.A notation과 tuple variable을 활용하여 다음과 같은 쿼리를 작성할 수 있다.

SELECT	title
FROM	Movies, StarsIn Star1, StarsIn Star2
WHERE	title = Star1.movieTitle AND title = Star2.movieTitle
	AND Star1.starName = 'Alice'
    	AND Star2.starName = 'Bob';

Nested loops

여러 개의 relation을 갖는 쿼리는 nested loop로 생각할 수 있다. select-from-where문에서 가능한 모든 튜플을 생각해본 후, 조건을 만족하는 튜플만이 정답에 기여할 수 있다. 즉 여러 개의 for문이 합쳐진 nested 루프와 동일하다.

즉, 다음과 같이 R1~Rm을 x1~xm으로 참조하여 a1~am의 attribute를 찾는 쿼리가 있다고 해보자.

SELECT	x1.a1, x2.a2, ... xm.am
FROM	R1 as x1, R2 as x2, ... Rm as xm
WHERE	Cond

이는 다음과 같은 nested loop 형태와 equivalent하다.

For x1 in R1:
	For x2 in R2:
    	...
    	For xm in Rm:
        	If Cond(x1, x2, ...):
            		output(x1.a1, x2.a2, ... xm.am)

Unions, Intersections, Differences

SQL은 UNION, INTERSECT, EXCEPT 세 개의 집합 연산을 제공한다. 이 연산들에서 디폴트로 중복이 제거되며, 중복되는 결과를 그대로 두고 싶을 때는 ALL 키워드를 사용한다.

R과 S라는 relation 모두 A라는 attribute를 가진다고 해보자.

R A S A
  1   1
  2   3

UNION

UNION은 합집합(∪)이다.

(SELECT A FROM R) UNION (SELECT A FROM S);

중복값이 제거되므로, 이 결과는 다음과 같다.

A
1
2
3

ALL을 통해서 중복되는 값을 제외하지 않고 유지할 수 있다.

(SELECT A FROM R) UNION ALL (SELECT A FROM S);
A
1
1
2
3

INTERSECT

INTERSECT는 교집합(∩)이다.

(SELECT A FROM R) INTERSECT (SELECT A FROM S);
A
1

EXCEPT

EXCEPT는 차집합(-)이다.

(SELECT A FROM R) EXCEPT (SELECT A FROM S);
A
2