오늘은 중급 강의의 마지막인 UNION, UNION ALL에 대해 배웠다.
회사 내부에서 짠 쿼리들을 살펴봤을 때 가장 많이 본 집합연산이 아닐까 싶었다.
✅ UNION (디폴트값이 DISTINCT)
- 중복값을 없앤 (DISTINCT) 값을 출력해준다.
- SELECT DISTINCT와 동일하다.
✅ UNION ALL
- 중복값을 포함한 값을 출력해준다.
UNION
You are given a table, Functions, containing two columns: X and Y.

Two pairs (X1, Y1) and (X2, Y2) are said to be symmetric pairs if X1 = Y2 and X2 = Y1.
Write a query to output all such symmetric pairs in ascending order by the value of X. List the rows such that X1 ≤ Y1.
Sample Input

Sample Output
20 20
20 21
22 23
문제부터 예사롭지 않아보이는데, 일단 이해하기론 동일행에서 Y의 값보다 작거나 큰 X값이 있는 행을 출력하라는 것이었다.
조건문에 ' X <= Y'를 넣어주면 될 것 같고, 중복된 행을 제거해서 출력해주면 될 것 같다.
중복을 제거하는건 UNION을 써주면 되는데.. 하나의 Function 테이블을 어떻게 분리해야 잘 분리할 수 있을지 모르겠다.
아 그리고 order by the value of X. List the rows such that X1 ≤ Y1. 이걸 보니 ORDER BY 절도 추가 되어야 하고, X 값 기준 오름차순 (ASC)를 추가해야겠다.
일단 테이블을 분리하지 않고, 조건문만 걸어서 아래와 같이 짜봤다.
SELECT DISTINCT *
FROM Functions
where X<=Y
총 105개의 행이 아래와 같이 출력되었다.
당연히 WRONG ANSWER이고.. 하 밤이라서 그런가 머리가 안돌아간다. 양치하고 와서 다시 생각해봐야겠다.
86 | 86 |
27 | 27 |
45 | 45 |
95 | 95 |
11 | 11 |
85 | 85 |
2 | 2 |
77 | 77 |
91 | 91 |
15 | 15 |
84 | 84 |
51 | 51 |
32 | 32 |
35 | 35 |
8 | 8 |
92 | 92 |
67 | 67 |
62 | 62 |
33 | 33 |
13 | 13 |
18 | 18 |
3 | 3 |
38 | 38 |
80 | 80 |
34 | 34 |
6 | 6 |
72 | 72 |
44 | 44 |
4 | 22 |
90 | 90 |
47 | 47 |
78 | 78 |
42 | 42 |
56 | 56 |
79 | 79 |
55 | 55 |
65 | 65 |
17 | 17 |
64 | 64 |
4 | 4 |
28 | 28 |
19 | 19 |
36 | 36 |
25 | 25 |
81 | 81 |
60 | 60 |
48 | 48 |
5 | 5 |
88 | 88 |
7 | 19 |
21 | 21 |
29 | 29 |
52 | 52 |
9 | 17 |
9 | 9 |
1 | 1 |
31 | 31 |
46 | 46 |
7 | 7 |
58 | 58 |
23 | 23 |
87 | 87 |
83 | 83 |
66 | 66 |
93 | 93 |
98 | 98 |
53 | 53 |
61 | 61 |
20 | 20 |
96 | 96 |
99 | 99 |
73 | 73 |
2 | 24 |
14 | 14 |
71 | 71 |
5 | 21 |
75 | 75 |
6 | 20 |
97 | 97 |
41 | 41 |
26 | 26 |
22 | 22 |
8 | 18 |
74 | 74 |
40 | 40 |
94 | 94 |
76 | 76 |
49 | 49 |
11 | 15 |
59 | 59 |
89 | 89 |
68 | 68 |
24 | 24 |
37 | 37 |
12 | 12 |
63 | 63 |
43 | 43 |
16 | 16 |
100 | 100 |
39 | 39 |
69 | 69 |
54 | 54 |
50 | 50 |
30 | 30 |
10 | 10 |
테이블을 서로 분리해서 UNION하고 난리 부르스를 추다가 문제 자체도 이해를 잘 못 한 것 같아서 해설 강의를 봤다.
symmetric pairs if X1 = Y2 and X2 = Y1. 이 부분에 대한 이해가 조금 부족했던 것 같다.
결국에 2개의 쌍으로 이루어진 Symmetric Pairs를 찾아야 하는 문제였다.
실제로 이 쿼리를 잡고 씨름할 때, X와 Y의 값이 같은 조건과 X와 Y의 값이 서로 다른 조건의 테이블을 분리해서 봐야겠다 정도로 생각은 했지만 생각만큼 쿼리 짜는게 쉽지 않았다.
강의를 보니 Select에 Count(*)값을 줌으로써 Symmetric 에 해당하는 숫자가 몇 개 인지 살펴볼 수 있어서 좋았다.
이런 생각까지 했으면 좋았을 텐데, 나는 이렇게 count를 출력해 볼 생각을 하지 못하는 애송이었다.
SELECT *
, count(*)
FROM Functions
WHERE X = Y
GROUP BY X, Y
ORDER BY X ASC
위 쿼리에서 GROUP BY를 쓴 건 조건이 맞는 값을 그룹핑을 해주기 위함이었다.
그리고 ORDER BY는 value of X. List the rows such that X1 ≤ Y1 문제에 이 부분을 참고하여 내가 그냥 썼다.
위 쿼리를 돌려보면 아래와 같은 결과 값이 나오는 것을 확인할 수 있다.
1 | 1 | 1 |
2 | 2 | 1 |
3 | 3 | 1 |
4 | 4 | 1 |
5 | 5 | 1 |
6 | 6 | 1 |
7 | 7 | 1 |
8 | 8 | 1 |
9 | 9 | 1 |
10 | 10 | 1 |
11 | 11 | 1 |
12 | 12 | 1 |
13 | 13 | 2 |
14 | 14 | 1 |
15 | 15 | 1 |
16 | 16 | 1 |
17 | 17 | 1 |
18 | 18 | 1 |
19 | 19 | 1 |
20 | 20 | 1 |
21 | 21 | 1 |
22 | 22 | 1 |
23 | 23 | 1 |
24 | 24 | 1 |
25 | 25 | 1 |
26 | 26 | 1 |
27 | 27 | 1 |
28 | 28 | 1 |
29 | 29 | 1 |
30 | 30 | 1 |
31 | 31 | 1 |
32 | 32 | 1 |
33 | 33 | 1 |
34 | 34 | 1 |
35 | 35 | 1 |
36 | 36 | 1 |
37 | 37 | 1 |
38 | 38 | 1 |
39 | 39 | 1 |
40 | 40 | 1 |
41 | 41 | 1 |
42 | 42 | 1 |
43 | 43 | 1 |
44 | 44 | 1 |
45 | 45 | 1 |
46 | 46 | 1 |
47 | 47 | 1 |
48 | 48 | 1 |
49 | 49 | 1 |
50 | 50 | 1 |
51 | 51 | 1 |
52 | 52 | 1 |
53 | 53 | 1 |
54 | 54 | 1 |
55 | 55 | 1 |
56 | 56 | 1 |
58 | 58 | 1 |
59 | 59 | 1 |
60 | 60 | 1 |
61 | 61 | 1 |
62 | 62 | 1 |
63 | 63 | 1 |
64 | 64 | 1 |
65 | 65 | 1 |
66 | 66 | 1 |
67 | 67 | 1 |
68 | 68 | 1 |
69 | 69 | 1 |
71 | 71 | 1 |
72 | 72 | 1 |
73 | 73 | 1 |
74 | 74 | 1 |
75 | 75 | 1 |
76 | 76 | 1 |
77 | 77 | 1 |
78 | 78 | 1 |
79 | 79 | 1 |
80 | 80 | 1 |
81 | 81 | 1 |
83 | 83 | 1 |
84 | 84 | 1 |
85 | 85 | 1 |
86 | 86 | 1 |
87 | 87 | 1 |
88 | 88 | 1 |
89 | 89 | 1 |
90 | 90 | 1 |
91 | 91 | 1 |
92 | 92 | 1 |
93 | 93 | 1 |
94 | 94 | 1 |
95 | 95 | 1 |
96 | 96 | 1 |
97 | 97 | 1 |
98 | 98 | 1 |
99 | 99 | 1 |
100 | 100 | 1 |
제일 오른 쪽에 count가 2가 나오는게 Symmetric Pairs만 구하는 것이니 Having 절에 조건을 추가하면 되겠다.
SELECT *
FROM Functions
WHERE X = Y
GROUP BY X, Y
HAVING count(*) =2
ORDER BY X ASC
이렇게 HAVING 절에 조건을 추가해주니 아래와 같은 1행을 도출하는데 성공했다.
13 | 13 |
자 이제, X와 Y의 값이 다른 테이블을 출력해주는 쿼리를 짜보았다.
SELECT
t1.X
, t1.Y
, t2.X
, t2.Y
FROM Functions AS t1
INNER JOIN Functions AS t2 ON t1.X = t2.Y AND t1.Y = t2.X
INNER JOIN을 통해 X와 Y를 t1,t2의 테이블로 분리해주고 t1테이블의 X와 T2테이블의 Y가 같고 AND t1테이블의 Y와 t2테이블의 X가 같은 값을 출력해달라고 하는 쿼리이다.
아래와 같은 테이블이 출력되었다.
86 | 86 | 86 | 86 |
27 | 27 | 27 | 27 |
45 | 45 | 45 | 45 |
95 | 95 | 95 | 95 |
11 | 11 | 11 | 11 |
8 | 18 | 18 | 8 |
85 | 85 | 85 | 85 |
2 | 2 | 2 | 2 |
77 | 77 | 77 | 77 |
91 | 91 | 91 | 91 |
15 | 15 | 15 | 15 |
84 | 84 | 84 | 84 |
51 | 51 | 51 | 51 |
32 | 32 | 32 | 32 |
35 | 35 | 35 | 35 |
8 | 8 | 8 | 8 |
92 | 92 | 92 | 92 |
67 | 67 | 67 | 67 |
62 | 62 | 62 | 62 |
33 | 33 | 33 | 33 |
13 | 13 | 13 | 13 |
13 | 13 | 13 | 13 |
11 | 15 | 15 | 11 |
18 | 18 | 18 | 18 |
3 | 3 | 3 | 3 |
38 | 38 | 38 | 38 |
80 | 80 | 80 | 80 |
34 | 34 | 34 | 34 |
6 | 6 | 6 | 6 |
72 | 72 | 72 | 72 |
44 | 44 | 44 | 44 |
22 | 4 | 4 | 22 |
90 | 90 | 90 | 90 |
47 | 47 | 47 | 47 |
78 | 78 | 78 | 78 |
42 | 42 | 42 | 42 |
56 | 56 | 56 | 56 |
79 | 79 | 79 | 79 |
55 | 55 | 55 | 55 |
65 | 65 | 65 | 65 |
17 | 17 | 17 | 17 |
64 | 64 | 64 | 64 |
4 | 4 | 4 | 4 |
28 | 28 | 28 | 28 |
19 | 19 | 19 | 19 |
9 | 17 | 17 | 9 |
36 | 36 | 36 | 36 |
25 | 25 | 25 | 25 |
81 | 81 | 81 | 81 |
60 | 60 | 60 | 60 |
48 | 48 | 48 | 48 |
5 | 5 | 5 | 5 |
88 | 88 | 88 | 88 |
21 | 21 | 21 | 21 |
29 | 29 | 29 | 29 |
52 | 52 | 52 | 52 |
17 | 9 | 9 | 17 |
9 | 9 | 9 | 9 |
13 | 13 | 13 | 13 |
13 | 13 | 13 | 13 |
1 | 1 | 1 | 1 |
31 | 31 | 31 | 31 |
46 | 46 | 46 | 46 |
7 | 7 | 7 | 7 |
58 | 58 | 58 | 58 |
23 | 23 | 23 | 23 |
87 | 87 | 87 | 87 |
83 | 83 | 83 | 83 |
66 | 66 | 66 | 66 |
93 | 93 | 93 | 93 |
2 | 24 | 24 | 2 |
98 | 98 | 98 | 98 |
53 | 53 | 53 | 53 |
6 | 20 | 20 | 6 |
61 | 61 | 61 | 61 |
20 | 20 | 20 | 20 |
96 | 96 | 96 | 96 |
99 | 99 | 99 | 99 |
73 | 73 | 73 | 73 |
24 | 2 | 2 | 24 |
14 | 14 | 14 | 14 |
71 | 71 | 71 | 71 |
21 | 5 | 5 | 21 |
4 | 22 | 22 | 4 |
75 | 75 | 75 | 75 |
20 | 6 | 6 | 20 |
97 | 97 | 97 | 97 |
41 | 41 | 41 | 41 |
26 | 26 | 26 | 26 |
22 | 22 | 22 | 22 |
18 | 8 | 8 | 18 |
74 | 74 | 74 | 74 |
40 | 40 | 40 | 40 |
5 | 21 | 21 | 5 |
94 | 94 | 94 | 94 |
76 | 76 | 76 | 76 |
49 | 49 | 49 | 49 |
15 | 11 | 11 | 15 |
59 | 59 | 59 | 59 |
89 | 89 | 89 | 89 |
68 | 68 | 68 | 68 |
24 | 24 | 24 | 24 |
37 | 37 | 37 | 37 |
12 | 12 | 12 | 12 |
63 | 63 | 63 | 63 |
43 | 43 | 43 | 43 |
16 | 16 | 16 | 16 |
100 | 100 | 100 | 100 |
39 | 39 | 39 | 39 |
69 | 69 | 69 | 69 |
54 | 54 | 54 | 54 |
50 | 50 | 50 | 50 |
30 | 30 | 30 | 30 |
10 | 10 | 10 | 10 |
Symmetric Pairs에서 X가 Y값 보다 작은 값을 출력해야 하니 WHERE 절에 조건을 걸어주었다.
t1.테이블의 X가 Y보다 작아야 하는 조건이다.
SELECT
t1.X
, t1.Y
, t2.X
, t2.Y
FROM Functions AS t1
INNER JOIN Functions AS t2 ON t1.X = t2.Y AND t1.Y = t2.X
WHERE t1.X < t1.Y
이제 실제로 나와야 하는 X값과 Y값을 출력하는 것으로 SELECT 값을 변경해주고 아까 위에 짠 쿼리와 합쳐주면!
SELECT *
FROM Functions
WHERE X = Y
GROUP BY X, Y
HAVING count(*) =2
UNION
SELECT
t1.X
, t1.Y
FROM Functions AS t1
INNER JOIN Functions AS t2 ON t1.X = t2.Y AND t1.Y = t2.X
WHERE t1.X < t1.Y
ORDER BY X ASC
2 | 24 |
4 | 22 |
5 | 21 |
6 | 20 |
8 | 18 |
9 | 17 |
11 | 15 |
13 | 13 |
이렇게 쿼리를 짜니 드디어 Congratulations! 이라는 행복한 결과값이 나왔다.
한가지 주의해야 할 점은 ORDER BY는 2번 단락 최하단에 한번만 써야한다는 것이다. 또한 디폴트 값이 ASC이므로 이 부분을 생략하고
ORDER BY X로만 해줘도 결과값이 출력된다.
해설을 듣고야 이해했지 혼자 다시 풀라고하면 잘 못 풀것 같다.
특히 INNER JOIN 하는 부분이 어려운 것 같다. 생각은 SELF JOIN을 해야지 하고 실제론 LEFT JOIN을 쓰는 우를 범했다.
또 어려웠던 건 GROUP BY와 HAVING 절이었는데 분명 이 전에 배웠는데 문제 풀 때 써먹으려고 하니 어려웠다.
한번 더 짚고 넘어 가면..
✔ GROUP BY
- 특정 조건으로 그룹핑 해주고 싶을 때
- 예) GROUP BY col1, col2 또는 GROUP BY 1,2 로 사용하는데 숫자로 사용하는 건 권장하지 않는다.
- 숫자를 권장하지 않는 건 SELECT 문에 출력하고자 하는 컬럼이 변경될 수 있기 때문이다.
✔ HAVING
- GROUP BY 결과물에 대해서 조건을 걸고 싶을 때 HAVING을 쓴다.
- 실행 순서가 GROUP BY 이후에 HAVING으로 오기 때문에 HAVING은 GROUP BY 뒤에 위치 한다.
- HAVING 절에선 AS(별명) 를 사용하여 출력할 수 있다. (ORDER BY에서도 가능)
하나 하나의 함수를 배우고, 단순한 쿼리를 짜는 건 쉬운데 배웠던 모든 내용이 혼합되어 한층 어려워진 문제 앞에선 쿼리를 짤 엄두가 안난다. 이건 나에게만 어려운 것이 아니라 쿼리를 짜기 시작한 모든 아마추어들에게도 어려울 것이라고 생각한다.
오늘 풀어봤던 문제를 내일 한번 더 풀어보면서 어려운 부분들을 다시 한 번 짚고 넘어가는 시간을 가져야겠다.
가장 중요한 것은 ⭐️ 문제에 대한 해석, 해결 방향에 대한 고민 ⭐️ 이라고 느꼈다.
내일은 오늘보다 하나만 더 기억해서 풀어보기로 약~쏙~ 🤙🏻
'👩🏻💻직무 > SQL STUDY' 카테고리의 다른 글
[SQL Study] 쿼리 '잘' 짜는 PO되기 / Update (Feat. 인프런-고급) (0) | 2021.09.06 |
---|---|
[SQL Study] 쿼리 '잘' 짜는 PO되기 / SELF JOIN (Feat. 인프런-중급) (0) | 2021.08.30 |
[SQL Study] 쿼리 '잘' 짜는 PO되기 / INNER JOIN (Feat. 인프런-중급) (0) | 2021.08.26 |