์ด๋ ค์์ ๊ฒฐ๊ตญ ํผ์ ๋ชป ํ์๋ค
ํผ๋ดํ๋ ๊ฑด๋ฐ ์๋ก์ด๊ฑธ ์๊ฒ๋๋ค
์ด๋ ๊ฒ ์๊ธด ํ ์ด๋ธ์ Doctor ๋ ์ฝ๋, Actor ๋ ์ฝ๋... ๋ก ์ง์ ๋ณ๋ก ์ด์ ๋ง๋ค๊ณ ํ๋์ ์ฌ๋์ด๋ฆ์ ๋ฃ์ผ๋ผ๋ ๋ฌธ์ ๋ค.
์ง์ ๋ณ๋ก ์ฌ๋์๊ฐ ๋ค๋ฅธ๋ฐ ๋จ๋ ํ์ NULL์ ๋ฃ๋๋ค. ์ฌ๋์ด๋ฆ์ ์ํ๋ฒณ์ ๋์ดํด์ผ ํ๋ค.
๋ฌธ์ ํ์ด ์ ์ ๊ธฐ๋ณธ๊ฐ๋ ์ ๋ฆฌ๋ฅผ ํด๋ดค๋ค.
๐ Step 0. SELF JOIN์ ๋ํด
-- ์์
SELECT t1.name, t2.name
FROM occupations t1 JOIN occupations t2
WHERE t1.name = 'Eve'
๋ฉ์ธ ํ ์ด๋ธ์ธ Occupations๋ 18rows์ด๋ค.
์์ฒ๋ผ ๊ฐ์ ํ ์ด๋ธ ๋์ ์กฐ์ธํ๊ณ Eve๋ง ๋ถ๋ฌ์ค๋ฉด ์ฒซ ๋ ์ฝ๋๋ Eve, ๋๋ฒ์งธ ๋ ์ฝ๋๋ 18๋ช ์ ์ด๋ฆ์ด ๋ค ๋ถ๋๋ค. (ํด์ปค๋ญํฌ๋ ๊ฒฐ๊ณผ๊ฐ ์ฐฝ์ ์ต๋ํ ๋๋ ค๋ 18์ค์ด ๋ค ๋ณด์ด์ง ์์์ ์บก์ณ๊ฐ ์๋ ธ๋ค)
์ฐธ๊ณ ๋ก WHERE์ ์์ด ๋ถ๋ฌ์ค๋ฉด 18*18์ 324ํ์ด ์ถ๋ ฅ๋๋ค.
์ด ๋ฌธ์ ์ ์ต์ข ๋ต์๊ณผ๋ ์๊ด์์ง๋ง ์ด๋ฒ์ ํ๋ฒ ์ ๋ฆฌํ๊ฒ ๋ผ์ ๊ธฐ๋กํ๊ณ ์ถ์๋ค.
๐ Step 0. ๋ฌธ์ํ์์ ์ฐ์ฐ์์ ๋ํด
-- ์์
SELECT t1.name, t2.name
FROM occupations t1 JOIN occupations t2
WHERE t1.name = 'Jane' AND t1.name <t2.name
์ด๋ฒ์ ์ฒ์ ์์๋๋ฐ ์ซ์ํ, ๋ ์งํ๋ฟ ์๋๋ผ ๋ฌธ์ํ์์๋ ์ฐ์ฐ์๋ฅผ ์ธ ์ ์์๋ค! alphabetic order ๊ธฐ์ค์ธ ๊ฑฐ ๊ฐ๋ค.
์ ์ฟผ๋ฆฌ๋ฅผ ํตํด Jane๋ณด๋ค ์ด๋ฆ์ด ํ์์์ธ ์ฌ๋๋ค์ ๋๋ฒ์งธ์ด์์ ๋ถ๋ฌ๋ณด์๋ค.
์ด์ ๋ฌธ์ ๋ฅผ ํ์ด๋ณด๊ฒ ๋ค.
๐ Step 1. ์ํธ์ฐ๊ด ์๋ธ์ฟผ๋ฆฌ
SELECT name
, occupation
, (SELECT COUNT(*)
FROM occupations t1
WHERE t1.occupation = t2.occupation AND t1.name < t2.name) AS rank_name
FROM occupations t2
correlated subquery๋ ์ฒ์ ์จ๋ณธ๋ค.
์ค์ฒฉ ์๋ธ์ฟผ๋ฆฌ(=nested subquery, ๋ณดํต WHERE์ ์์ ์ฐ์ฐ์์ ํจ๊ป ์) ์ค์์, ๋ณดํต์ simple subquery๋ ์๋ธ์ฟผ๋ฆฌ์ ๊ฐ์ ๋ฉ์ธ์ฟผ๋ฆฌ๊ฐ ์ด์ฉํ๋ ๋ฐฉ์์ธ ๋ฐ๋ฉด์ correlated subquery๋ ์๋ธ์ฟผ๋ฆฌ๊ฐ ๋ฉ์ธ์ฟผ๋ฆฌ๋ฅผ ์ฐธ์กฐํ๋ค.
์ํธ์ฐ๊ด ์๋ธ์ฟผ๋ฆฌ? ํ์ ์๋ธ์ฟผ๋ฆฌ? (๊ณตํต์ ์ผ๋ก ์ฝ์๋ ๋ฒ์ญ์ด ์๋์ง ๋ชจ๋ฆ)๋ ๋๊ฐ ์ฑ๋ฅ์ด ์ข์ง ์๋์ SELF JOIN์ผ๋ก ๋ฐ๊ฟ๋ณด๋ ค ํ๊ธด ํ๋๋ฐ ์์ง์ ์คํจํ๋ค. ํ ๋ฐฉ๋ฒ์ด ์๊ธด ํ๊ฑด์ง ๋ชจ๋ฅด๊ฒ ๋๋ฐ ๋์ค์ ๋์์์ ๋ ํด๋ด์ผ์ง...
์๋ฌดํผ ์ด ์ฟผ๋ฆฌ์ ๊ฒฐ๊ณผ๋ก๋ ์ด๋ฆ, ์ง์ , ๊ทธ ์ง์ ๊ตฐ ๋ด์์ ๋ณธ์ธ์ ์ด๋ฆ ์์(0๋ถํฐ ์์~)๋ฅผ ๋ฐํํ๊ณ ์๋ค.
์๋ธ์ฟผ๋ฆฌ์ WHERE์ ์์ ๊ฐ์ ์ง์ ์ ๊ฐ์ง ์ฌ๋๋ค ์ค์, ์ด๋ฆ์ด ๋ณธ์ธ๋ณด๋ค ํ์์์ธ ํ์ ์๋ฅผ COUNTํ๊ณ ์๊ณ
๋ฉ์ธ์ฟผ๋ฆฌ์SELECT์ ์์ ๋ณธ์ธ์ ์ด๋ฆ๊ณผ COUNT๊ฒฐ๊ณผ๋ฅผ ๋ถ๋ฅด๊ณ ์๋ค. RANKํจ์๋ฅผ ์ฐ์ง ์๊ณ ๋ ๋ฒํธ๋ฅผ ๋งค๊ธธ ์ ์์๋ค.
๐ Step 2. NULL์ ํฌํจํด ์ง์ ๊ณจ๋ผ๋ด๊ธฐ
SELECT
(CASE WHEN occupation = 'Doctor' THEN name ELSE null END) AS Doctor
, (CASE WHEN occupation = 'Professor' THEN name ELSE null END) AS Professor
, (CASE WHEN occupation = 'Singer' THEN name ELSE null END) AS Singer
, (CASE WHEN occupation = 'Actor' THEN name ELSE null END) AS Actor
FROM occupations
์ง์ ๋ง๋ค ์ํ ์ฌ๋์๊ฐ ๋ค๋ฅธ๋ฐ, ๊ฐ์ ๊ธธ์ด(length)๊ฐ ๋ค๋ฅธ๊ฑธ ๋์์ ๋ถ๋ฌ์ฌ ์๋ ์๋ค. (์๋์ผ๋ก ๋จ๋์นธ์ NULL๋ก ํด์ฃผ์ง ์๋๋ค)
CASE๋ฌธ์ผ๋ก ํด๋น์๋๋ฉด null์ ๋ฃ์ด์ฃผ๋ฉด ์ด๋ ๊ฒ ๊ณจ๋ผ๋ผ ์ ์๋ค.
์ด์ ์ด๊ฑธ FROM์์ occupations๊ฐ ์๋๋ผ ์์์ ๋ง๋ ์ฟผ๋ฆฌ๋ฅผ ์ธ๋ผ์ธ๋ทฐ ์๋ธ์ฟผ๋ฆฌ๋ก ์จ์ฃผ๋ฉด ๋๋๋ค.
๐ Step 3. ์์ฑ
SELECT
sub.rank_name
, MIN(CASE WHEN occupation = 'Doctor' THEN name ELSE null END) AS Doctor
, MIN(CASE WHEN occupation = 'Professor' THEN name ELSE null END) AS Professor
, MIN(CASE WHEN occupation = 'Singer' THEN name ELSE null END) AS Singer
, MIN(CASE WHEN occupation = 'Actor' THEN name ELSE null END) AS Actor
FROM (SELECT name
, occupation
, (SELECT COUNT(*)
FROM occupations t1
WHERE t1.occupation = t2.occupation AND t1.name < t2.name) AS rank_name
FROM occupations t2)
AS sub
GROUP BY sub.rank_name
ORDER BY sub.rank_name
2์์ ๋ง๋ ์ฟผ๋ฆฌ์ FROM์ ์ 1์์ ๋ง๋ ์ฟผ๋ฆฌ๋ก ๋ฃ์ด์ค๋ค.
์ด๋ฆ์๋๋ก ๋์ดํด์ผ ํ๊ธฐ์ GROUP BY์ ORDER BY๋ฅผ ํด์ค๋ค.
MIN()์ ํ ์ด์ ๋ ๋ณ๊ฑฐ ์๋๋ฐ, ํ๋ฒ์ ํ๊ฐ์ฉ๋ง ๋์์ผ ํ๊ธฐ์ ์๋ฌด ์ง๊ณํจ์๋ ์ด๊ฑฐ๋ค. MIN()์ ํ๋ MAX()๋ฅผ ํ๋ ๋๊ฐ์ด ๋์จ๋ค. ๊ฐ์ occupation์ด๋ฉด์ ๊ฐ์ sub.rank_name์ธ ๊ฒฝ์ฐ๋ ํ๋ช ๋ฐ์ ์๊ธฐ ๋๋ฌธ์ ํจ์๋ฅผ ๋ญ ์ฐ๋ ๊ฐ์ ์ฌ๋์ด ๋์จ๋ค.
ํผ๋ด์ด ์ด๋ ๊ฒ ์ด๋ ต๊ตฌ๋...! ์ฟผ๋ฆฌ์ depth๊ฐ 3์ด๋ ๋๋ค.
SET๊ณผ @+1 ์ ์ฌ์ฉํ๋ ๋ต์๋ ๋ณด๊ธด ํ๋๋ฐ ๊ทธ๋ ๊ฒ ํ์ง ์๊ณ ํธ๋ MySQL์ฟผ๋ฆฌ๋ ์ด๊ฒ ์ต์ ์ธ ๊ฑฐ ๊ฐ์๋ค.
ํนํ MySQL์ ์ง์์๋๋ ํจ์๋ฅผ ์จ์ ๋ค๋ฅธ DB๋ ๋ ๊ฐ๋จํ๊ฒ ์๊ธด ์ฟผ๋ฆฌ๋ฅผ ์ฐ๋ ๊ฑฐ ๊ฐ๊ธด ํ๋ค. PIVOT์ด๋ FULL OUTER JOIN ๊ฐ์...
์ถ๊ฐ) ์ํธ์ฐ๊ด ์๋ธ์ฟผ๋ฆฌ ๋์ RANKํจ์ ์ฌ์ฉ
SELECT
sub.rank_name
, MIN(CASE WHEN occupation = 'Doctor' THEN name ELSE null END) AS Doctor
, MIN(CASE WHEN occupation = 'Professor' THEN name ELSE null END) AS Professor
, MIN(CASE WHEN occupation = 'Singer' THEN name ELSE null END) AS Singer
, MIN(CASE WHEN occupation = 'Actor' THEN name ELSE null END) AS Actor
FROM (SELECT name
, occupation
, RANK() OVER (PARTITION BY occupation ORDER BY name) AS rank_name
FROM occupations) AS sub
GROUP BY sub.rank_name
ORDER BY sub.rank_name
์ฐธ๊ณ 1) MS SQL Server์ ๊น๋ํ ๋ต์
SELECT d.name, p.name, s.name, a.name
FROM
(SELECT name, ROW_NUMBER() OVER (PARTITION BY occupation ORDER BY name) id
FROM occupations
WHERE occupation = 'Doctor') D
FULL OUTER JOIN
(SELECT name, ROW_NUMBER() OVER (PARTITION BY occupation ORDER BY name) id
FROM occupations
WHERE occupation = 'Professor') P ON D.id = P.id
FULL OUTER JOIN
(SELECT name, ROW_NUMBER() OVER (PARTITION BY occupation ORDER BY name) id
FROM occupations
WHERE occupation = 'Singer') S ON P.id = S.id
FULL OUTER JOIN
(SELECT name, ROW_NUMBER() OVER (PARTITION BY occupation ORDER BY name) id
FROM occupations
WHERE occupation = 'Actor') A ON S.id = A.id;
์ฐธ๊ณ 2) MySQL์์ GROUP_CONCAT() ์ฌ์ฉํ ๋ต์
SELECT
GROUP_CONCAT(IF(occupation='doctor',name,NULL)) AS 'doctor'
, GROUP_CONCAT(IF(occupation='professor',name,NULL)) AS 'professor'
, GROUP_CONCAT(IF(occupation='singer',name,NULL)) AS 'singer'
, GROUP_CONCAT(IF(occupation='actor',name,NULL)) AS 'actor'
FROM (SELECT *, row_number() OVER(PARTITION BY occupation ORDER BY name) AS num
FROM OCCUPATIONS ) AS sub
GROUP BY num
ํ๋ก๊ทธ๋๋จธ์ค์ ์ฐ์ ์๊ฑฐํธ ๋ฌธ์ ์์ ์๊ฒ๋ ํจ์๋ค
GROUP_CONCAT๊ณผ IF๋ก ์ง์ ์ ๊ฐ๋ ค๋ด๊ณ row_number ์๋์ฐ๋ก ์์๋ฅผ ๊ฐ๋ ค๋๋ค.
'๐ฌ MySQL > HackerRank ํ์ด' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[HackerRank] Placements (Medium) (0) | 2022.09.28 |
---|---|
[HackerRank] Binary Tree Nodes (Medium) (1) | 2022.09.26 |
[HackerRank] The Blunder (Easy) (0) | 2022.09.16 |
[HackerRank] Type of Triangle (Easy) (0) | 2022.09.15 |
[HackerRank] Weather Observation Station 6~12 (Easy) (0) | 2022.09.15 |
๋๊ธ