본문 바로가기

MSSQL/T-SQL

UNION에 대하여

UNION

 

Gravity DBA 이승연

 

집합 A와 집합 B가 있다고 가정을 하자. 이 두 개의 집합 A와 집합 B을 상하로 결합하여 하나의 집합으로 만들려면 UNION 이외 방법이 존재하지 않는다. UNION은 앞서 이야기 했듯이 두 개의 집합을 종적으로 결합을 하지만, UNION을 하기 위해서는 몇가지 아래와 같은 규칙을 지켜야 한다.

 

l  UNION하는 두 개의 집합은 열의 개수가 동일하여야 한다.

l  UNION하는 두 개의 집합의 열의 데이터 타입은 서로 동일하거나 변환 가능한 값이어야 한다.

l  UNION하는 두 개의 집합의 열의 데이터 타입이 서로 동일하거나 변환 가능한 값일 경우, 두 개의 데이터 타입중의 데이터 우선 순위가 높은 데이터 타입으로 형 변환이 이루어지므로 UNION시 참고해야 한다.

l  UNION은 두 개의 집합의 값 중 데이터의 중복을 제거 한다.

l  UNION ALL은 두 개의 집합의 값이 중복이 되어도 제거 하지 않는다.

 

이 몇가지 규칙에 대하여 하나하나 살펴보도록 하자.

 

첫 번째 규칙, “UNION하는 두 개의 집합은 열의 개수가 동일하여야 한다.” 이 말은 첫 번째 SELEC 절의 column 5개면 두 번째 SELECT 절에도 5개의 column이 존재해야 하고, 만약에 개수가 틀린다면 임의적으로 맞추어 주어야 한다는 의미이다. 예제를 보면서 확인 하도록 하자.

 

SELECT  *

FROM (

        SELECT  1 as 'A'

        ,       2 as 'B'

        ,       3 as 'C'

        UNION

        SELECT  4 as 'aa'

        ,       5 as 'bb'

        ,       6 as 'cc'

)AS A

 

만약, 여기에서 첫 번째 열의 개수가 4개 이고 두 번째 열의 개수가 3개이면 아래와 같은 ERROR 메시지를 만나볼 수 가 있다.

메시지205, 수준16, 상태1, 1

UNION, INTERSECT 또는EXCEPT 연산자를 사용하여 결합된 모든 쿼리의 대상 목록에는 동일한 개수의 식이 있어야 합니다.

 

두 번째 규칙, “UNION하는 두 개의 집합의 열의 데이터 타입은 서로 동일하거나 변환 가능한 값이어야 한다.” 만약에 첫 번째 SELECT절의 열은 int타입이고, 두 번째 SELECT절의 열은 char타입인데 값이 숫자로 변환이 가능하지 않은 문자이면 ERROR가 발생한다. 여기서 숫자로 변환이 가능하지 않은 문자라는 것은 이승연또는 ‘A’ 이처럼 우리가 알고 있는 진짜 문자를 말한다. 우리가 알고 있는 숫자도 문자타입에는 저장이 될 수 있지만, 숫자가 int타입이 아닌 char타입에 저장이 된다는 말은 수칙연산을 하지 않는다는 의미인 것이다. 예제를 보면서 확인 하도록 하자.

 

SELECT  *

FROM (

        SELECT  '1' as 'A'

        ,       2 as 'B'

        ,       3 as 'C'

        UNION

        SELECT  4 as 'aa'

        ,       5 as 'bb'

        ,       6 as 'cc'

)AS A

 

앞서 이야기 했지만, 위의 예제는 ERROR를 발생하지 않는다. 문자타입인 ‘1’은 숫자로 변환될 수 있는 숫자형 문자이기 때문이다.

 

SELECT  *

FROM (

        SELECT  'A' as 'A'

        ,       2 as 'B'

        ,       3 as 'C'

        UNION

        SELECT  4 as 'aa'

        ,       5 as 'bb'

        ,       6 as 'cc'

)AS A

 

이 예제는 다음과 같은 ERROR를 발생을 시킨다.

메시지245, 수준16, 상태1, 1

varchar 'A'() 데이터형식 int()로 변환하지 못했습니다.

 

세 번째 규칙, UNION하는 두 개의 집합의 열의 데이터 타입이 서로 동일하거나 변환 가능한 값일 경우, 두 개의 데이터 타입중의 데이터 우선 순위가 높은 데이터 타입으로 형 변환이 이루어지므로 UNION시 참고해야 한다.” 먼저 데이터 우선 순위에 대하여 간략하게 설명을 해야 할 것 같다. 데이터 우선순위란? 자기자신의 데이터 형식보다 더 큰 데이터형식을 말하며, 작은 데이터형식과 큰 데이터형식의 연산이 발생하게 되면 작은 데이터형식은 큰 데이터형식을 따라간다는 말이다. 간략하게 예를 들어보자면 int형은 2 32승으로 약 20억의 수를 표현을 할 수가 있다. SQL 데이터 형식에서 int형보다 큰 것은 bigint float형이 있을 수가 있다. , int+float = float 또는 int+bigint = bigint이다.

 

다음은 데이터 우선순위를 나타낸 것이다. 최상의 형식이 가장 큰 형식인 것이다. 참고하기 바란다.

