DEV/DB

Oracle Recursive WITH Clause

SBP 2025. 6. 10. 10:22
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

๋™์ž‘ ์›๋ฆฌ โš™๏ธ

  1. ์•ต์ปค ๋ฉค๋ฒ„ ์‹คํ–‰: ๋จผ์ € ์•ต์ปค ๋ฉค๋ฒ„ ์ฟผ๋ฆฌ๊ฐ€ ์‹คํ–‰๋˜์–ด emp_id๊ฐ€ 2์ธ '๊น€๋ถ€์žฅ'์˜ ์ •๋ณด๋ฅผ ์ฐพ๊ณ , ์ด ๊ฒฐ๊ณผ๊ฐ€ ์ž„์‹œ ํ…Œ์ด๋ธ” emp_hierarchy์— ์ €์žฅ๋ฉ๋‹ˆ๋‹ค. (lvl = 1)
  2. ์žฌ๊ท€ ๋ฉค๋ฒ„ ์‹คํ–‰ (1์ฐจ): ์žฌ๊ท€ ๋ฉค๋ฒ„๋Š” emp_hierarchy์— ์žˆ๋Š” ๊ฒฐ๊ณผ(๊น€๋ถ€์žฅ)๋ฅผ ์ฐธ์กฐํ•ฉ๋‹ˆ๋‹ค. e.manager_id = h.emp_id ์กฐ๊ฑด์— ๋”ฐ๋ผ '๊น€๋ถ€์žฅ'์„ ๋งค๋‹ˆ์ €๋กœ ํ•˜๋Š” ์ง์›๋“ค('์ด๊ณผ์žฅ', '์ •์ฐจ์žฅ')์„ ์ฐพ์Šต๋‹ˆ๋‹ค. ์ด ๊ฒฐ๊ณผ๋Š” ๊ธฐ์กด ๊ฒฐ๊ณผ์— UNION ALL๋กœ ์ถ”๊ฐ€๋ฉ๋‹ˆ๋‹ค. (lvl = 2)
  3. ์žฌ๊ท€ ๋ฉค๋ฒ„ ์‹คํ–‰ (2์ฐจ): ์ด์ œ emp_hierarchy์—๋Š” '๊น€๋ถ€์žฅ', '์ด๊ณผ์žฅ', '์ •์ฐจ์žฅ'์˜ ์ •๋ณด๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ์žฌ๊ท€ ๋ฉค๋ฒ„๋Š” ๋ฐ”๋กœ ์ด์ „ ๋‹จ๊ณ„์—์„œ ์ถ”๊ฐ€๋œ '์ด๊ณผ์žฅ'๊ณผ '์ •์ฐจ์žฅ'์„ ์ฐธ์กฐํ•˜์—ฌ ๊ทธ๋“ค์˜ ํ•˜์œ„ ์ง์›์„ ์ฐพ์Šต๋‹ˆ๋‹ค. '๋ฐ•๋Œ€๋ฆฌ'์™€ 'ํ™์‚ฌ์›'์ด ์ฐพ์•„์ ธ ๊ฒฐ๊ณผ์— ์ถ”๊ฐ€๋ฉ๋‹ˆ๋‹ค. (lvl = 3)
  4. ๋ฐ˜๋ณต ๋ฐ ์ข…๋ฃŒ: ์ด ๊ณผ์ •์€ ์žฌ๊ท€ ๋ฉค๋ฒ„๊ฐ€ ๋” ์ด์ƒ ์ƒˆ๋กœ์šด ํ–‰์„ ๋ฐ˜ํ™˜ํ•˜์ง€ ์•Š์„ ๋•Œ๊นŒ์ง€ ๋ฐ˜๋ณต๋ฉ๋‹ˆ๋‹ค. ๋งˆ์ง€๋ง‰์œผ๋กœ '์ตœ์‚ฌ์›'์ด ์ถ”๊ฐ€๋œ ํ›„์—๋Š” ๋” ์ด์ƒ ํ•˜์œ„ ์ง์›์ด ์—†์œผ๋ฏ€๋กœ ์žฌ๊ท€๊ฐ€ ์ข…๋ฃŒ๋ฉ๋‹ˆ๋‹ค.
  5. ์ตœ์ข… SELECT: WITH ์ ˆ์˜ ์‹คํ–‰์ด ์™„๋ฃŒ๋˜๋ฉด, ์ตœ์ข… SELECT ๋ฌธ์ด emp_hierarchy์— ์Œ“์ธ ๋ชจ๋“  ๋ฐ์ดํ„ฐ๋ฅผ ์กฐํšŒํ•˜์—ฌ ๊ฒฐ๊ณผ๋ฅผ ๋ณด์—ฌ์ค๋‹ˆ๋‹ค.