Oracle Recursive WITH Clause
Oracle WITH ๋ฌธ (Recursive Query) recursively Explained ๐ณ
Oracle SQL์์ WITH ์ ์ ๋ณต์กํ ์ฟผ๋ฆฌ๋ฅผ ๋จ์ํํ๊ณ ๊ฐ๋ ์ฑ์ ๋์ด๊ธฐ ์ํด ์ฌ์ฉ๋๋ ๊ฐ๋ ฅํ ๊ธฐ๋ฅ์ ๋๋ค. ํนํ, WITH ์ ์ ์ฌ๊ท์ ์ผ๋ก ์ฌ์ฉํ๋ฉด ๊ณ์ธต์ ์ธ ๋ฐ์ดํฐ๋ฅผ ์ฝ๊ฒ ์กฐํํ๊ณ ์ฒ๋ฆฌํ ์ ์์ต๋๋ค. ์๋ฅผ ๋ค์ด, ์กฐ์ง๋, ๋ถํ ๊ด๊ณ, ๋ฉ๋ด ๊ตฌ์กฐ ๋ฑ์ ๋ค๋ฃฐ ๋ ๋งค์ฐ ์ ์ฉํฉ๋๋ค.
์ฌ๊ท WITH ์ ์ ๊ธฐ๋ณธ ๊ตฌ์กฐ
์ฌ๊ท์ ์ธ WITH ์ ์ ๋ ๋ถ๋ถ์ผ๋ก ๊ตฌ์ฑ๋ฉ๋๋ค:
- ์ต์ปค ๋ฉค๋ฒ (Anchor Member): ์ฌ๊ท์ ์์์ ์ด ๋๋ ์ด๊ธฐ ๋ฐ์ดํฐ ์งํฉ์ ์ ์ํ๋ ๋ถ๋ถ์ ๋๋ค.
- ์ฌ๊ท ๋ฉค๋ฒ (Recursive Member): ์ต์ปค ๋ฉค๋ฒ์ ๊ฒฐ๊ณผ๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ๋ฐ๋ณต์ ์ผ๋ก ์ํ๋๋ฉฐ, ์ด์ ๊ฒฐ๊ณผ์ ๊ฒฐํฉ(JOIN)ํ์ฌ ๋ค์ ๊ณ์ธต์ ๋ฐ์ดํฐ๋ฅผ ์ฐพ๋ ๋ถ๋ถ์ ๋๋ค.
์ด ๋ ๋ฉค๋ฒ๋ UNION ALL
์ฐ์ฐ์๋ก ์ฐ๊ฒฐ๋ฉ๋๋ค.
WITH temp_table_name (column1, column2, ...) AS (
-- 1. Anchor Member: ์ฌ๊ท์ ์์์
SELECT column1, column2, ...
FROM your_table
WHERE initial_condition
UNION ALL
-- 2. Recursive Member: ๋ฐ๋ณต ์ํ ๋ถ๋ถ
SELECT t.column1, t.column2, ...
FROM your_table t
JOIN temp_table_name r ON recursive_join_condition
)
SELECT * FROM temp_table_name;
์ค์: ์ฌ๊ท ๋ฉค๋ฒ๋ ๋ฐ๋์ WHERE
์ ์ ์ฌ๊ท๋ฅผ ๋ฉ์ถ๊ฒ ํ๋ ์ข
๋ฃ ์กฐ๊ฑด์ ํฌํจํด์ผ ๋ฌดํ ๋ฃจํ์ ๋น ์ง์ง ์์ต๋๋ค.
์ฌ์ฉ ์์ : ์กฐ์ง๋ ์กฐํ
๊ฐ์ฅ ์ผ๋ฐ์ ์ธ ์๋ ํ์ฌ์ ์กฐ์ง๋์์ ํน์ ๋งค๋์ ์ ์ํ ๋ชจ๋ ๋ถํ ์ง์์ ์ฐพ๋ ๊ฒ์ ๋๋ค.
1. ์์ ํ ์ด๋ธ ์์ฑ
๋จผ์ , ์ง์ ์ ๋ณด๋ฅผ ๋ด๋ ๊ฐ๋จํ employees
ํ
์ด๋ธ์ ๋ง๋ค์ด ๋ณด๊ฒ ์ต๋๋ค.
CREATE TABLE employees (
emp_id NUMBER PRIMARY KEY,
emp_name VARCHAR2(50),
manager_id NUMBER
);
INSERT INTO employees VALUES (1, '์ฌ์ฅ', NULL);
INSERT INTO employees VALUES (2, '๊น๋ถ์ฅ', 1);
INSERT INTO employees VALUES (3, '์ด๊ณผ์ฅ', 2);
INSERT INTO employees VALUES (4, '๋ฐ๋๋ฆฌ', 3);
INSERT INTO employees VALUES (5, '์ต์ฌ์', 4);
INSERT INTO employees VALUES (6, '์ ์ฐจ์ฅ', 2);
INSERT INTO employees VALUES (7, 'ํ์ฌ์', 6);
์์ฑ๋ ํ ์ด๋ธ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค:
emp_id | emp_name | manager_id |
---|---|---|
1 | ์ฌ์ฅ | NULL |
2 | ๊น๋ถ์ฅ | 1 |
3 | ์ด๊ณผ์ฅ | 2 |
4 | ๋ฐ๋๋ฆฌ | 3 |
5 | ์ต์ฌ์ | 4 |
6 | ์ ์ฐจ์ฅ | 2 |
7 | ํ์ฌ์ | 6 |
2. ์ฌ๊ท ์ฟผ๋ฆฌ ์์ฑ
'๊น๋ถ์ฅ'(emp_id = 2
)์ ๊ธฐ์ค์ผ๋ก ๋ชจ๋ ํ์ ์ง์์ ์กฐํํ๋ ์ฌ๊ท ์ฟผ๋ฆฌ๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค. ์ฌ๊ธฐ์๋ ๊ณ์ธต์ ๊น์ด๋ฅผ ๋ํ๋ด๋ level
๋ ํจ๊ป ์กฐํํด ๋ณด๊ฒ ์ต๋๋ค.
WITH emp_hierarchy (emp_id, emp_name, manager_id, lvl) AS (
-- Anchor Member: ์์์ ('๊น๋ถ์ฅ')
SELECT
emp_id,
emp_name,
manager_id,
1 AS lvl
FROM
employees
WHERE
emp_id = 2
UNION ALL
-- Recursive Member: ํ์ ์ง์ ์ฐพ๊ธฐ
SELECT
e.emp_id,
e.emp_name,
e.manager_id,
h.lvl + 1
FROM
employees e
JOIN
emp_hierarchy h ON e.manager_id = h.emp_id
)
SELECT
LPAD(' ', (lvl-1) * 4) || emp_name AS employee_name,
emp_id,
manager_id,
lvl
FROM
emp_hierarchy;
3. ์ฟผ๋ฆฌ ์คํ ๊ฒฐ๊ณผ
์ ์ฟผ๋ฆฌ๋ฅผ ์คํํ๋ฉด ๋ค์๊ณผ ๊ฐ์ด ๊ณ์ธต ๊ตฌ์กฐ๋ก ์ ๋ ฌ๋ ๊ฒฐ๊ณผ๋ฅผ ์ป์ ์ ์์ต๋๋ค.
EMPLOYEE_NAME | EMP_ID | MANAGER_ID | LVL |
---|---|---|---|
๊น๋ถ์ฅ | 2 | 1 | 1 |
์ด๊ณผ์ฅ | 3 | 2 | 2 |
์ ์ฐจ์ฅ | 6 | 2 | 2 |
๋ฐ๋๋ฆฌ | 4 | 3 | 3 |
ํ์ฌ์ | 7 | 6 | 3 |
์ต์ฌ์ | 5 | 4 | 4 |
๋์ ์๋ฆฌ โ๏ธ
- ์ต์ปค ๋ฉค๋ฒ ์คํ: ๋จผ์ ์ต์ปค ๋ฉค๋ฒ ์ฟผ๋ฆฌ๊ฐ ์คํ๋์ด
emp_id
๊ฐ 2์ธ '๊น๋ถ์ฅ'์ ์ ๋ณด๋ฅผ ์ฐพ๊ณ , ์ด ๊ฒฐ๊ณผ๊ฐ ์์ ํ ์ด๋ธemp_hierarchy
์ ์ ์ฅ๋ฉ๋๋ค. (lvl = 1) - ์ฌ๊ท ๋ฉค๋ฒ ์คํ (1์ฐจ): ์ฌ๊ท ๋ฉค๋ฒ๋
emp_hierarchy
์ ์๋ ๊ฒฐ๊ณผ(๊น๋ถ์ฅ)๋ฅผ ์ฐธ์กฐํฉ๋๋ค.e.manager_id = h.emp_id
์กฐ๊ฑด์ ๋ฐ๋ผ '๊น๋ถ์ฅ'์ ๋งค๋์ ๋ก ํ๋ ์ง์๋ค('์ด๊ณผ์ฅ', '์ ์ฐจ์ฅ')์ ์ฐพ์ต๋๋ค. ์ด ๊ฒฐ๊ณผ๋ ๊ธฐ์กด ๊ฒฐ๊ณผ์UNION ALL
๋ก ์ถ๊ฐ๋ฉ๋๋ค. (lvl = 2) - ์ฌ๊ท ๋ฉค๋ฒ ์คํ (2์ฐจ): ์ด์
emp_hierarchy
์๋ '๊น๋ถ์ฅ', '์ด๊ณผ์ฅ', '์ ์ฐจ์ฅ'์ ์ ๋ณด๊ฐ ์์ต๋๋ค. ์ฌ๊ท ๋ฉค๋ฒ๋ ๋ฐ๋ก ์ด์ ๋จ๊ณ์์ ์ถ๊ฐ๋ '์ด๊ณผ์ฅ'๊ณผ '์ ์ฐจ์ฅ'์ ์ฐธ์กฐํ์ฌ ๊ทธ๋ค์ ํ์ ์ง์์ ์ฐพ์ต๋๋ค. '๋ฐ๋๋ฆฌ'์ 'ํ์ฌ์'์ด ์ฐพ์์ ธ ๊ฒฐ๊ณผ์ ์ถ๊ฐ๋ฉ๋๋ค. (lvl = 3) - ๋ฐ๋ณต ๋ฐ ์ข ๋ฃ: ์ด ๊ณผ์ ์ ์ฌ๊ท ๋ฉค๋ฒ๊ฐ ๋ ์ด์ ์๋ก์ด ํ์ ๋ฐํํ์ง ์์ ๋๊น์ง ๋ฐ๋ณต๋ฉ๋๋ค. ๋ง์ง๋ง์ผ๋ก '์ต์ฌ์'์ด ์ถ๊ฐ๋ ํ์๋ ๋ ์ด์ ํ์ ์ง์์ด ์์ผ๋ฏ๋ก ์ฌ๊ท๊ฐ ์ข ๋ฃ๋ฉ๋๋ค.
- ์ต์ข
SELECT: WITH ์ ์ ์คํ์ด ์๋ฃ๋๋ฉด, ์ต์ข
SELECT
๋ฌธ์ดemp_hierarchy
์ ์์ธ ๋ชจ๋ ๋ฐ์ดํฐ๋ฅผ ์กฐํํ์ฌ ๊ฒฐ๊ณผ๋ฅผ ๋ณด์ฌ์ค๋๋ค.