데이터형식의 우선 순위

  1. 사용자 정의 데이터 형식(가장 높음)
  2. sql_variant
  3. xml
  4. datetimeoffset
  5. datetime2
  6. datetime
  7. smallldatetime
  8. date
  9. time
  10. float
  11. real
  12. decimal
  13. money
  14. smallmoney
  15. bigint
  16. int
  17. smallint
  18. tinyint
  19. bit
  20. ntext
  21. text
  22. image
  23. timestamp
  24. uniqueidentifier
  25. nvarchar(nvarchar(max) 포함)
  26. nchar
  27. varchar(varchar(max) 포함)
  28. char
  29. varbinary(varbinary(max) 포함)
  30. binary(가장낮음)

UNION시 뜻하지 않게 데이터형식이 변경될 수 있으니 주의해야 한다.

 

네 번째 규칙, UNION은 두 개의 집합의 값 중 데이터의 중복을 제거 한다 UNION은 기본적으로 중복 값을 제거 하게 되여 있다. 예제를 보자

 

SELECT * FROM (

        SELECT  *

        FROM (

               SELECT  1 as 'A', 2 as 'B', 3 as 'C'

               UNION

               SELECT  1 as 'A', 5 as 'B', 6 as 'C'

        )AS A

        UNION

        SELECT  *

        FROM (

               SELECT  1 as 'A', 2 as 'B', 3 as 'C'

               UNION

               SELECT  2 as 'A', 5 as 'B', 6 as 'C'

        )AS C

)AS B

 

위 예제를 보자. 조금 복잡해 보일 수도 있지만, 잘 보면 간단한 UNION 집합이다. 첫 번째 A집합의 값을 보게 되면 그 중에 1,2,3 값이 보일 것이다. 또한, B집합의 값에 이 1,2,3값이 동일 하게 존재하는 것을 알 수 있다. 그럼 원래는 우리가 상식적으로 생각을 해보면 A집합의 2개의 ROW B집합의 2개의 ROW UNION으로 결합을 하게 되면, 4개의 ROW가 생성이 되어야 하는데 여기에서는 3개의 ROW만을 생성을 한다. 왜냐? 1,2,3의 값이 중복이기 때문에 UNION은 기본적으로 이 중복 된 값을 제거 하고 결합을 하기 때문이다. 그리하여 결과값은 아래와 같이 출력이 된다.

 

A           B           C

-------------------------

1            2           3

1            5           6

2           5           6

(3개 행이 영향을 받음)

 

우리가 원하는 결과 일수도 있고 원하지 않은 결과 일수도 있다.

 

이제 마지막 규칙을 보자. UNION ALL은 두 개의 집합의 값이 중복이 되어도 제거 하지 않는다.” 이 전의 규칙은 UNION은 기본적으로 중복 된 값을 제거 한다고 하였다. 우리는 그 값이 원하는 값을 수도 있을 것이고, 원하지 않는 결과 값일 수도 있다고 말을 하였다. 그럼 우리는 중복된 값이 제거 되지 않고 출력 될 수 있게 하려면 어떻게 해야 하는가? 바로 UNION ALL이다.

 

SELECT * FROM (

        SELECT  *

        FROM (

               SELECT  1 as 'A', 2 as 'B', 3 as 'C'

               UNION

               SELECT  1 as 'A', 5 as 'B', 6 as 'C'

        )AS A

        UNION ALL

        SELECT  *

        FROM (

               SELECT  1 as 'A', 2 as 'B', 3 as 'C'

               UNION

               SELECT  2 as 'A', 5 as 'B', 6 as 'C'

        )AS C

)AS B

 

예제와 같이 UNION에서 UNION ALL로 변경하면 결과값은 아래와 같이 달라진다.

 

A           B           C

----------- ----------- -----------

1           2           3

1           5           6

1           2           3

2           5           6

(4개 행이 영향을 받음)

 

위의 결과 값의 굵게 표시된 값 즉, 중복된 값도 출력이 되고 있다.

UNION UNION ALL의 성능 비교를 해보면 UNION은 결과 값을 출력 하기 전에 중복되는 값을 제거하기 위해 데이터를 정렬을 시켜야 하며 이런 작업은 데이터가 커지면 상당한 부담으로 다가올 수가 있다. 반면, UNION ALL은 중복을 제거 하지 않으므로 UNION보다 상당히 빠르다고 할 수 있다. UNION을 할 경우 값들이 중복이 되어도 상관이 없다면 우리는 UNION보다 UNION ALL을 사용하도록 하자.

 

그런데, 갑자기 의문점이 생긴다.

그럼 두 개의 큰 집합이 있다고 가정하에 그 두 개의 집합이 UNION으로 결합이 되어야 하는데, 중복도 제거 되어야 한다. 라고 하면 과연 UNION ALL로 일단, 결합을 한 후에 중복을 제거 하는 것이 빠를까? 아님 UNION 으로 하는 것이 빠를까? , 각 집합 안에서도 중복된 값이 존재한다면? 어떻게 해야 빠른 것 일까?


----------------------------------------------------------
DBA 이승연
GRAVITY co., Ltd 
Global Business Dept / Tech Support

http://www.gravity.co.kr
http://www.ddoung2.com
----------------------------------------------------------

'MSSQL > T-SQL' 카테고리의 다른 글

손상된 페이지 복원  (0) 2009.06.01
union시 문자셋 에러 해결에 대하여  (3) 2009.05.08
GROUP BY에 대하여  (0) 2009.04.28
SELECT절 집계 함수  (0) 2009.04.28
SQL에서의 관계대수  (0) 2009.04.28