👩🏻‍💻직무/SQL STUDY

[SQL Study] 쿼리 '잘' 짜는 PO되기 / UNION (Feat. 인프런-중급)

Kailyim 2021. 9. 1. 01:58

오늘은 중급 강의의 마지막인 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에서도 가능)

 


하나 하나의 함수를 배우고, 단순한 쿼리를 짜는 건 쉬운데 배웠던 모든 내용이 혼합되어 한층 어려워진 문제 앞에선 쿼리를 짤 엄두가 안난다. 이건 나에게만 어려운 것이 아니라 쿼리를 짜기 시작한 모든 아마추어들에게도 어려울 것이라고 생각한다.

오늘 풀어봤던 문제를 내일 한번 더 풀어보면서 어려운 부분들을 다시 한 번 짚고 넘어가는 시간을 가져야겠다.

 

가장 중요한 것은 ⭐️ 문제에 대한 해석, 해결 방향에 대한 고민 ⭐️ 이라고 느꼈다.

내일은 오늘보다 하나만 더 기억해서 풀어보기로 약~쏙~ 🤙🏻

반응형