๐ ๋ณธ ํฌ์คํ ์์ ์ฌ์ฉ๋๋ ํ ์ด๋ธ์ ์๋ฃ์ ์ถ์ฒ๋ HackerRank ์์ ๋ฐํ๋๋ค. ๋ ๋ค์ํ SQL ๋ฌธ์ ๋ฅผ ํ์ด๋ณด์๋ ค๋ฉด HackerRank ์ฌ์ดํธ๋ฅผ ๋ฐฉ๋ฌธํด ๋ณด์ธ์!
์ด๋ฒ ํฌ์คํ ์์๋ SQL๋ก ์์(Prime Number)๋ฅผ ์ถ๋ ฅํด๋ณด๋ ๋ฌธ์ ๋ฅผ ํ์ด๋ณด๋ ค๊ณ ํ๋ค. ํด๋น ๋ฌธ์ ๋ฅผ ํ๊ธฐ ์ํด์ MySQL์ Stored Procedure๋ฅผ ์ฐธ๊ณ ํด์ ํ๊ธฐ๋ ํ์ง๋ง ์ผ๋ฐ์ ์ธ ์ฟผ๋ฆฌ๋ฌธ์ ํตํด ํด๊ฒฐํ ์ ์๋ ํ์ด๋ฅผ ์๊ฐํ๊ธฐ ์ํด Discussion์ ๋ค๋ฅธ ๋ถ์ ๋ฐ์ด๋ ํ์ด๋ฅผ ์ฐธ๊ณ ํ๋ค.
ํ์ง๋ง ๋ฌธ์ ๋ฅผ ํด๊ฒฐํด๋๊ฐ๋ฉด์ MySQL์ Procedure๋ผ๋ ๊ฒ์ ๋ํด ์๊ฒ ๋์๊ณ Procedure
์์์ WHILE
, LOOP
, ITERATE
, IF
๋ฑ ๋ค์ํ ๋ฌธ๋ฒ์ ์ฌ์ฉํ ์ ์๋ค๋ ์ฌ์ค๋ ์๊ฒ ๋์๋ค. ์ด์ ๋ํด ์์ธํ ์๊ณ ์ถ๋ค๋ฉด ์ฌ๊ธฐ๋ฅผ ํด๋ฆญํด ํ์ธํด๋ณด์. ๊ทธ๋ฆฌ๊ณ ์ด Procedure๋ฅผ ํ์ฉํด ์์๋ฅผ ๊ตฌํ๋ ํ์ด์ ํ๋ ์์ ์ฌ๊ธฐ๋ฅผ ํตํด ์ดํด๋ณด์.
์ด๋ฒ ํฌ์คํ ์์ ํด๊ฒฐํ๋ ๋ฐฉ๋ฒ์ ํ์์ ์ฌ์ฉํด์๋ ์ผ๋ฐ์ ์ธ ์ฟผ๋ฆฌ์ ์๋ธ์ฟผ๋ฆฌ๋ฅผ ์ด์ฉํด ํ์ด๋ณด๋ ค ํ๋ค. ๋จ์ํ SQL ๊ตฌ๋ฌธ๋ง ๋ณด์์๋ ์ง๊ด์ ์ผ๋ก ํ์ด๊ฐ ์ ๋ฟ์ง ์์ผ๋ฏ๋ก ๋ฌธ์ ์๋ณธ์ ๋ค์ด๊ฐ ์ฟผ๋ฆฌ๋ฅผ ํ๋ํ๋์ฉ ์ถ๋ ฅํด ์ดํด๋ณด๋ ๊ฒ์ ๊ถ์ฅํ๋ค.
์ฐ์ ๋ฌธ์ ์์ ์๊ตฌํ๋ ์ฌํญ์ ๋ค์๊ณผ ๊ฐ๋ค.
Write a query to print allprime numbersless than or equal to 1000. Print your result on a single line, and use the ampersand ('&') character as your separator (instead of a space).
(1000 ์ดํ์ ์์ฐ์๋ค ์ค ๋ชจ๋ ์์๊ฐ๋ค์ ํ๋์ ์ค๋ก ์ถ๋ ฅํด๋ผ. ์ด ๋ ์์๊ฐ๋ค ์ฌ์ด์ ๊ตฌ๋ถ์๋ฅผ '&'๋ฅผ ์ฝ์ ํด ์ถ๋ ฅํด๋ผ.)
์ด ๋ ์์๋, 0.12, 0.567 ๊ณผ ๊ฐ์ ๋ถ๋์์์ ์ ์๊ธฐํ๋ ๊ฒ์ด ์๋ ๋๋ ์ ์๋ ์๊ฐ ์๊ธฐ ์์ ๊ณผ 1๋ฐ์ ์๋ ์ซ์๋ฅผ ์๋ฏธํ๋ค. ์๋ฅผ ๋ค๋ฉด 7์ ๋ ๊ฐ์ ๊ณฑ์ ์ผ๋ก ๋๋์ด ๋ณธ๋ค๋ฉด 1 x 7 ์ด๋ผ๋ 1๊ฐ์ง ์กฐํฉ๋ฐ์ ์กด์ฌํ์ง ์๋๋ค. 17์ด๋ 13๋ ๋ง์ฐฌ๊ฐ์ง๋ค. ๋์ ์ซ์๋ก ์ฌ๋ผ๊ฐ๋ฉด 787๋ ์์์ด๋ค.
๊ทธ๋ฐ๋ฐ ํ ๊ฐ์ง ์ด์ํ ์ ์ด ์๋ค. ํ ์ด๋ธ์ด ์ฃผ์ด์ง์ง ์์๋๋ฐ ๋์ฒด ์ด๋ป๊ฒ ์ฟผ๋ฆฌ๋ฅผ ํ๋ ๋ง์ธ๊ฐ? ์ด๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด์๋ MySQL ์์ฒด์ ๋ด์ฅ๋์ด ์๋ ํ ์ด๋ธ๋ค์ด ๋ด๊ฒจ ์๋ ์ฆ, ์ฐ๋ฆฌ๊ฐ ๋ก์ปฌ์ MySQL์ ๊น๊ฒ ๋๋ฉด ์ ์ด๋ถํฐ ์กด์ฌํ๋ ํ ์ด๋ธ๋ค์ ๋ด๊ณ ์๋ information_schema ๋ฅผ ์ด์ฉํด์ผ ํ๋ค. information_schema์ ๋ํ ์์ธํ ๋ด์ฉ์ ์ฌ๊ธฐ๋ฅผ ์ดํด๋ณด์.
๋จผ์ ํด๋น ๋ฌธ์ ๋ฅผ ํ์ดํ SQL ๊ตฌ๋ฌธ๋ถํฐ ์ดํด๋ณด์.
SELECT GROUP_CONCAT(NUMB SEPARATOR '&')
FROM (SELECT @num:=@num+1 AS NUMB
FROM information_schema.tables t1,
information_schema.tables t2,
(SELECT @num:=1) tmp
) tempNum
WHERE NUMB <= 1000
AND NOT EXISTS (SELECT *
FROM (SELECT @nu:=@nu+1 AS NUMA
FROM information_schema.tables t1,
information_schema.tables t2,
(SELECT @nu:=1) tmp1
LIMIT 1000
) tempNum1
WHERE FLOOR(NUMB/NUMA) = (NUMB/NUMA)
AND NUMA < NUMB
AND 1 < NUMA
)
๋ง์ด ๋ณต์กํ๋ค.. ์ฐ์ ๊ฐ์ฅ ์ฒซ ๋ฒ์งธ์ ์๋ ์๋ธ์ฟผ๋ฆฌ ํํ๋ถํฐ ํ๋ํ๋ ์ถ๋ ฅํด๋ณด์. ๋ค์์ SQL ๊ตฌ๋ฌธ์ ์ถ๋ ฅํ๋ฉด ๋ค์๊ณผ ๊ฐ๋ค.
SELECT *
FROM (SELECT @num:=@num+1 AS NUMB
FROM information_schema.tables t1,
information_schema.tables t2
) tempNum
์ ํ๋ฉด์ ๋ณด๋ฉด ๋ชจ๋ Null
๊ฐ์ด ๋์ด ์๋ค. ์ด ๋ information_schema
๋ฅผ 2๊ฐ๋ก ์ค์ ํ ๊ฒ์ information_schema
๋ฅผ 1๊ฐ๋ก๋ง ์ค์ ํด์ ๋ชจ๋ row๋ค์ ์ถ๋ ฅํ๋ฉด 1000๊ฐ์ ๊ฐ์๋ณด๋ค ์ ๊ฒ ๋์ค๊ธฐ ๋๋ฌธ์ด๋ค. ๋ฐ๋ผ์ ์ถํ์ 1000๊ฐ๋ณด๋ค ๋๋ row๋ค ์ค 1000๊ฐ๋ก LIMIT
ํ๊ธฐ ์ํด 2๊ฐ๋ก ์ค์ ํ๋ค๋ ๊ฒ์ ์์๋์. ์ ์ฟผ๋ฆฌ์์ Null
๊ฐ ๋์ 1๋ณด๋ค ํฐ ์ฆ 2๋ถํฐ 1์ฉ ์ปค์ง๋ ๊ฐ์ ๋ฃ์ด๋ณด์.
SELECT *
FROM (SELECT @num:=@num+1 AS NUMB
FROM information_schema.tables t1,
information_schema.tables t2,
(SELECT @num:=1) tmp
) tempNum
์ฐ๋ฆฌ๊ฐ ์ํ๋ ๋ฐ๋ก ๊ฐ์ด ์ฝ์
๋์๋ค. ์ฌ์ค ์์ SELECT
๋ฌธ๋ง ๋ถ์ฌ์ ๊ฐ์ด ์ฝ์
๋๋ค๋ ์ฌ์ค์ด ์ ๊ธฐ ํ๋ค. @num
์ด๋ผ๋ ์ด๋ฏธ ์ฌ์ฉ๋ ๋ณ์๊ฐ ๋ค์ด๊ฐ ์๊ธฐ ๋๋ฌธ์ ์์์ ์ฝ์
๋๋ ๊ฑด์ง.. ์ด์ ๋ํด์๋ ์ถ๊ฐ์ ์ธ ๊ณต๋ถ๊ฐ ํ์ํ ๊ฒ ๊ฐ๋ค.
์ด์จ๋ ์ด์ 1000๋ณด๋ค ํฐ ์ซ์๋ค์ด ๋ชจ๋ ์ฝ์ ๋์์ผ๋ ์กฐ๊ฑด์ ๋ถ์ฌ์ฃผ์. ๊ทธ๋ฆฌ๊ณ ์กฐ๊ฑด๋ฌธ์ ๋ฐฉ๊ธ ๋ง๋ค์๋ 1000๊ฐ์ ์ซ์๊ฐ ์ฝ์ ๋ ํ ์ด๋ธ์ ํ๋ ๋ ๋ง๋ค์ด์ ์ด๋ค ์๊ฐ '์์'์ธ์ง ํํฐ๋งํด๋ณด์.
SELECT GROUP_CONCAT(NUMB SEPARATOR '&')
FROM (SELECT @num:=@num+1 AS NUMB
FROM information_schema.tables t1,
information_schema.tables t2,
(SELECT @num:=1) tmp
) tempNum
WHERE NUMB <= 1000
AND NOT EXISTS (SELECT *
FROM (SELECT @nu:=@nu+1 AS NUMA
FROM information_schema.tables t1,
information_schema.tables t2,
(SELECT @nu:=1) tmp1
LIMIT 1000
) tempNum1
WHERE FLOOR(NUMB/NUMA) = (NUMB/NUMA)
AND NUMA < NUMB
AND 1 < NUMA
)
์ฃผ๋ชฉํด์ผ ํ ๋ถ๋ถ์ FLOOR(NUMB/NUMA) = (NUMB/NUMA)
๋ฅผ ๋ง์กฑํ๋ NUMB ์ซ์๋ค์ด ๋ฐ๋ก ์์๊ฐ ์๋๋ผ๋ ์ ์ด๋ค. ์ด์ ๋ํด์ ๊ฐ๋จํ ์์๋ฅผ ๋ค์ด๋ณด์.
NUMB | NUMA | FLOOR(NUMB/NUMA) | NUMB/NUMA |
7 | 4 | 1 | 1.75 |
6 | 2 | 3 | 3 |
11 | 5 | 2 | 2.2 |
10 | 5 | 2 | 2 |
์ ํ
์ด๋ธ์ ๋ณด๋ฉด FLOOR(NUMB/NUMA)
์ NUMB/NUMA
๊ฐ ๋์ผํ๋ค๋ ์กฐ๊ฑด์ ๋ง์กฑํ๋ NUMB
์๋ค์ ์์๊ฐ ์๋ ์๋ค์์ ์ ์ ์๋ค. ์ฆ, ํด๋น ์กฐ๊ฑด์ ๋ถ๋ง์กฑํ๋ NUMB
์๋ค์ด ๋ฐ๋ก ์์๋ผ๋ ๊ฒ์ด๋ค.
๋ฐ๋ผ์ ์ด๋ฌํ ์กฐ๊ฑด์ด์ธ์ ์ถ๊ฐ์ ์ผ๋ก NUMA
๊ฐ 1๋ณด๋ค ํฌ๊ณ NUMA < NUMB
์ด์ด์ผ ํ๋ ์กฐ๊ฑด 2๊ฐ์ง๋ฅผ ๋ ๋ถ์ฌ ์ํ๋ ๊ฐ๋ค์ธ 1000 ์ดํ์ ์์๊ฐ๋ค์ ์ถ๋ ฅํ ์ ์๋ค.
์ด์ ๋ง์ง๋ง์ผ๋ก ๊ตฌ๋ถ์์ธ &
๋ฅผ ์ฌ์ด์ ๋ฃ์ด์ ํ ์ค๋ก ์ถ๋ ฅํด์ฃผ์ด์ผ ํ๋๋ฐ ์ด ๋๋ GROUP_CONCAT
ํจ์๋ฅผ ์ฌ์ฉํ๋ฉด ๋๋ค. ํ์๋ ์ด์ ๋ํด์๋ ์ฒ์ ์์๋๋ฐ ๋ธ๋ก๊ทธ๋ฅผ ์ฐพ์๋ณด๋ ์ ์ฉํ ๊ธฐ๋ฅ์ด ๋ง์๋ค. ํ ์ค๋ก ์ถ๋ ฅํด์ค ๋ ์ค๋ณต์ ์ ๊ฑฐ(DISTINCT
) ํ๊ฑฐ๋ ์ ๋ ฌ ์์(ORDER BY
)๋ฅผ ์ ํด์ฃผ๊ธฐ, ์ง๊ธ ๋ฌธ์ ํ์ด์ ์ฌ์ฉ๋ ๊ตฌ๋ถ์ ์ค์ ๋ฑ ๋ค์ํ ๊ธฐ๋ฅ์ด ์์๋ค. ์ถํ์ ์ ์ฉํ๊ฒ ์ฌ์ฉํด๋ณผ ๋งํ ๊ธฐ๋ฅ์ธ ๊ฒ ๊ฐ๋ค.
์ด์ GROUP_CONCAT
๊น์ง ์ค์ ํ ํ ์ต์ข
๊ฒฐ๊ณผ๋ฅผ ํ
์คํธ ํด๋ณด๋ฉด ์ ๋ต ์ฒ๋ฆฌ๊ฐ ๋๋ค. ๋์ผ๋ก ๋ฌธ๋์ ์ธ๊ธํ๋ Procedure
์ ์ด์ฉํ ํ์ด๋ ์ฒจ๋ถํด๋์ผ๋ ค ํ๋ค. ๋จ, ์ถ๋ ฅ ๋ฐ์ดํฐ ๊ธธ์ด๊ฐ ๊ธธ๊ธฐ ๋๋ฌธ์ ์ถ๋ ฅ ๊ธธ์ด๋ฅผ ์ค์ ํ๋ OUT
๋ถ๋ถ์ HackerRank ์์ ์ ๊ณตํ๋ ์ต๋๊ฐ์ธ 16,383 ๊ธธ์ด๋ฅผ ์ค์ ํด์ผ ํ๋ค.
-- Stored Procedure ๋ง๋ค๊ธฐ
DELIMITER $$
CREATE PROCEDURE getPrime(IN n INT,
OUT result VARCHAR(16383))
BEGIN
DECLARE j, i, flag INT;
SET j:=2;
SET result:= ' ';
WHILE (j<n) DO
SET i:=2;
SET flag:=0;
WHILE (i<=j) DO
IF (j%i=0) THEN
SET flag:=flag+1;
END IF;
SET i:=i+1;
END WHILE;
IF (flag=1) THEN
SET result:=CONCAT(result, j, '&');
END IF;
SET j:=j+1;
END WHILE;
END $$
-- ๋ง๋ Stored Procedure ํธ์ถ(call)ํ๊ธฐ
CALL getPrime(1000, @result);
SELECT SUBSTR(@result, 1, LENGTH(@result)-1);
'SQL' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[SQL] SQL๋ก ์ด์งํธ๋ฆฌ ํ์ํ๊ธฐ(HackerRank - Binary Tree Nodes ๋ฌธ์ ) (0) | 2021.03.15 |
---|---|
[SQL] HackerRank - Placements ๋ฌธ์ (0) | 2021.03.10 |
[SQL] HackerRank - SQL Project Planning ๋ฌธ์ (0) | 2021.03.04 |
[SQL] HackerRank - Contest Leaderboard ๋ฌธ์ (0) | 2021.03.02 |
[SQL] MySQL์์๋ ์๋๋ ํ์ด(HackerRank - The PADS ๋ฌธ์ ) (0) | 2021.02.28 |