๋ณต์กํ ERP ์์คํ ์์ ๋ง์ ์ํฐํฐ๋ ๊ณ์ธต์ ์ฑ๊ฒฉ์ ๊ฐ์ง๊ณ ์์ต๋๋ค.๊ฐ์ ์ข ๋ฅ์ ๋ฌผ์ฒด๊ฐ ์ค์ง์ด ๋์ด์ ์์ ๋ ์กฐ์-ํ์ ๊ด๊ณ์ ๋๋ฌด - ์ด๊ฒ์ ๊ธฐ์ ์ ์กฐ์ง ๊ตฌ์กฐ(๋ชจ๋ ์ง์ , ๋ถ์ ๋ฐ ์์ ๊ทธ๋ฃน), ์ํ ์นดํ๋ก๊ทธ, ์์ ์์ญ, ํ๋งค ์ง์ ์ ์ง๋ฆฌ์ ๋๋ค...
์ฌ์ค์ ํ๋๋ ์์ด์
์ด๋ฌํ ํธ๋ฆฌ๋ฅผ DBMS์ ์ ์ฅํ๋ ๋ฐฉ๋ฒ์ ์ฌ๋ฌ ๊ฐ์ง๊ฐ ์์ง๋ง ์ค๋์ ํ ๊ฐ์ง ์ต์ ์๋ง ์ค์ ์ ๋ ๊ฒ์ ๋๋ค.
CREATE TABLE hier(
id
integer
PRIMARY KEY
, pid
integer
REFERENCES hier
, data
json
);
CREATE INDEX ON hier(pid); -- ะฝะต ะทะฐะฑัะฒะฐะตะผ, ััะพ FK ะฝะต ะฟะพะดัะฐะทัะผะตะฒะฐะตั ะฐะฒัะพัะพะทะดะฐะฝะธะต ะธะฝะดะตะบัะฐ, ะฒ ะพัะปะธัะธะต ะพั PK
๊ทธ๋ฆฌ๊ณ ๋น์ ์ด ๊ณ์ธต ๊ตฌ์กฐ์ ๊น์ด๋ฅผ ๋ค์ฌ๋ค๋ณด๋ ๋์, ๊ทธ๋ฌํ ๊ตฌ์กฐ๋ก ์์ ํ๋ "์์งํ" ๋ฐฉ์์ด ์ผ๋ง๋ ํจ๊ณผ์ ์ด์ง ์์์ง ์ธ๋ด์ฌ์ ๊ฐ๊ณ ๊ธฐ๋ค๋ฆฌ๊ณ ์์ต๋๋ค.
๋ฐ์ํ๋ ์ผ๋ฐ์ ์ธ ๋ฌธ์ ์ SQL์์์ ๊ตฌํ์ ์ดํด๋ณด๊ณ ์ฑ๋ฅ์ ๊ฐ์ ํด ๋ณด๊ฒ ์ต๋๋ค.
#1. ํ ๋ผ๊ตด์ ์ผ๋ง๋ ๊น๋์?
๋ช
ํ์ฑ์ ์ํด ์ด ๊ตฌ์กฐ๋ ๋ถ์, ์ฌ์
๋ถ, ๋ถ๋ฌธ, ์ง์ , ์์
๊ทธ๋ฃน ๋ฑ ์กฐ์ง ๊ตฌ์กฐ์์ ๋ถ์์ ์ข
์์ฑ์ ๋ฐ์ํ๋ค๋ ์ ์ ์ธ์ ํ๊ฒ ์ต๋๋ค.
๋จผ์ 10K ์์๋ก ๊ตฌ์ฑ๋ 'ํธ๋ฆฌ'๋ฅผ ์์ฑํด ๋ณด๊ฒ ์ต๋๋ค.
INSERT INTO hier
WITH RECURSIVE T AS (
SELECT
1::integer id
, '{1}'::integer[] pids
UNION ALL
SELECT
id + 1
, pids[1:(random() * array_length(pids, 1))::integer] || (id + 1)
FROM
T
WHERE
id < 10000
)
SELECT
pids[array_length(pids, 1)] id
, pids[array_length(pids, 1) - 1] pid
FROM
T;
๊ฐ์ฅ ๊ฐ๋จํ ์์
๋ถํฐ ์์ํด ๋ณด๊ฒ ์ต๋๋ค. ํน์ ๋ถ๋ฌธ ๋ด์์ ๋๋ ๊ณ์ธต ๊ตฌ์กฐ ์ธก๋ฉด์์ ์ผํ๋ ๋ชจ๋ ์ง์์ ์ฐพ์๋ณด์ธ์. ๋
ธ๋์ ๋ชจ๋ ์์ ์ฐพ๊ธฐ. ์์์ "๊น์ด"๋ฅผ ์ป๋ ๊ฒ๋ ์ข์ ๊ฒ์
๋๋ค... ์๋ฅผ ๋ค์ด ์ผ์ข
์ ๊ฒ์ ๊ตฌ์ถํ๋ ค๋ฉด ์ด ๋ชจ๋ ๊ฒ์ด ํ์ํ ์ ์์ต๋๋ค.
์ด๋ฌํ ํ์์ ๋ ๋ฒจ์ด ๋ช ๊ฐ๋ง ์๊ณ ๊ทธ ์๊ฐ ์ญ์ฌ ๊ฐ ์ด๋ด๋ผ๋ฉด ๋ชจ๋ ๊ฒ์ด ๊ด์ฐฎ๊ฒ ์ง๋ง, ๋ ๋ฒจ์ด 5๊ฐ๊ฐ ๋๊ณ ์ด๋ฏธ ์์์ด ์์ญ ๊ฐ๋ผ๋ฉด ๋ฌธ์ ๊ฐ ๋ฐ์ํ ์ ์์ต๋๋ค. ์ ํต์ ์ธ ํ์ ํธ๋ฆฌ ๊ฒ์ ์ต์ ์ด ์ด๋ป๊ฒ ์์ฑ๋๊ณ ์๋ํ๋์ง ์ดํด๋ณด๊ฒ ์ต๋๋ค. ํ์ง๋ง ๋จผ์ ์ฐ๋ฆฌ ์ฐ๊ตฌ์ ๊ฐ์ฅ ํฅ๋ฏธ๋ก์ด ๋ ธ๋๊ฐ ๋ฌด์์ธ์ง ๊ฒฐ์ ํด ๋ณด๊ฒ ์ต๋๋ค.
๊ฐ์ฅ ์ข์ "๊น์" ํ์ ํธ๋ฆฌ:
WITH RECURSIVE T AS (
SELECT
id
, pid
, ARRAY[id] path
FROM
hier
WHERE
pid IS NULL
UNION ALL
SELECT
hier.id
, hier.pid
, T.path || hier.id
FROM
T
JOIN
hier
ON hier.pid = T.id
)
TABLE T ORDER BY array_length(path, 1) DESC;
id | pid | path
---------------------------------------------
7624 | 7623 | {7615,7620,7621,7622,7623,7624}
4995 | 4994 | {4983,4985,4988,4993,4994,4995}
4991 | 4990 | {4983,4985,4988,4989,4990,4991}
...
๊ฐ์ฅ ์ข์ "๋์" ํ์ ํธ๋ฆฌ:
...
SELECT
path[1] id
, count(*)
FROM
T
GROUP BY
1
ORDER BY
2 DESC;
id | count
------------
5300 | 30
450 | 28
1239 | 27
1573 | 25
์ด๋ฌํ ์ฟผ๋ฆฌ์ ๋ํด ์ฐ๋ฆฌ๋ ์ผ๋ฐ์ ์ธ ์ฌ๊ท์ JOIN:
๋ถ๋ช
ํ ์ด ์์ฒญ ๋ชจ๋ธ์ ์ฌ์ฉํ๋ฉด ๋ฐ๋ณต ํ์๋ ์ด ํ์ ํญ๋ชฉ ์์ ์ผ์นํฉ๋๋ค. (๊ทธ๋ฆฌ๊ณ ์์ญ ๊ฐ๊ฐ ์์ต๋๋ค) ์ด๋ ์๋นํ ๋ฆฌ์์ค์ ๊ฒฐ๊ณผ์ ์ผ๋ก ์๊ฐ์ด ๊ฑธ๋ฆด ์ ์์ต๋๋ค.
"๊ฐ์ฅ ๋์" ํ์ ํธ๋ฆฌ๋ฅผ ํ์ธํด ๋ณด๊ฒ ์ต๋๋ค.
WITH RECURSIVE T AS (
SELECT
id
FROM
hier
WHERE
id = 5300
UNION ALL
SELECT
hier.id
FROM
T
JOIN
hier
ON hier.pid = T.id
)
TABLE T;
์์๋๋ก 30๊ฐ์ ๋ ์ฝ๋๋ฅผ ๋ชจ๋ ์ฐพ์์ต๋๋ค. ๊ทธ๋ฌ๋ ๊ทธ๋ค์ ์ฌ๊ธฐ์ ์ด ์๊ฐ์ 60%๋ฅผ ์๋นํ์ต๋๋ค. ์๋ํ๋ฉด ๊ทธ๋ค์ ์ธ๋ฑ์ค์์ 30๋ฒ์ ๊ฒ์๋ ์ํํ๊ธฐ ๋๋ฌธ์ ๋๋ค. ์ ๊ฒ ํ๋ ๊ฒ์ด ๊ฐ๋ฅํ๊ฐ์?
์์ธ๋ณ ๋๋๊ต์
๊ฐ ๋
ธ๋์ ๋ํด ๋ณ๋์ ์ธ๋ฑ์ค ์ฟผ๋ฆฌ๋ฅผ ๋ง๋ค์ด์ผ ํฉ๋๊น? ์๋์. ์์ธ์์ ์ฝ์ ์ ์์ต๋๋ค. ํ ๋ฒ์ ํธ์ถ๋ก ์ฌ๋ฌ ํค๋ฅผ ๋์์ ์ฌ์ฉ ๋ฅผ ํตํด = ANY(array)
.
๊ทธ๋ฆฌ๊ณ ๊ฐ ์๋ณ์ ๊ทธ๋ฃน์์ ์ด์ ๋จ๊ณ์์ "๋ ธ๋"๋ก ์ฐพ์ ๋ชจ๋ ID๋ฅผ ์ฌ์ฉํ ์ ์์ต๋๋ค. ์ฆ, ๋ค์ ๋จ๊ณ๋ง๋ค ์ฐ๋ฆฌ๋ ํน์ ๋ ๋ฒจ์ ๋ชจ๋ ์์์ ํ๋ฒ์ ๊ฒ์.
๋ค๋ง, ๋ฌธ์ ๋ ๋ฐ๋ก ์ด๊ฒ์ด๋ค. ์ฌ๊ท ์ ํ์์๋ ์ค์ฒฉ ์ฟผ๋ฆฌ์์ ์์ฒด์ ์ก์ธ์คํ ์ ์์ต๋๋ค., ํ์ง๋ง ์ด์ ์์ค์์ ์ฐพ์ ๊ฒ๋ง ์ ํํด์ผ ํฉ๋๋ค... ์ ์ฒด ์ ํ ํญ๋ชฉ์ ๋ํด ์ค์ฒฉ ์ฟผ๋ฆฌ๋ฅผ ๋ง๋๋ ๊ฒ์ด ๋ถ๊ฐ๋ฅํ์ง๋ง ํน์ ํ๋์ ๋ํด์๋ ๊ฐ๋ฅํ๋ค๋ ๊ฒ์ด ๋ฐํ์ก์ต๋๋ค. ๊ทธ๋ฆฌ๊ณ ์ด ํ๋๋ ๋ฐฐ์ด์ด ๋ ์๋ ์์ต๋๋ค. ์ด๊ฒ์ด ์ฐ๋ฆฌ๊ฐ ์ฌ์ฉํด์ผ ํ๋ ๊ฒ์
๋๋ค. ANY
.
์กฐ๊ธ ์ด์ํ๊ฒ ๋ค๋ฆฌ์ง๋ง ๋ค์ด์ด๊ทธ๋จ์์๋ ๋ชจ๋ ๊ฒ์ด ๊ฐ๋จํฉ๋๋ค.
WITH RECURSIVE T AS (
SELECT
ARRAY[id] id$
FROM
hier
WHERE
id = 5300
UNION ALL
SELECT
ARRAY(
SELECT
id
FROM
hier
WHERE
pid = ANY(T.id$)
) id$
FROM
T
WHERE
coalesce(id$, '{}') <> '{}' -- ััะปะพะฒะธะต ะฒัั
ะพะดะฐ ะธะท ัะธะบะปะฐ - ะฟัััะพะน ะผะฐััะธะฒ
)
SELECT
unnest(id$) id
FROM
T;
๊ทธ๋ฆฌ๊ณ ์ฌ๊ธฐ์ ๊ฐ์ฅ ์ค์ํ ๊ฒ์ ์๊ฐ ๋ด์ 1.5๋ฐฐ ์น๋ฆฌ, ์ธ๋ฑ์ค์ ๋ํ ํธ์ถ์ด 5๊ฐ๊ฐ ์๋ 30๊ฐ๋ฟ์ด๋ฏ๋ก ๋ ์ ์ ์์ ๋ฒํผ๋ฅผ ๋บ๋๋ค!
์ถ๊ฐ ๋ณด๋์ค๋ ์ต์ข unnest ํ์๋ ์๋ณ์๊ฐ "๋ ๋ฒจ"๋ณ๋ก ์ ๋ ฌ๋์ด ์๋ค๋ ์ฌ์ค์ ๋๋ค.
๋ ธ๋ ์ฌ์ธ
์ฑ๋ฅ ํฅ์์ ๋์์ด ๋๋ ๋ค์ ๊ณ ๋ ค ์ฌํญ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค. "์"์ ์์์ ๊ฐ์ง ์ ์์ต๋๋ค์ฆ, ๊ทธ๋ค์๊ฒ๋ ์ ํ "์๋"๋ฅผ ๋ณผ ํ์๊ฐ ์์ต๋๋ค. ์ฐ๋ฆฌ ์์ ์ ๊ณต์ํ์์ ์ด๋ ๋ถ์ ์ฒด์ธ์ ๋ฐ๋ผ ์ง์์๊ฒ ์ฐ๋ฝํ๋ฉด ์ด ์ง์ ์ ๋ ์ด์ ๋ณผ ํ์๊ฐ ์์์ ์๋ฏธํฉ๋๋ค.
์ฐ๋ฆฌ ํ
์ด๋ธ์ ๋ค์ด๊ฐ์ ์ถ๊ฐ์ boolean
-ํ๋, ์ด๋ ํธ๋ฆฌ์ ์ด ํน์ ํญ๋ชฉ์ด "๋
ธ๋"์ธ์ง, ์ฆ ํ์ ํญ๋ชฉ์ ๊ฐ์ง ์ ์๋์ง ์ฌ๋ถ๋ฅผ ์ฆ์ ์๋ ค์ค๋๋ค.
ALTER TABLE hier
ADD COLUMN branch boolean;
UPDATE
hier T
SET
branch = TRUE
WHERE
EXISTS(
SELECT
NULL
FROM
hier
WHERE
pid = T.id
LIMIT 1
);
-- ะะฐะฟัะพั ััะฟะตัะฝะพ ะฒัะฟะพะปะฝะตะฝ: 3033 ัััะพะบ ะธะทะผะตะฝะตะฝะพ ะทะฐ 42 ะผั.
์์ฒญ๋! ๋ชจ๋ ํธ๋ฆฌ ์์ ์ค 30% ๋จ์ง๋ง์ด ์์์ ๊ฐ๊ณ ์๋ ๊ฒ์ผ๋ก ๋ํ๋ฌ์ต๋๋ค.
์ด์ ์ฝ๊ฐ ๋ค๋ฅธ ๋ฉ์ปค๋์ฆ์ ์ฌ์ฉํด ๋ณด๊ฒ ์ต๋๋ค. ์ฆ, ๋ค์์ ํตํด ์ฌ๊ท ๋ถ๋ถ์ ์ฐ๊ฒฐํฉ๋๋ค. LATERAL
์ด๋ฅผ ํตํด ์ฌ๊ท "ํ
์ด๋ธ"์ ํ๋์ ์ฆ์ ์ก์ธ์คํ๊ณ ๋
ธ๋ ๊ธฐ๋ฐ ํํฐ๋ง ์กฐ๊ฑด๊ณผ ํจ๊ป ์ง๊ณ ํจ์๋ฅผ ์ฌ์ฉํ์ฌ ํค ์ธํธ๋ฅผ ์ค์ผ ์ ์์ต๋๋ค.
WITH RECURSIVE T AS (
SELECT
array_agg(id) id$
, array_agg(id) FILTER(WHERE branch) ns$
FROM
hier
WHERE
id = 5300
UNION ALL
SELECT
X.*
FROM
T
JOIN LATERAL (
SELECT
array_agg(id) id$
, array_agg(id) FILTER(WHERE branch) ns$
FROM
hier
WHERE
pid = ANY(T.ns$)
) X
ON coalesce(T.ns$, '{}') <> '{}'
)
SELECT
unnest(id$) id
FROM
T;
์ธ๋ฑ์ค ํธ์ถ์ ํ ๋ฒ ๋ ์ค์ผ ์ ์์๊ณ ์์ ์ผ๋ก 2๋ฐฐ ์ด์ ์น๋ฆฌ ๊ต์ ํ๋ค.
#2. ๋ฟ๋ฆฌ๋ก ๋์๊ฐ์
์ด ์๊ณ ๋ฆฌ์ฆ์ "ํธ๋ฆฌ ์"์ ๋ชจ๋ ์์์ ๋ํ ๊ธฐ๋ก์ ์์งํด์ผ ํ๋ ๋์์ ์ด๋ค ์์ค ์ํธ(๋ฐ ์ด๋ค ์งํ๋ก)๊ฐ ์ํ์ ํฌํจ๋์๋์ง์ ๋ํ ์ ๋ณด๋ฅผ ์ ์งํด์ผ ํ๋ ๊ฒฝ์ฐ์ ์ ์ฉํฉ๋๋ค(์: ์์ฝ ๋ณด๊ณ ์ ์์ฑ). ๋ ธ๋๋ก ์ง๊ณ๋ฉ๋๋ค.
์์ฒญ์ด ๋งค์ฐ ๋ฒ๊ฑฐ๋กญ๊ธฐ ๋๋ฌธ์ ๋ค์ ๋ด์ฉ์ ๊ฐ๋
์ฆ๋ช
์ผ๋ก๋ง ๋ฐ์๋ค์ฌ์ผ ํฉ๋๋ค. ๊ทธ๋ฌ๋ ๊ทธ๊ฒ์ด ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ฅผ ์ง๋ฐฐํ๋ค๋ฉด ์ ์ฌํ ๊ธฐ์ ์ ์ฌ์ฉํ๋ ๊ฒ์ ๊ณ ๋ คํด์ผ ํฉ๋๋ค.
๋ช ๊ฐ์ง ๊ฐ๋จํ ๋ฌธ์ฅ์ผ๋ก ์์ํด ๋ณด๊ฒ ์ต๋๋ค.
- ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ๋์ผํ ๋ ์ฝ๋ ํ ๋ฒ๋ง ์ฝ์ด๋ณด๋ ๊ฒ์ด ๊ฐ์ฅ ์ข์ต๋๋ค..
- ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ๋ ์ฝ๋ ์ผ๊ด์ ์ผ๋ก ์ฝ๋ ๊ฒ์ด ๋ ํจ์จ์ ์ ๋๋ค.ํผ์๋ณด๋ค.
์ด์ ํ์ํ ์์ฒญ์ ๊ตฌ์ฑํด ๋ณด๊ฒ ์ต๋๋ค.
1 ๋จ๊ณ
๋ถ๋ช ํ, ์ฌ๊ท๋ฅผ ์ด๊ธฐํํ ๋(์ฌ๊ท๊ฐ ์์ผ๋ฉด ์ด๋์ ์์๊น์!) ์ด๊ธฐ ์๋ณ์ ์ธํธ๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ๋ฆฌํ ์์ฒด์ ๋ ์ฝ๋๋ฅผ ๋นผ์ผ ํฉ๋๋ค.
WITH RECURSIVE tree AS (
SELECT
rec -- ััะพ ัะตะปัะฝะฐั ะทะฐะฟะธัั ัะฐะฑะปะธัั
, id::text chld -- ััะพ "ะฝะฐะฑะพั" ะฟัะธะฒะตะดัะธั
ััะดะฐ ะธัั
ะพะดะฝัั
ะปะธัััะตะฒ
FROM
hier rec
WHERE
id = ANY('{1,2,4,8,16,32,64,128,256,512,1024,2048,4096,8192}'::integer[])
UNION ALL
...
"์ธํธ"๊ฐ ๋ฐฐ์ด์ด ์๋ ๋ฌธ์์ด๋ก ์ ์ฅ๋๋ค๋ ๊ฒ์ด ๋๊ตฐ๊ฐ์๊ฒ ์ด์ํ๊ฒ ๋ณด์ธ๋ค๋ฉด ์ด์ ๋ํ ๊ฐ๋จํ ์ค๋ช
์ด ์์ต๋๋ค. ๋ฌธ์์ด์ ๋ํ ์ง๊ณ "์ ์ฐฉ" ๊ธฐ๋ฅ์ด ๋ด์ฅ๋์ด ์์ต๋๋ค. string_agg
, ๊ทธ๋ฌ๋ ๋ฐฐ์ด์๋ ํด๋น๋์ง ์์ต๋๋ค. ๋น๋ก ๊ทธ๋
๋
2 ๋จ๊ณ
์ด์ ๋ ์ฝ์ด์ผ ํ ์น์ ID ์ธํธ๋ฅผ ์ป๊ฒ ๋ฉ๋๋ค. ๊ฑฐ์ ํญ์ ์๋ณธ ์ธํธ์ ๋ค๋ฅธ ๋ ์ฝ๋์ ๋ณต์ ๋ฉ๋๋ค. ๊ทธ๋ฃนํ, ์์ค ์์ ๋ํ ์ ๋ณด๋ ๋ณด์กดํฉ๋๋ค.
๊ทธ๋ฌ๋ ์ฌ๊ธฐ์๋ ์ธ ๊ฐ์ง ๋ฌธ์ ๊ฐ ์ฐ๋ฆฌ๋ฅผ ๊ธฐ๋ค๋ฆฌ๊ณ ์์ต๋๋ค.
- ์ฟผ๋ฆฌ์ "ํ์ ์ฌ๊ท" ๋ถ๋ถ์๋ ๋ค์๊ณผ ๊ฐ์ ์ง๊ณ ํจ์๊ฐ ํฌํจ๋ ์ ์์ต๋๋ค.
GROUP BY
. - ์ฌ๊ท์ "ํ ์ด๋ธ"์ ๋ํ ์ฐธ์กฐ๋ ์ค์ฒฉ๋ ํ์ ์ฟผ๋ฆฌ์ ํฌํจ๋ ์ ์์ต๋๋ค.
- ์ฌ๊ท ๋ถ๋ถ์ ์์ฒญ์๋ CTE๊ฐ ํฌํจ๋ ์ ์์ต๋๋ค.
๋คํํ๋ ์ด๋ฌํ ๋ชจ๋ ๋ฌธ์ ๋ ํด๊ฒฐํ๊ธฐ๊ฐ ๋งค์ฐ ์ฝ์ต๋๋ค. ๋๋ถํฐ ์์ํฉ์๋ค.
์ฌ๊ท ๋ถ๋ถ์ CTE
์ฌ๊ธฐ ๊ทธ๋ ๊ฒ ์๋ ๊ณต์ฅ:
WITH RECURSIVE tree AS (
...
UNION ALL
WITH T (...)
SELECT ...
)
๊ทธ๋์ ์๋ํฉ๋๋ค. ๊ดํธ๊ฐ ์ฐจ์ด๋ฅผ ๋ง๋ญ๋๋ค!
WITH RECURSIVE tree AS (
...
UNION ALL
(
WITH T (...)
SELECT ...
)
)
์ฌ๊ท์ "ํ ์ด๋ธ"์ ๋ํ ์ค์ฒฉ ์ฟผ๋ฆฌ
ํ ... ์ฌ๊ท CTE๋ ํ์ ์ฟผ๋ฆฌ์์ ์ก์ธ์คํ ์ ์์ต๋๋ค. ํ์ง๋ง CTE ๋ด๋ถ์ ์์ ์๋ ์์ต๋๋ค! ๊ทธ๋ฆฌ๊ณ ์ค์ฒฉ๋ ์์ฒญ์ ์ด๋ฏธ ์ด CTE์ ์ก์ธ์คํ ์ ์์ต๋๋ค!
GROUP BY ๋ด๋ถ ์ฌ๊ท
๋ถ์พํ์ง๋ง... ๋ค์์ ์ฌ์ฉํ์ฌ GROUP BY๋ฅผ ์๋ฎฌ๋ ์ดํธํ๋ ๊ฐ๋จํ ๋ฐฉ๋ฒ์ด ์์ต๋๋ค. DISTINCT ON
๊ทธ๋ฆฌ๊ณ ์ฐฝ ๊ธฐ๋ฅ!
SELECT
(rec).pid id
, string_agg(chld::text, ',') chld
FROM
tree
WHERE
(rec).pid IS NOT NULL
GROUP BY 1 -- ะฝะต ัะฐะฑะพัะฐะตั!
๊ทธ๋ฆฌ๊ณ ์ด๊ฒ์ด ์๋ํ๋ ๋ฐฉ์์ ๋๋ค!
SELECT DISTINCT ON((rec).pid)
(rec).pid id
, string_agg(chld::text, ',') OVER(PARTITION BY (rec).pid) chld
FROM
tree
WHERE
(rec).pid IS NOT NULL
์ด์ ์ซ์ ID๊ฐ ํ ์คํธ๋ก ๋ณํ๋ ์ด์ ๋ฅผ ์ดํด๋ณด๊ฒ ์ต๋๋ค. ์ด๋ฅผ ํตํด ์ผํ๋ก ๊ตฌ๋ถํ์ฌ ์๋ก ๊ฒฐํฉํ ์ ์์ต๋๋ค.
3 ๋จ๊ณ
๊ฒฐ์น์ ์๋ ์๋ฌด๊ฒ๋ ๋จ์ง ์์์ต๋๋ค.
- ๊ทธ๋ฃนํ๋ ID ์ธํธ๋ฅผ ๊ธฐ๋ฐ์ผ๋ก "์น์ " ๋ ์ฝ๋๋ฅผ ์ฝ์ต๋๋ค.
- ๋บ ๋ถ๋ถ์ ์๋ณธ ์ํธ์ "์ธํธ"์ ๋น๊ตํฉ๋๋ค.
- ๋ค์์ ์ฌ์ฉํ์ฌ ์ค์ ๋ฌธ์์ด์ "ํ์ฅ"ํฉ๋๋ค.
unnest(string_to_array(chld, ',')::integer[])
WITH RECURSIVE tree AS (
SELECT
rec
, id::text chld
FROM
hier rec
WHERE
id = ANY('{1,2,4,8,16,32,64,128,256,512,1024,2048,4096,8192}'::integer[])
UNION ALL
(
WITH prnt AS (
SELECT DISTINCT ON((rec).pid)
(rec).pid id
, string_agg(chld::text, ',') OVER(PARTITION BY (rec).pid) chld
FROM
tree
WHERE
(rec).pid IS NOT NULL
)
, nodes AS (
SELECT
rec
FROM
hier rec
WHERE
id = ANY(ARRAY(
SELECT
id
FROM
prnt
))
)
SELECT
nodes.rec
, prnt.chld
FROM
prnt
JOIN
nodes
ON (nodes.rec).id = prnt.id
)
)
SELECT
unnest(string_to_array(chld, ',')::integer[]) leaf
, (rec).*
FROM
tree;
์ถ์ฒ : habr.com