SQL์์๋ ์คํํด์ผ ํ๋ "๋ฐฉ๋ฒ"์ด ์๋๋ผ ๋ฌ์ฑํ๋ ค๋ "๋ฌด์"์ ์ค๋ช
ํฉ๋๋ค. ๊ทธ๋ฌ๋ฏ๋ก "๋ค์ ๋๋ก ์ฐ์ฌ์ง๋ค"๋ผ๋ ์คํ์ผ๋ก SQL ์ฟผ๋ฆฌ๋ฅผ ๊ฐ๋ฐํ๋ ๋ฌธ์ ๊ฐ ๊ทธ ์๋ฆฌ๋ฅผ ๋์ ํฉ๋๋ค.
์ค๋์ ๋งค์ฐ ๊ฐ๋จํ ์๋ฅผ ์ฌ์ฉํ์ฌ ์ด๊ฒ์ด ์ฌ์ฉ ๋งฅ๋ฝ์์ ์ด๋ค ๊ฒฐ๊ณผ๋ฅผ ๊ฐ์ ธ์ฌ ์ ์๋์ง ์ดํด๋ณด๊ฒ ์ต๋๋ค. GROUP/DISTINCT
ะธ LIMIT
๊ทธ๋ค๊ณผ ํจ๊ป.
์ด์ ์์ฒญ์ ์ผ๋ค๋ฉด โ๋จผ์ ์ด ํ์งํ๋ค์ ์ฐ๊ฒฐํ ๋ค์, ์ค๋ณต๋ ๊ฒ๋ค์ ๋ชจ๋ ๋ฒ๋ฆฌ์ธ์. ํ๋๋ง ๋จ์์ผ ํด ๊ฐ ํค์ ๋ํด ๋ณต์ฌ" - ์ฐ๊ฒฐ์ด ์ ํ ํ์ํ์ง ์์ ๊ฒฝ์ฐ์๋ ์ด๊ฒ์ด ์ ํํ ์๋ํ๋ ๋ฐฉ์์ ๋๋ค.
๋๋ก๋ ์ด์ด ์ข์์ "๊ทธ๋ฅ ์๋"ํ๊ธฐ๋ ํ๊ณ , ๋๋ก๋ ์ฑ๋ฅ์ ๋ถ์พํ ์ํฅ์ ๋ฏธ์น๊ธฐ๋ ํ๊ณ , ๋๋ก๋ ๊ฐ๋ฐ์์ ๊ด์ ์์ ์ ํ ์์์น ๋ชปํ ํจ๊ณผ๋ฅผ ์ฃผ๊ธฐ๋ ํฉ๋๋ค.
๊ธ์์, ๊ทธ๋ ๊ฒ ํ๋ฅญํ์ง๋ ์์ ์๋ ์์ง๋ง...
โ๋ฌ์ฝคํ ์ปคํโ: JOIN + DISTINCT
SELECT DISTINCT
X.*
FROM
X
JOIN
Y
ON Y.fk = X.pk
WHERE
Y.bool_condition;
๊ทธ๋ค์ด ์ํ๋ ๊ฒ์ด ๋ฌด์์ธ์ง๋ ๋ถ๋ช
ํ ๊ฒ์ด๋ค. ์ถฉ์กฑ๋ ์กฐ๊ฑด๊ณผ ๊ด๋ จ๋ Y์ ๋ ์ฝ๋๊ฐ ์๋ ๋ ์ฝ๋ X๋ฅผ ์ ํํฉ๋๋ค.. ๋ค์์ ํตํด ์์ฒญ์ ์์ฑํ์ต๋๋ค. JOIN
โ pk ๊ฐ์ ์ฌ๋ฌ ๋ฒ ์ป์์ต๋๋ค(์ ํํ Y์ ์ ํฉํ ํญ๋ชฉ์ด ๋ช ๊ฐ๋ ๋ํ๋ฌ๋์ง). ์ ๊ฑฐํ๋ ๋ฐฉ๋ฒ? ํ๋ฆผ์์ด DISTINCT
!
๊ฐ X ๋ ์ฝ๋์ ๋ํด ์๋ฐฑ ๊ฐ์ ๊ด๋ จ Y ๋ ์ฝ๋๊ฐ ์๊ณ ์ค๋ณต ํญ๋ชฉ์ด ์์
์ ์ผ๋ก ์ ๊ฑฐ๋๋ฉด ํนํ "๊ธฐ์๋ค".
์ด๋ป๊ฒ ๊ณ ์น๋ ์ง? ์ฐ์ ๋ฌธ์ ๊ฐ ๋ค์๊ณผ ๊ฐ์ด ์์ ๋ ์ ์๋ค๋ ์ ์ ์ธ์ํ์ธ์. "Y์ ์ถฉ์กฑ๋ ์กฐ๊ฑด๊ณผ ์ฐ๊ด๋ AT LEAST ONE์ด ์๋ X ๋ ์ฝ๋๋ฅผ ์ ํํ์ธ์." -๊ฒฐ๊ตญ Y ๋ ์ฝ๋ ์์ฒด์์๋ ์๋ฌด๊ฒ๋ ํ์ํ์ง ์์ต๋๋ค.
์ค์ฒฉ๋ ์กด์ฌ
SELECT
*
FROM
X
WHERE
EXISTS(
SELECT
NULL
FROM
Y
WHERE
fk = X.pk AND
bool_condition
LIMIT 1
);
์ผ๋ถ PostgreSQL ๋ฒ์ ์ EXISTS์์๋ ๋ํ๋๋ ์ฒซ ๋ฒ์งธ ํญ๋ชฉ์ ์ฐพ๋ ๊ฒ์ผ๋ก ์ถฉ๋ถํ์ง๋ง ์ด์ ๋ฒ์ ์ ๊ทธ๋ ์ง ์๋ค๋ ๊ฒ์ ์ดํดํฉ๋๋ค. ๊ทธ๋ฌ๋ฏ๋ก ๋๋ ํญ์ ํ์ํ๋ ๊ฒ์ ์ ํธํฉ๋๋ค LIMIT 1
์ด๋ด EXISTS
.
์ธก๋ฉด ์กฐ์ธ
SELECT
X.*
FROM
X
, LATERAL (
SELECT
Y.*
FROM
Y
WHERE
fk = X.pk AND
bool_condition
LIMIT 1
) Y
WHERE
Y IS DISTINCT FROM NULL;
๋์ผํ ์ต์ ์ ์ฌ์ฉํ๋ฉด ํ์ํ ๊ฒฝ์ฐ ๋ฐ๊ฒฌ๋ ๊ด๋ จ Y ๋ ์ฝ๋์์ ์ผ๋ถ ๋ฐ์ดํฐ๋ฅผ ์ฆ์ ๋ฐํํ ์ ์์ต๋๋ค. ์ ์ฌํ ์ต์ ์ด ๊ธฐ์ฌ์์ ๋ ผ์๋ฉ๋๋ค.
"PostgreSQL ์ํฐํจํด: ๋๋ฌธ ๋ ์ฝ๋๊ฐ JOIN ์ค๊ฐ์ ๋๋ฌํฉ๋๋ค." .
โ๋ ๋ง์ ๋น์ฉ์ ์ง๋ถํด์ผ ํ๋ ์ด์ โ: DISTINCT [ON] + LIMIT 1
์ด๋ฌํ ์ฟผ๋ฆฌ ๋ณํ์ ๋ ๋ค๋ฅธ ์ด์ ์ ๋ค์๊ณผ ๊ฐ์ด ๋ ์ฝ๋ ์ค ํ๋ ๋๋ ๋ช ๊ฐ๊ฐ ํ์ํ ๊ฒฝ์ฐ ๋ ์ฝ๋ ๊ฒ์์ ์ฝ๊ฒ ์ ํํ ์ ์๋ค๋ ๊ฒ์ ๋๋ค.
SELECT DISTINCT ON(X.pk)
*
FROM
X
JOIN
Y
ON Y.fk = X.pk
LIMIT 1;
์ด์ ์์ฒญ์ ์ฝ๊ณ DBMS๊ฐ ์ํํ ์์ ์ด ๋ฌด์์ธ์ง ์ดํดํ๋ ค๊ณ ๋ ธ๋ ฅํฉ๋๋ค.
- ํ์งํ์ ์ฐ๊ฒฐํ๋ค
- X.pk ๊ณ ์
- ๋๋จธ์ง ํญ๋ชฉ ์ค์์ ํ๋๋ฅผ ์ ํํ์ธ์.
๊ทธ๋์ ๋ฌด์์ ์ป์๋์? "ํ ๋ฒ๋ง ์ ๋ ฅํ์ธ์" ๊ณ ์ ํ ๊ฒ ์ค์์ - ๊ณ ์ ํ์ง ์์ ๊ฒ์ ์ทจํ๋ฉด ๊ฒฐ๊ณผ๊ฐ ์ด๋ป๊ฒ๋ ๋ฐ๋๊น์?.. "์ฐจ์ด๊ฐ ์๋ค๋ฉด ์ ๋ ๋ง์ ๋น์ฉ์ ์ง๋ถํฉ๋๊น?"
SELECT
*
FROM
(
SELECT
*
FROM
X
-- ััะดะฐ ะผะพะถะฝะพ ะฟะพะดััะฝััั ะฟะพะดั
ะพะดััะธั
ััะปะพะฒะธะน
LIMIT 1 -- +1 Limit
) X
JOIN
Y
ON Y.fk = X.pk
LIMIT 1;
๊ทธ๋ฆฌ๊ณ ์ ํํ ๊ฐ์ ์ฃผ์ GROUP BY + LIMIT 1
.
"๋ฌผ์ด๋ณผ ๊ฒ ์์ด์": ์์์ GROUP + LIMIT
๋น์ทํ ์ผ์ด ๋ค๋ฅธ ๊ณณ์์ ๋ฐ์ํฉ๋๋ค. ๋น์ด ์์ง ์์์ง ํ์ธ ์์ฒญ์ด ์งํ๋จ์ ๋ฐ๋ผ ์๋ช ๋๋ CTE:
...
CASE
WHEN (
SELECT
count(*)
FROM
X
LIMIT 1
) = 0 THEN ...
์ง๊ณ ํจ์(count/min/max/sum/...
)์ ๋ช
์์ ์ธ ์ง์นจ ์์ด๋ ์ ์ฒด ์ธํธ์์ ์ฑ๊ณต์ ์ผ๋ก ์คํ๋ฉ๋๋ค. GROUP BY
. ์ค์ง LIMIT
๊ทธ๋ค์ ๊ทธ๋ค์ง ์น์ ํ์ง ์์ต๋๋ค.
๊ฐ๋ฐ์๋ ์๊ฐํ ์ ์๋ค โ๊ฑฐ๊ธฐ์ ๊ธฐ๋ก์ด ์๋ค๋ฉด LIMIT๋ง ์์ผ๋ฉด ๋ฉ๋๋ค.โ. ํ์ง๋ง ๊ทธ๋ฌ์ง ๋ง์ธ์! ๋ฒ ์ด์ค์ ๊ฒฝ์ฐ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
- ๊ทธ๋ค์ด ์ํ๋ ๊ฒ์ ์ธ์ด๋ณด์ธ์ ๋ชจ๋ ๊ธฐ๋ก์ ์ํ๋ฉด
- ๊ทธ๋ค์ด ์๊ตฌํ๋ ๋งํผ ๋ง์ ๋์ฌ๋ฅผ ์ค
๋์ ์กฐ๊ฑด์ ๋ฐ๋ผ ๋ค์ ๋์ฒด ์ค ํ๋๋ฅผ ์ํํ๋ ๊ฒ์ด ์ ์ ํฉ๋๋ค.
(count + LIMIT 1) = 0
์NOT EXISTS(LIMIT 1)
(count + LIMIT 1) > 0
์EXISTS(LIMIT 1)
count >= N
์(SELECT count(*) FROM (... LIMIT N))
"๊ทธ๋จ ๋จ์๋ก ๋งค๋ฌ์์ผ ํ ์": DISTINCT + LIMIT
SELECT DISTINCT
pk
FROM
X
LIMIT $1
์์งํ ๊ฐ๋ฐ์๋ ์์ฒญ ์คํ์ด ์ค์ง๋ ๊ฒ์ด๋ผ๊ณ ์ง์ฌ์ผ๋ก ๋ฏฟ์ ์ ์์ต๋๋ค. ์ฒ์์ผ๋ก ๋ฐ๊ฒฌ๋ ๋ค๋ฅธ ๊ฐ ์ค 1๋ฌ๋ฌ๋ฅผ ์ฐพ์๋ง์.
๋ฏธ๋์๋ ์๋ก์ด ๋ ธ๋ ๋๋ถ์ ์ด๊ฒ์ด ์๋ํ ์๋ ์๊ณ ์๋ํ ๊ฒ์ ๋๋ค. ์ธ๋ฑ์ค ๊ฑด๋๋ฐ๊ธฐ ์ค์บ, ๊ตฌํ์ด ํ์ฌ ์งํ ์ค์ด์ง๋ง ์์ง์ ์๋๋๋ค.
์ง๊ธ์ ๋จผ์ ๋ชจ๋ ๊ธฐ๋ก์ด ๊ฒ์๋ฉ๋๋ค, ๊ณ ์ ํ๋ฉฐ ํด๋น ์ค์์๋ง ์์ฒญํ ๊ธ์ก์ด ๋ฐํ๋ฉ๋๋ค. ์ฐ๋ฆฌ๊ฐ ๋ค์๊ณผ ๊ฐ์ ๊ฒ์ ์ํ๋ค๋ฉด ํนํ ์ฌํ๋ค $ 1 = 4, ํ ์ด๋ธ์๋ ์์ญ๋ง ๊ฐ์ ๋ ์ฝ๋๊ฐ ์์ต๋๋ค.
์ฌํ์ ํ๋์ด ๋ณด๋ด์ง ์๊ธฐ ์ํด ์ฌ๊ท ์ฟผ๋ฆฌ๋ฅผ ํ์ฉํด๋ณด์
์ถ์ฒ : habr.com