[DBMS] 05. Set Operators & Nested Query
31 Aug 2023- 한양대학교 컴퓨터소프트웨어학부 정형수 교수님의 2022년도 데이터베이스시스템및응용 강의를 듣고 정리한 내용임을 밝힙니다.
- 내용에 오류가 있을 수 있으며, 발견 시 댓글로 알려주시면 감사하겠습니다.
5. Set Operators & Nested Query
- 집합 연산자와 중첩된 쿼리에 대해 알아보자.
Set Operators
집합 연산하면 떠오르는 그것들을 정확히 SQL에서도 지원한다.
- Union (합집합)
- Intersect (교집합)
- Except (차집합)
- Union All (중복을 허용하는 합집합 = 멀티셋 합집합)
- Except All (중복을 허용하는 차집합 = 멀티셋 차집합)
멀티셋은 이전에 언급했던것과 같이 중복을 허용하는 집합이다.
Union
- 두 개의 테이블을 합친다.
- 중복된 행은 하나만 나오도록 한다.
SELECT *
FROM A
UNION
SELECT *
FROM B;
이런식으로 두 쿼리 결과를 합쳐서 표현할 수 있다. 이때, A와 B의 칼럼 개수는 서로 같아야하고 칼럼의 이름도 같아야한다.
a union a = a
1 3 1
2 5 2
3
5
Intersect
- 교집합을 구한다.
SELECT *
FROM A
INTERSECT
SELECT *
FROM B;
마찬가지로 칼럼의 개수와 이름이 같아야한다.
a intersect a = a
1 1 1
2 3 3
3 4
5
Except
- 차집합을 구한다.
SELECT *
FROM A
EXCEPT
SELECT *
FROM B;
역시 칼럼의 개수와 이름이 같아야한다.
a except a = a
1 1 4
4 2 6
5 5
6
Union All
- 중복을 허용하는 합집합을 구한다.
SELECT *
FROM A
UNION ALL
SELECT *
FROM B;
a union all a = a
1 1 1
2 2 2
3 3 3
1
2
3
Except All
- 중복을 허용하는 차집합을 구한다.
- 개인적으로 가장 Tricky하다고 생각한다. 별로 쓸 일도 없고 지원하지 않는 DB들이 많다.
- 중복되어 있는 원소가 있으면 그 원소를 제거하지 않고 살려두는 연산인데 쉽지 않다.
SELECT *
FROM A
EXCEPT ALL
SELECT *
FROM B;
a except all a = a
1 1 1
1 2
2
나는 무슨 연산인지 아직도 잘 모르겠다.
Nested Query (Sub Query)
쿼리 안에 쿼리가 들어있으면 Nested Query라고 한다.
ALL
ALL은 쿼리 결과의 모든 행에 대해하여 어떤 조건을 만족하는 지 확인하는 것이다. 말이 조금 어려운데, 1반 학생들이 2반 학생들 모두보다 성적이 높은 지 확인하고 싶은 이런 상황에 사용하면 된다.
SELECT *
FROM Student
WHERE Class = 1
AND Score > ALL (
SELECT Score
FROM Student
WHERE Class = 2
);
이런식으로 작성하면, 위에서 말한 예시처럼 쿼리를 만들 수 있다. 오호~ 그렇다면, 1반 학생들 중에 2반 학생들 아무나와 성적이 같은 학생들을 찾고 싶다면 어떻게 하면 될까?
ANY
ANY는 그런 상황에 사용할 수 있다. 아무나 하나 존재하기만 하면 될 때 사용하면 된다.
SELECT *
FROM Student
WHERE Class = 1
AND Score = ANY (
SELECT Score
FROM Student
WHERE Class = 2
);
IN
IN은 집합론에서 \(\in\)과 같은 의미이다.
SELECT *
FROM Student
WHERE Class = 1
AND Score IN (
SELECT Score
FROM Student
WHERE Class = 2
);
위의 ANY 쿼리와 같은 의미를 가지도록 사용할 수 있다.
EXISTS
EXISTS는 쿼리 결과가 존재하는 지 확인하는 것이다.
SELECT *
FROM Student AS S1
WHERE Class = 1
AND EXISTS (
SELECT *
FROM Student AS S2
WHERE Class = 2
AND S1.Score = S2.Score
);
위의 IN 쿼리와 같은 의미를 가지도록 사용할 수 있다. 이렇게 여러 연산들로 같은 쿼리를 다양하게 표현할 수 있다.
NOT
NOT은 결과를 반대로 바꾸는 연산자이다.
SELECT *
FROM Student AS S1
WHERE Class = 1
AND NOT EXISTS (
SELECT *
FROM Student AS S2
WHERE Class = 2
AND S1.Score = S2.Score
);
이렇게 사용하면, 1반 중 2반 학생들과 성적이 같지 않은 학생들을 찾을 수 있다. 물론 그냥 AND 조건에다가 <>를 넣는것으로 해결할 수 있는데, 예시가 잘 안떠올라서 이렇게 썼다.
Correlated Query
위 예시에서 숨쉬듯 자연스럽게 쿼리를 서로 연관시켜서 써놓은 것을 볼 수 있다. 이게 바로 Correlated Query이다. 메인 쿼리와 서브 쿼리 끼리 서로 연관되어 있는 쿼리들을 말한다.
SELECT *
FROM Student AS S1
WHERE Class = 1
AND EXISTS (
SELECT *
FROM Student AS S2
WHERE Class = 2
AND S1.Score = S2.Score
);
이런 것처럼 S1과 S2가 서로 연관되어 있는 것을 확인할 수 있다.
요약
- 쿼리는 집합 연산자, 서브 쿼리 같은 강력한 기능을 제공한다.
- 집합 연산자는 강력하지만 코스트때문에 주의해야함.
- 서브 쿼리를 잘 쓰면 편리합니다.