์ด์ ๊ด๋ จํ์ฌ DBMS๋ ๋์ผํ ์์น์ ๋ฐ๋ผ ์๋ํฉ๋๋ค. "ํ๋ผ๊ณ ํด์ ํ๋ ๊ฑฐ์ผ". ๊ทํ์ ์์ฒญ์ ์ธ์ ํ ํ๋ก์ธ์ค์ ์๋๋ฅผ ๋ฆ์ถ๊ณ ์ง์์ ์ผ๋ก ํ๋ก์ธ์ ๋ฆฌ์์ค๋ฅผ ์ฐจ์งํ ๋ฟ๋ง ์๋๋ผ ์ ์ฒด ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ฅผ "์ญ์ "ํ์ฌ ์ฌ์ฉ ๊ฐ๋ฅํ ๋ชจ๋ ๋ฉ๋ชจ๋ฆฌ๋ฅผ "๋จน์ต๋๋ค". ๋ฐ๋ผ์ ๋ฌดํ ์ฌ๊ท๋ก๋ถํฐ ๋ณดํธ - ๊ฐ๋ฐ์ ์์ ์ ์ฑ
์์
๋๋ค.
PostgreSQL์์๋ ๋ค์์ ํตํด ์ฌ๊ท ์ฟผ๋ฆฌ๋ฅผ ์ฌ์ฉํ๋ ๊ธฐ๋ฅ์ด ์์ต๋๋ค. WITH RECURSIVE
์ฌ๊ท ์ฟผ๋ฆฌ๋ฅผ ์์ฑํ์ง ๋ง์ธ์
๊ทธ๋ฆฌ๊ณ ๋น์ฌ๊ท์ ์ธ ๊ฒ์ ์์ฑํ์ธ์. ์ง์ฌ์ผ๋ก, ๋น์ ์ K.O.
์ค์ ๋ก PostgreSQL์ ๋ค์ ์์ ์ ์ฌ์ฉํ ์ ์๋ ๊ฝค ๋ง์ ๊ธฐ๋ฅ์ ์ ๊ณตํฉ๋๋ค. ์๋ ์ฌ๊ท๋ฅผ ์ ์ฉํฉ๋๋ค.
๋ฌธ์ ์ ๋ํด ๊ทผ๋ณธ์ ์ผ๋ก ๋ค๋ฅธ ์ ๊ทผ ๋ฐฉ์์ ์ฌ์ฉํ์ญ์์ค.
๋๋ก๋ "๋ค๋ฅธ ์ธก๋ฉด"์์ ๋ฌธ์ ๋ฅผ ๋ณผ ์๋ ์์ต๋๋ค. ๋๋ ๊ธฐ์ฌ์์ ๊ทธ๋ฌํ ์ํฉ์ ์๋ฅผ ์ ์ํ์ต๋๋ค.
WITH RECURSIVE src AS (
SELECT '{2,3,5,7,11,13,17,19}'::integer[] arr
)
, T(i, val) AS (
SELECT
1::bigint
, 1
UNION ALL
SELECT
i + 1
, val * arr[i]
FROM
T
, src
WHERE
i <= array_length(arr, 1)
)
SELECT
val
FROM
T
ORDER BY -- ะพัะฑะพั ัะธะฝะฐะปัะฝะพะณะพ ัะตะทัะปััะฐัะฐ
i DESC
LIMIT 1;
์ด ์์ฒญ์ ์ํ ์ ๋ฌธ๊ฐ์ ์ต์ ์ผ๋ก ๋์ฒด๋ ์ ์์ต๋๋ค.
WITH src AS (
SELECT unnest('{2,3,5,7,11,13,17,19}'::integer[]) prime
)
SELECT
exp(sum(ln(prime)))::integer val
FROM
src;
๋ฃจํ ๋์ generate_series ์ฌ์ฉ
๋ฌธ์์ด์ ๋ํด ๊ฐ๋ฅํ ๋ชจ๋ ์ ๋์ฌ๋ฅผ ์์ฑํ๋ ์์
์ ์ง๋ฉดํ๋ค๊ณ ๊ฐ์ ํด ๋ณด๊ฒ ์ต๋๋ค. 'abcdefgh'
:
WITH RECURSIVE T AS (
SELECT 'abcdefgh' str
UNION ALL
SELECT
substr(str, 1, length(str) - 1)
FROM
T
WHERE
length(str) > 1
)
TABLE T;
์ฌ๊ธฐ์ ์ฌ๊ท๊ฐ ํ์ํฉ๋๊น?.. ๋ค์์ ์ฌ์ฉํ๋ ๊ฒฝ์ฐ LATERAL
ะธ generate_series
, ๊ทธ๋ฌ๋ฉด CTE๋ ํ์ํ์ง ์์ต๋๋ค.
SELECT
substr(str, 1, ln) str
FROM
(VALUES('abcdefgh')) T(str)
, LATERAL(
SELECT generate_series(length(str), 1, -1) ln
) X;
๋ฐ์ดํฐ๋ฒ ์ด์ค ๊ตฌ์กฐ ๋ณ๊ฒฝ
์๋ฅผ ๋ค์ด, ๋๊ฐ ๋๊ตฌ์๊ฒ ์๋ตํ๋์ง ์ฐ๊ฒฐ์ด ํฌํจ๋ ํฌ๋ผ ๋ฉ์์ง ํ
์ด๋ธ์ด ์์ต๋๋ค.
CREATE TABLE message(
message_id
uuid
PRIMARY KEY
, reply_to
uuid
REFERENCES message
, body
text
);
CREATE INDEX ON message(reply_to);
ํ ์ฃผ์ ์ ๋ํ ๋ชจ๋ ๋ฉ์์ง๋ฅผ ๋ค์ด๋ก๋ํ๋ผ๋ ์ผ๋ฐ์ ์ธ ์์ฒญ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
WITH RECURSIVE T AS (
SELECT
*
FROM
message
WHERE
message_id = $1
UNION ALL
SELECT
m.*
FROM
T
JOIN
message m
ON m.reply_to = T.message_id
)
TABLE T;
ํ์ง๋ง ์ฐ๋ฆฌ๋ ํญ์ ๋ฃจํธ ๋ฉ์์ง์ ์ ์ฒด ์ฃผ์ ๊ฐ ํ์ํ๋ฏ๋ก ๊ฐ ํญ๋ชฉ์ ID๋ฅผ ์ถ๊ฐํ์ธ์. ์๋์ ์ธ?
-- ะดะพะฑะฐะฒะธะผ ะฟะพะปะต ั ะพะฑัะธะผ ะธะดะตะฝัะธัะธะบะฐัะพัะพะผ ัะตะผั ะธ ะธะฝะดะตะบั ะฝะฐ ะฝะตะณะพ
ALTER TABLE message
ADD COLUMN theme_id uuid;
CREATE INDEX ON message(theme_id);
-- ะธะฝะธัะธะฐะปะธะทะธััะตะผ ะธะดะตะฝัะธัะธะบะฐัะพั ัะตะผั ะฒ ััะธะณะณะตัะต ะฟัะธ ะฒััะฐะฒะบะต
CREATE OR REPLACE FUNCTION ins() RETURNS TRIGGER AS $$
BEGIN
NEW.theme_id = CASE
WHEN NEW.reply_to IS NULL THEN NEW.message_id -- ะฑะตัะตะผ ะธะท ััะฐััะพะฒะพะณะพ ัะพะฑััะธั
ELSE ( -- ะธะปะธ ะธะท ัะพะพะฑัะตะฝะธั, ะฝะฐ ะบะพัะพัะพะต ะพัะฒะตัะฐะตะผ
SELECT
theme_id
FROM
message
WHERE
message_id = NEW.reply_to
)
END;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER ins BEFORE INSERT
ON message
FOR EACH ROW
EXECUTE PROCEDURE ins();
์ด์ ์ ์ฒด ์ฌ๊ท ์ฟผ๋ฆฌ๋ฅผ ๋ค์๊ณผ ๊ฐ์ด ์ค์ผ ์ ์์ต๋๋ค.
SELECT
*
FROM
message
WHERE
theme_id = $1;
์ ์ฉ๋ "๋ฆฌ๋ฏธํฐ" ์ฌ์ฉ
์ด๋ค ์ด์ ๋ก ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ๊ตฌ์กฐ๋ฅผ ๋ณ๊ฒฝํ ์ ์๋ ๊ฒฝ์ฐ, ๋ฐ์ดํฐ์ ์ค๋ฅ๊ฐ ์์ด๋ ๋์๋ ๋ฐ๋ณต์ด ๋ฐ์ํ์ง ์๋๋ก ๋ฌด์์ ์์งํ ์ ์๋์ง ์ดํด๋ณด๊ฒ ์ต๋๋ค.
์ฌ๊ท ๊น์ด ์นด์ดํฐ
์ฐ๋ฆฌ๋ ๋ช ๋ฐฑํ ๋ถ์ ์ ํ๋ค๊ณ ์๊ฐ๋๋ ํ๊ณ์ ๋๋ฌํ ๋๊น์ง ๊ฐ ์ฌ๊ท ๋จ๊ณ์์ ์นด์ดํฐ๋ฅผ ํ๋์ฉ ์ฆ๊ฐ์ํต๋๋ค.
WITH RECURSIVE T AS (
SELECT
0 i
...
UNION ALL
SELECT
i + 1
...
WHERE
T.i < 64 -- ะฟัะตะดะตะป
)
์ง์
: ๋ฃจํ๋ฅผ ์๋ํ ๋ "๊น์ด ์๋" ๋ฐ๋ณต์ ์ง์ ๋ ์ ํ ์ด์์ ์ํํ์ง ์์ต๋๋ค.
๋จ์ : ๋์ผํ ๋ ์ฝ๋๋ฅผ ๋ค์ ์ฒ๋ฆฌํ์ง ์๋๋ค๋ ๋ณด์ฅ์ ์์ต๋๋ค. ์๋ฅผ ๋ค์ด ๊น์ด 15์ 25์์ ๊ทธ๋ฆฌ๊ณ +10๋ง๋ค. ๊ทธ๋ฆฌ๊ณ ์๋ฌด๋ "ํญ"์ ๋ํด ์ฝ์ํ์ง ์์์ต๋๋ค.
๊ณต์์ ์ผ๋ก ์ด๋ฌํ ๋ฐ๋ณต์ ๋ฌดํํ์ง ์์ง๋ง ๊ฐ ๋จ๊ณ์์ ๋ ์ฝ๋ ์๊ฐ ๊ธฐํ๊ธ์์ ์ผ๋ก ์ฆ๊ฐํ๋ฉด ์ฐ๋ฆฌ ๋ชจ๋๋ ๊ทธ๊ฒ์ด ์ด๋ป๊ฒ ๋๋๋์ง ์ ์๊ณ ์์ต๋๋ค.
"๊ธธ"์ ์ํธ์
์ฐ๋ฆฌ๋ ์ฌ๊ท ๊ฒฝ๋ก๋ฅผ ๋ฐ๋ผ ๋ง๋ ๋ชจ๋ ๊ฐ์ฒด ์๋ณ์๋ฅผ ๋ฐฐ์ด์ ์ถ๊ฐํฉ๋๋ค. ๋ฐฐ์ด์ ๋ฐฐ์ด์ ๋ํ ๊ณ ์ ํ "๊ฒฝ๋ก"์ ๋๋ค.
WITH RECURSIVE T AS (
SELECT
ARRAY[id] path
...
UNION ALL
SELECT
path || id
...
WHERE
id <> ALL(T.path) -- ะฝะต ัะพะฒะฟะฐะดะฐะตั ะฝะธ ั ะพะดะฝะธะผ ะธะท
)
์ง์
: ๋ฐ์ดํฐ์ ์ํ์ด ์๋ ๊ฒฝ์ฐ ๋์ผํ ๊ฒฝ๋ก ๋ด์์ ๋์ผํ ๋ ์ฝ๋๋ฅผ ๋ฐ๋ณต์ ์ผ๋ก ์ฒ๋ฆฌํ์ง ์์ต๋๋ค.
๋จ์ : ๊ทธ๋ฌ๋ ๋์์ ์ฐ๋ฆฌ๋ ๋ฐ๋ณตํ์ง ์๊ณ ๋ ๋ง ๊ทธ๋๋ก ๋ชจ๋ ๊ธฐ๋ก์ ์ฐํํ ์ ์์ต๋๋ค.
๊ฒฝ๋ก ๊ธธ์ด ์ ํ
์ดํดํ ์ ์๋ ๊น์ด์์ ์ฌ๊ท๊ฐ "๋ฐฉํฉ"ํ๋ ์ํฉ์ ํผํ๊ธฐ ์ํด ์ด์ ๋ ๊ฐ์ง ๋ฐฉ๋ฒ์ ๊ฒฐํฉํ ์ ์์ต๋๋ค. ๋๋ ๋ถํ์ํ ํ๋๋ฅผ ์ง์ํ์ง ์์ผ๋ ค๋ฉด ๊ฒฝ๋ก ๊ธธ์ด ์ถ์ ์ผ๋ก ์ฌ๊ท๋ฅผ ๊ณ์ํ๊ธฐ ์ํ ์กฐ๊ฑด์ ๋ณด์ํ์ธ์.
WITH RECURSIVE T AS (
SELECT
ARRAY[id] path
...
UNION ALL
SELECT
path || id
...
WHERE
id <> ALL(T.path) AND
array_length(T.path, 1) < 10
)
์ทจํฅ์ ๋ง๊ฒ ๋ฐฉ๋ฒ์ ์ ํํด๋ณด์ธ์!
์ถ์ฒ : habr.com