דילוג לתוכן המרכזי
מודול 7 · שיעור 4 מתוך 428/57 בקורס~14 min
שיעורי מודול (4/4)

CTEs רקורסיביים: היררכיות עומק שרירותיות

חיבור עצמי (מודול 5) מוצא רק רמה אחת של היררכיה: ילד → הורה. אבל מה קורה אם ההיררכיה היא בעומק של 3, 5 או n רמות, ואתה לא יודע מראש כמה? אתה צריך CTEs רקורסיבי: א CTE שמתייחסת לעצמה כדי "להרחיב" את התוצאות באופן איטרטיבי.

במערך הנתונים ecommerce, לטבלה categories יש 3 שורשים (Elettronica, Libri, Casa) ו-2 ילדים כל אחד - עץ בן 2 מפלסים. זה א מקרה פשוט אבל מספיק כדי ללמוד את הדפוס.

התחביר

SQL
WITH RECURSIVE nome (col1, col2, …) AS (
  -- (1) Termine BASE: le righe di partenza
  SELECT …
  FROM   …
  WHERE  …

  UNION ALL

  -- (2) Termine RICORSIVO: si appoggia a "nome" stesso per espandere
  SELECT …
  FROM   tabella  t
  JOIN   nome    n  ON …
)
SELECT * FROM nome;

איך זה עובד בפועל:

  1. PostgreSQL מבצע את מונח הבסיס פעם אחת.
  2. הוא מבצע את המונח הרקורסי באמצעות השורות שהופקו זה עתה "קלט" (לא כל ה-CTE: רק התוספת).
  3. הוא חוזר על שלב 2 עד שהמונח הרקורסי מייצר 0 שורות חדשות.
  4. התוצאה הסופית היא UNION ALL של כל השלבים.

דוגמה 1: עץ עם עומק ושביל

SQL
WITH RECURSIVE tree AS (
  -- base: le radici (parent_id IS NULL)
  SELECT id,
         name,
         parent_id,
         1                 AS depth,
         name              AS path
  FROM   categories
  WHERE  parent_id IS NULL

  UNION ALL

  -- ricorsivo: per ogni categoria che ha come parent una riga già in tree
  SELECT c.id,
         c.name,
         c.parent_id,
         t.depth + 1,
         t.path || ' > ' || c.name
  FROM   categories c
  JOIN   tree       t ON c.parent_id = t.id
)
SELECT id, name, depth, path
FROM   tree
ORDER BY path;

האיטרציה הראשונה מייצרת 3 שורות (השורשים ברמה 1). השני איטרציה מוצאת את 6 הילדים (רמה 2). האיטרציה השלישית מוצאת שום דבר → נעשה.

דוגמה 2: בהינתן צומת, מצא את השורש שלו

גרסה של "מלמעלה למטה → מלמטה למעלה": אנו מפיצים את המזהה של השורש למטה העץ.

SQL
WITH RECURSIVE tree AS (
  SELECT id,
         name,
         parent_id,
         id   AS root_id,
         name AS root_name
  FROM   categories
  WHERE  parent_id IS NULL

  UNION ALL

  SELECT c.id,
         c.name,
         c.parent_id,
         t.root_id,    -- propago lo stesso id_radice
         t.root_name   -- e nome
  FROM   categories c
  JOIN   tree       t ON c.parent_id = t.id
)
SELECT id, name, root_name
FROM   tree
ORDER BY id;

נסה את זה

פעילות גופנית#sql.m7.l4.e1
ניסיונות: 0טוען...

השתמש ב-CTE רקורסיבי בשם 'עץ' כדי לשטח את היררכיית הקטגוריות. הצג מזהה, שם, עומק (1 לשורשים, 2 לילדים וכו') ונתיב (למשל 'Elettronica > Audio'). סדר לפי נתיב.

טוען עורך...
הצג רמז

ה-JOIN במונח הרקורסי מקשר את c.parent_id לשורה שכבר קיימת בעץ (t.id).

הפתרון זמין לאחר 3 ניסיונות

סקירת התרגיל

פעילות גופנית#sql.m7.l4.e2
ניסיונות: 0טוען...

עבור כל קטגוריה, הצג id, name ו-root_name (שם קטגוריית השורש בראש העץ שאליו היא שייכת). לשורשים יש root_name = שם. הזמנה לפי תעודת זהות.

טוען עורך...
הצג רמז

הפיצו root_name מהאב (t.root_name) לילד (c).

הפתרון זמין לאחר 3 ניסיונות