sql union 연산자 : 결과를 합친다.

코딩/Sql 2020. 6. 9. 01:50

 이번 시간에는 결과를 합집합 하는 sql의 union 연산자에 대해 알아보겠습니다.

 


 select 1 As temp를 하면 어떤 값이 나올까요?

 

 

 1이 나옵니다. 네. 저는 단지 1이라는 값을 선택할 뿐입니다. 그러면, select 2 As temp는 무엇을 의미하나요? 2라는 값을 선택합니다. 이 둘을 union 하면 무엇이 될까요? 아래 쿼리를 작성해 보겠습니다.

 

 

 union 앞 뒤로 괄호로 묶여져 있다는 것을 주목해 보겠습니다. A union B로 묶였다고 했을 때, A는 1을 선택하는 것이였고, B는 2를 선택하는 것이였습니다. 1이라는 결과와 2라는 결과를 union 하면 1과 2가 나올 겁니다. 결과값을 보겠습니다.

 

 

 1과 2가 나오는군요.

 

 

 그러면 이런 식으로 작성해도 될까요? union 앞에는 1을 선택하는 겁니다. 다음에 2번째 쿼리는 (2, 2)를 선택합니다.

 

 

 열의 수가 다르기 때문에, 오류가 납니다. 이 정도만 짚고 넘어가면 좋을 듯 싶습니다. 그러면 레코드 값이 1, 2, ... , 12인 테이블은 어떻게 뽑아내면 좋을까요? 위에서 한 내용을 응용하면 어렵지 않습니다.

 

 

 저는 간단하게 select 1 As temp부터, select 12 As temp까지의 결과를 모두 합집합 하는 식으로 처리하였습니다. 결과 1과, 결과 2,. 3, 4, 5, 6, 7, 8, 9, 10, 11, 12를 모두 union 처리하면, 1부터 12까지의 결과가 나올 겁니다.

 

 

 이제 테이블과 다른 결과 테이블을 적절히 outer join을 날리면, 프로그래머스에 나온 모 SQL 문제를 해결하실 수 있습니다.

 


 자. 이제, 중복된 값이 나오게 하고 싶을 때 어떻게 처리하면 좋을지 보도록 하겠습니다.

 

 t1은 1, 2, 6이라는 결과를, t2는 1, 4, 5라는 결과를 가지고 있습니다. 이 둘을 union 하면 어떻게 될까요?

 

 

 중복된 1은 단 1번만 나옵니다. 즉, 중복된 값은 1번만 나옵니다. union 해서 '결과가 같은 값들의 중복'을 제거한다는 의미를 잘 생각해 보면, 어렵지 않습니다. 모든 중복을 유지하려고 한다면, union all을 쓰셔야 합니다. 그렇게 하면 너무 쉬우니, 요 키워드를 쓰지 않고, 모든 중복을 유지해 보겠습니다.

 

 

 그러면, dummy 값을 하나 두겠습니다. A union B라고 할 때, A의 dummy 값은 1번, B의 dummy 값은 2번입니다. A와 B와 C를 합집합 하면 A의 더미는 1, B의 더미는 2, C의 더미는 3 이렇게 올라가는 식입니다.

 

 

 이 result table에서 temp만 취하면 될 듯 싶습니다. 그러면 아래와 같이 쿼리를 작성하면 되겠군요.

 

 

 이런 식으로 작성한 다음에 결과를 보도록 하겠습니다.

 

 

 아. 그러면 이렇게 나오는 군요. 일단 의도에 맞게 잘 동작하는 것처럼 보입니다. 유니온 하는 순서대로 dummy 값을 다르게 주는 것은 생각보다 굉장히 좋은 아이디어 같아요. 그리고, 의도에 맞게 수행될 듯 싶습니다. 그런데, 이 방법은 반례가 있습니다.

 

 

 돛단배 교과서의 db를 보시면, section이라는 테이블이 있습니다. 여기서 2004년 수업들의 강의실 번호만 뽑아보겠습니다.

 

 

 113이 2개나 있습니다. 113번 강의실을 쓰는 강의가 있는 년도랑 union을 하면 어떨까요? 2004년에 있는 수업들의 강의실 번호와 1을 출력한 테이블을 T1이라 하고, 200x년에 있는 수업들의 강의실 번호와 2를 출력한 테이블을 T2라 하고, 이 둘을 union 했다고 해 보겠습니다.

 

 그러면, (113, 1)이라는 값은 중복해서 등장합니다. 당연하게도, 이러한 중복은 제거가 될 겁니다. 그러면 어떻게 해야 할까요? 각 테이블의 레코드마다, 중복되지 않을 만한, 고유한 값을 하나 더 넣으면 됩니다. 그 중 하나는, 조회된 순서대로 열 번호를 매기는 방법입니다. mysql 5.8은 이러한 역할을 하는 함수인 row_number가 있습니다.

 

 

 이런 식으로 작성하시면 됩니다. 이제 쿼리를 수행해 보겠습니다.

 

 

 2008년에 113이라는 데이터가 하나, 2004년에 2개 있었던 것이 합쳐지면서 3개가 되었습니다. 113의 중복 3개가 그대로 유지되고 있습니다. 제대로 수행이 되었습니다. 만약에 PK나 unique + not null 조건이 있는 컬럼이 있다면, row_number 함수를 넣는 대신에, 그것을 넣어도 무난합니다.

 

 저걸 쓸 바에야, union all이 지원된다면, union all을 써서 2줄만에 끝내겠네요.