9.5 KiB
9.5 KiB
31강. 집합 연산
지금부터는 복수의 테이블을 사용해 데이터를 검색하는 방법에 관해 알아본다.
RDBMS의 창시자인 에드거 커드는관계형 모델을 고안한 인물이기도 하다.- 관계형 모델을 채택한 데이터베이스를 관계형 데이터베이스라 부른다.
- 관계형 모델에서의 관계형은 수학 집합론의 관계형 이론에서 유래했다.
- 집합론이라고 거창하게 말하지만 실질적으로는 데이터베이스의 데이터를 집합으로 간주해 다루기 쉽게 하자는 것에 지나지 않는다.
1. SQL과 집합
집합이라 하면 AND와 OR를 설명할 때 등장했던 벤 다이어그램을 떠올리면 쉽다.
- 벤 다이어그램에서는 하나의 원이 곧 하나의 집합이다.
- 원 안에는 몇 가지 요소가 포함되는데, 원 안에 적혀있는 숫자가 요소에 해당한다.
- 한편 데이터베이스에서는 테이블의 행이 요소에 해당한다.
- 행은 여러 개의 열로 구성되는 경우도 있으므로, 수치 상으로는 복수의 값이 존재한다.
- 하지만 집합의 요소라는 측면에서 보면 하나의 행이 곧 하나의 요소가 된다.
SELECT명령을 실행하면 데이터베이스에 질의하며 그 결과 몇 개의 행이 반환된다.- 이때 반환된 결과 전체를 하나의 집합이라고 생각하면 된다.
2. UNION으로 합집합 구하기
- 집합의 연산에는
합집합이라는 것이 있다. 이는 집합을 서로 더한 것을 말한다. - 우선 간단한 숫자를 모아놓은 집합을 이용해 설명한다.
- A와 B라는 두 개의 집합이 존재한다고 했을 때, A 집합에는 [1, 2, 3]이라는 세 개의 요소가, B 집합에는 [2, 10, 11]이라는 세 개의 요소가 있다.
- 그중 2라는 요소는 A에도 B에도 모두 존재한다.
- 집합 A와 B의 합집합을 구하면 그 결과는 [1, 2, 3, 10, 11]이 된다.
- 벤 다이어 그램으로 설명하면 두 개의 집합을 모두 합한 부분이 합집합의 결과이다.
- 이때 두 개 집합에서 겹쳐지는 부분, 즉 '요소 2'가 계산 결과로는 한 개밖에 나타나지 않는다는 점이 핵심이다.
- 즉, 단순하게 서로 더하면 [1, 2, 3, 2, 10, 11]과 같이 6개의 요소가 되지만 합집합에서는 그렇지 않다.
UNION
- SQL에서는
SELECT명령의 실행 결과를 하나의 집합으로 다룰 수 있다. - 합집합을 계산할 경우에는 수학에서 사용하던 U기호 대신
UNION키워드를 사용한다. - U는
U와 모양이 비슷해 기억하기 쉽다. 즉, 수학에서의A U B는 SQL에서는A UNION B라고 표현한다. - A나 B로 표현했지만 실제로는
SELECT명령이다. SELECT명령의 결과를 집합으로 간주하고,UNION으로 합집합을 구할 수 있다.
두 개의 SELECT 명령을 UNION해서 합집합 구하기
SELECT * FROM smaple71_a
UNION
SELECT * FROM sample71_b;
- 이때 두 개의
SELECT명령을 하나의 명령으로 합치는 만큼,세미콜론(;)은 맨 나중에 붙인다는 점에 주의해야 한다. - 만약 sample71_a 뒤에 세미콜론을 붙이면 도중에 명령이 끝나버리므로 제대로 실행되지 않는다.
- 정리하면, 한 번의 쿼리 실행으로 두 개의
SELECT명령이 내부적으로 실행되는 형식이다. - 이때 각
SELECT명령의 실행결과(집합)를 합집합(UNION)으로 계산하여 최종적으로 결과를 반환한다.
UNION으로 두 개의 SELECT 명령을 하나로 연계해 질의 결과를 얻을 수 있다!
UNION을 이용하면 여러 개의SELECT명령을 하나로 묶을 수 있다.- 1+2+3...처럼 연속해서 더하는 것과 같은 형식이다.
- 이때 각각의
SELECT명령의 열의 내용은 서로 일치해야 한다. - 예를 들어 sample71_a와 sample71_b의 경우, 열 이름은 서로 다르지만 열 개수와 자료형이 서로 같기 때문에 일치한다고 말할 수 있다.
- 반면 다음과 같이 완전히 열 구성이 다른 테이블을
UNION으로 묶을 수는 없다.
SELECT * FROM sample71_a
UNION
SELECT * FROM sample71_b
UNION
SELECT * FROM sample31;
- 다만 전체 데이터를 반환하는
애스터리스크(*)를 쓰지 않고, 열을 따로 지정하여 각SELECT명령에서 집합의 요소가 될 데이터를 서로 맞춰주면UNION으로 실행할 수 있는 쿼리가 된다. 예를 들면 다음과 같다.
SELECT a FROM sample71_a
UNION
SELECT b FROM sample71_b
UNION
SELECT age FROM sample31;
SELECT명령들을UNION으로 묶을 때 나열 순서는 합집합의 결과에 영향을 주지 않는다.- 따라서 아래의 명령들은 결과가 모두 같다.
- 단, 결괏값의 나열 순서는 달라질 수도 있다.
ORDER BY를 지정하지 않은SELECT명령은 결과가 내부처리의 상황에 따라 바뀌기 때문이다.
SELECT * FROM sample71_a UNION SELECT * FROM sample71_b;
SELECT * FROM sample71_b UNION SELECT * FROM sample71_a;
UNION을 사용할 때에는ORDER BY를 지정하는 방법에 주의해야 한다.
UNION을 사용할 때의 ORDER BY
UNION으로SELECT명령을 결합해 합집합을 구하는 경우, 각SELECT명령에ORDER BY를 지정해 정렬할 수는 없다.ORDER BY를 지정할 때는 마지막SELECT명령에만 지정하도록 한다.- 예를 들어 다음과 같은 쿼리를 실행하면 에러가 발생한다.
첫 번째 SELECT 명령에 ORDER BY를 지정할 수 없다
SELECT a FROM sample71_a ORDER BY a
UNION
SELECT b FROM sample71_b;
ORDER BY로 정렬할 수 없다는 뜻이 아니다. 합집합의 결과를 정렬하므로, 가장 마지막의SELECT명령에ORDER BY를 지정해야 한다는 의미이다.
마지막의 SELECT 명령에 ORDER BY를 지정한다
SELECT a FROM sample71_a
UNION
SELECT b FROM sample71_b ORDER BY b;
- 하지만 이 쿼리에서도 에러가 발생한다.
ORDER BY를 지정할 수 있다고 해도 마지막의SELECT명령의 결과만 정렬하는 것이 아니고 합집합의 결과를 정렬하는 것이기 때문이다. - 이때 두 개의
SELECT명령에서 열 이름이 서로 일치한다면 문제가 없겠지만 앞의 예제에서처럼 반드시 그렇다는 보장이 없다. - 이런 경우 서로 동일하게 별명을 붙여 정렬할 수 있다.
SELECT a AS c FROM sample71_a
UNION
SELECT b AS c FROM sample71_b ORDER BY c;
UNION으로 SELECT 명령을 연결하는 경우, 가장 마지막 SELECT 명령에 대해서만 ORDER BY 구를 지정할 수 있다!
ORDER BY 구에 지정하는 열은 별명을 붙여 이름을 일치시킨다!
UNION ALL
UNION은 합집합을 구하는 것이므로 두 개의 집합에서 겹치는 부분은 공통 요소가 된다.- 예를 들어 앞에서 살펴본 sample71_a와 sample71_b 예제에서는 양쪽 모두 2가 포함되어 있었다. 그리고 이들을 합집합 하면 2는 하나만 존재한다.
- 두 명령의 실행 결과에
DISTINCT를 걸어 중복을 제거한 것과 같다고 생각하면 이해하기 쉬울 것이다. - 수학에서 말하는 집합은 중복값이 존재하지 않는 것을 전제로 한다.
- 그래서
UNION을 한 결과에도 중복값이 제거되어 있다. - 하지만 경우에 따라서는 중복을 제거하지 않고 2개의
SELECT명령의 결과를 그냥 합치고 싶은 때도 있을 것이다. 이러한 경우에는UNION ALL을 사용한다. SELECT명령에서 중복을 제거할 때는SELECT구에DISTINCT를 지정한다.- 이때 기본값은
ALL로, 명시적으로 지정하거나 생략할 수도 있다. - 즉, 중복을 제거하는 경우에는
DISTINCT, 중복을 제거하지 않고 모두를 반환하는 경우에는ALL을 추가적으로 지정한다. - 즉,
DISTINCT나ALL로 중복제거 여부를 지정할 수 있다는 점은 똑같지만,UNION의 기본동작은ALL이 아닌DISTINCT라는 점이 다르다. - 또한
UNION DISTINCT라는 문법은 허용되지 않으므로 주의해야 한다.
두 개의 SELECT 명령에 UNION ALL을 적용해 합집합 구하기
SELECT * FROM sample71_a
UNION ALL
SELECT * FROM sample71_b;
- 위의 명령을 실행하면 2라는 값을 가진 행이 중복되어 표시된다.
UNION ALL은 두 개의 집합을 단순하게 합치는 것이다.UNION에서는 이미 존재하는 값인지를 검사하는 처리가 필요한 만큼,UNION ALL쪽이 성능적으로는 유리할 경우가 있다.- 즉, 중복값이 없는 경우에는
UNION ALL을 사용하는 편이 좋은 성능을 보여준다.
3. 교집합과 차집합
MySQL에서는 지원되지 않는다.- SQL을 이용해 교집합, 차집합도 구할 수 있다. 교집합은
INTERSECT를, 차집합은EXCEPT를(Oracle의 경우는MINUS) 사용한다. - 교집합이란 두 개의 집합이 겹치는 부분을 말하며,
공통 부분이라 불리기도 한다. - 차집합은 집합에서 다른 쪽의 집합을 제거하고 남은 부분이다.
- 계산 대상이 되는 두 개의 집합에 공통부분이 존재하지 않으면 차집합을 구해도 결과는 바뀌지 않는다.
- 또한 완전히 같은 집합끼리 차집합을 계산하면 아무런 요소도 존재하지 않는 공집합이 된다.
- 차집합의 결과가 공집합인지 아닌지에 따라 두 개의 집합이 동일한지 아닌지를 알 수 있다.