eff3ct's st0rage Dev Blog

[DBMS] 05. Set Operators & Nested Query

  • 한양대학교 컴퓨터소프트웨어학부 정형수 교수님의 2022년도 데이터베이스시스템및응용 강의를 듣고 정리한 내용임을 밝힙니다.
  • 내용에 오류가 있을 수 있으며, 발견 시 댓글로 알려주시면 감사하겠습니다.

5. Set Operators & Nested Query

  • 집합 연산자와 중첩된 쿼리에 대해 알아보자.

Set Operators

집합 연산하면 떠오르는 그것들을 정확히 SQL에서도 지원한다.

  1. Union (합집합)
  2. Intersect (교집합)
  3. Except (차집합)
  4. Union All (중복을 허용하는 합집합 = 멀티셋 합집합)
  5. 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가 서로 연관되어 있는 것을 확인할 수 있다.

요약

  • 쿼리는 집합 연산자, 서브 쿼리 같은 강력한 기능을 제공한다.
  • 집합 연산자는 강력하지만 코스트때문에 주의해야함.
  • 서브 쿼리를 잘 쓰면 편리합니다.