๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
๐Ÿฌ MySQL/HackerRank ํ’€์ด

[HackerRank] Occupations (Medium)

by Chloe._. 2022. 9. 20.

์–ด๋ ค์›Œ์„œ ๊ฒฐ๊ตญ ํ˜ผ์ž ๋ชป ํ’€์—ˆ๋‹ค

ํ”ผ๋ด‡ํ•˜๋Š” ๊ฑด๋ฐ ์ƒˆ๋กœ์šด๊ฑธ ์•Œ๊ฒŒ๋๋‹ค

 

์ด๋ ‡๊ฒŒ ์ƒ๊ธด ํ…Œ์ด๋ธ”์„ 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

๋Œ“๊ธ€