0Pricing
SQL Academy · บทเรียน

การเดินผ่านต้นไม้หมวดหมู่

ขยายต้นไม้พ่อแม่-ลูกให้ครบถ้วน

การเดินผ่านต้นไม้หมวดหมู่ เป็นบทเรียน SQL Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 2 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน SQL Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส SQL Academy มีบทเรียนทั้งหมด 4 บทเรียน

ต้นไม้หมวดหมู่คืออะไร

ชุดข้อมูลในโลกจริงจำนวนมากมีความสัมพันธ์ระหว่างโหนดแม่กับโหนดลูก แค็ตตาล็อกสินค้าอาจมีหมวดหมู่ เช่น อุปกรณ์อิเล็กทรอนิกส์ → โทรศัพท์ → สมาร์ตโฟน แต่ละโหนดมีโหนดแม่ จึงก่อให้เกิดโครงสร้างต้นไม้

ในภาษาเอสคิวแอล โดยทั่วไปจะจัดเก็บข้อมูลนี้เป็นตารางที่อ้างอิงตัวเอง โดยแต่ละแถวมี id และ parent_id ซึ่งชี้ไปยังอีกแถวหนึ่งในตารางเดียวกัน

CREATE TABLE categories (
  id       INT PRIMARY KEY,
  name     VARCHAR(100) NOT NULL,
  parent_id INT REFERENCES categories(id)
);

ข้อมูลหมวดหมู่ตัวอย่าง

มาสร้างต้นไม้หมวดหมู่ขนาดเล็กกัน โหนดรากมี parent_id = NULL เพราะไม่มีโหนดแม่ ส่วนโหนดอื่นทุกโหนดจะชี้ไปยังโหนดแม่ด้วยค่า parent_id ที่ไม่เป็นค่าว่าง

INSERT INTO categories (id, name, parent_id) VALUES
  (1, 'Electronics',   NULL),
  (2, 'Phones',         1),
  (3, 'Laptops',        1),
  (4, 'Smartphones',    2),
  (5, 'Feature Phones', 2),
  (6, 'Gaming Laptops', 3),
  (7, 'Ultrabooks',     3);

ปัญหาของคิวรีแบบง่าย

SELECT ธรรมดาสามารถดึงข้อมูลได้ทีละระดับเท่านั้น หากต้องการเข้าถึงข้อมูลที่ลึกสามระดับ คุณจะต้องใช้คิวรีแยกกันสามชุดหรือการเชื่อมตารางกับตัวเองสามครั้ง ซึ่งจะจัดการได้ยากขึ้นเมื่อต้นไม้ขยายใหญ่ขึ้น

WITH RECURSIVE แก้ปัญหานี้ด้วยการเปิดให้คิวรีอ้างอิงผลลัพธ์ของตัวเอง และไล่ไปทีละระดับจนไม่พบแถวใหม่

-- This only shows direct children of Electronics (level 1)
SELECT id, name
FROM   categories
WHERE  parent_id = 1;

โครงสร้างของ WITH RECURSIVE

CTE แบบเรียกซ้ำมีสองส่วนที่คั่นด้วย UNION ALL:

1. สมาชิกฐาน — SELECT ปกติที่ให้แถวเริ่มต้น

2. สมาชิกแบบเรียกซ้ำ — SELECT ที่เชื่อม CTE กลับเข้ากับตัวมันเอง โดยสร้างระดับถัดไปในการวนซ้ำแต่ละครั้ง

ระบบประมวลผลจะทำซ้ำสมาชิกแบบเรียกซ้ำจนกว่าจะไม่ส่งคืนแถวใดเลย

WITH RECURSIVE cte AS (
  -- Anchor: starting rows
  SELECT ...
  UNION ALL
  -- Recursive: join cte to base table
  SELECT ... FROM base_table JOIN cte ON ...
)
SELECT * FROM cte;

เดินสำรวจต้นไม้ทั้งหมดจากราก

เริ่มจากราก (ตำแหน่งที่ parent_id IS NULL) แล้วเดินสำรวจลงไปยังลูกหลานทุกโหนด สมาชิกแบบเรียกซ้ำจะเชื่อมแต่ละแถวที่สะสมไว้กลับเข้ากับ categories ตามความสัมพันธ์ระหว่างแม่กับลูก

WITH RECURSIVE category_tree AS (
  -- Anchor: root nodes
  SELECT id, name, parent_id, 1 AS depth
  FROM   categories
  WHERE  parent_id IS NULL

  UNION ALL

  -- Recursive: children of current level
  SELECT c.id, c.name, c.parent_id, ct.depth + 1
  FROM   categories      c
  JOIN   category_tree   ct ON ct.id = c.parent_id
)
SELECT id, name, depth
FROM   category_tree
ORDER  BY depth, id;

การติดตามเส้นทาง

การบันทึกเส้นทางเต็มจากรากไปยังแต่ละโหนดมีประโยชน์ คุณสามารถสร้างข้อความ path ด้วยการนำชื่อบรรพบุรุษมาต่อกันขณะเรียกซ้ำลึกลงไป

วิธีนี้ช่วยให้แสดงเส้นทางนำทาง เช่น อุปกรณ์อิเล็กทรอนิกส์ / โทรศัพท์ / สมาร์ตโฟน ได้อย่างง่ายดาย

WITH RECURSIVE category_tree AS (
  SELECT id, name, parent_id,
         name AS path
  FROM   categories
  WHERE  parent_id IS NULL

  UNION ALL

  SELECT c.id, c.name, c.parent_id,
         ct.path || ' / ' || c.name
  FROM   categories    c
  JOIN   category_tree ct ON ct.id = c.parent_id
)
SELECT id, name, path
FROM   category_tree
ORDER  BY path;

เริ่มจากโหนดที่ระบุ

คุณไม่จำเป็นต้องเริ่มจากราก โดยเปลี่ยนส่วนคำสั่ง WHERE ของสมาชิกฐาน คุณก็สามารถเดินสำรวจต้นไม้ย่อยของโหนดใดก็ได้ ในที่นี้เราเริ่มจาก โทรศัพท์ (รหัส = 2) และดึงลูกหลานทั้งหมดของโหนดนี้

WITH RECURSIVE subtree AS (
  SELECT id, name, parent_id, 0 AS depth
  FROM   categories
  WHERE  id = 2          -- start at Phones

  UNION ALL

  SELECT c.id, c.name, c.parent_id, s.depth + 1
  FROM   categories c
  JOIN   subtree    s ON s.id = c.parent_id
)
SELECT id, name, depth
FROM   subtree
ORDER  BY depth, id;

เดินสำรวจขึ้นด้านบน: ค้นหาบรรพบุรุษทั้งหมด

คุณสามารถเดินสำรวจต้นไม้ในทิศทางย้อนกลับได้เช่นกัน โดยเดินขึ้นจากโหนดปลายไปยังราก เพียงสลับการเชื่อมเพื่อให้ติดตาม parent_id ขึ้นด้านบนแทนการลงด้านล่าง วิธีนี้มีประโยชน์เมื่อต้องการเส้นทางนำทางทั้งหมดของโหนดปลายที่ทราบอยู่แล้ว

WITH RECURSIVE ancestors AS (
  SELECT id, name, parent_id
  FROM   categories
  WHERE  id = 4          -- start at Smartphones

  UNION ALL

  SELECT c.id, c.name, c.parent_id
  FROM   categories c
  JOIN   ancestors  a ON a.parent_id = c.id
)
SELECT id, name
FROM   ancestors
ORDER  BY id;

เพิ่มการแสดงผลแบบเยื้อง

รูปแบบทั่วไปของส่วนติดต่อผู้ใช้คือการเยื้องโหนดลูกให้เห็นทางภาพ คุณสามารถใช้ REPEAT (หรือ LPAD) ร่วมกับคอลัมน์ depth เพื่อเติมช่องว่างหน้าชื่อแต่ละชื่อ ทำให้เกิดมุมมองต้นไม้แบบข้อความ

WITH RECURSIVE category_tree AS (
  SELECT id, name, parent_id, 0 AS depth
  FROM   categories
  WHERE  parent_id IS NULL

  UNION ALL

  SELECT c.id, c.name, c.parent_id, ct.depth + 1
  FROM   categories    c
  JOIN   category_tree ct ON ct.id = c.parent_id
)
SELECT
  REPEAT('    ', depth) || name AS indented_name,
  depth
FROM   category_tree
ORDER  BY path;

ป้องกันวงวนไม่สิ้นสุด

หากข้อมูลมีวงจร (A เป็นแม่ของ B และ B เป็นแม่ของ A) การเรียกซ้ำจะทำงานไม่สิ้นสุดและทำให้ระบบขัดข้อง คุณสามารถป้องกันปัญหานี้ได้ด้วยการติดตาม ID ที่เยี่ยมชมแล้วในอาร์เรย์ และหยุดเมื่อ ID ปัจจุบันมีอยู่ในอาร์เรย์แล้ว

WITH RECURSIVE safe_tree AS (
  SELECT id, name, parent_id,
         ARRAY[id] AS visited
  FROM   categories
  WHERE  parent_id IS NULL

  UNION ALL

  SELECT c.id, c.name, c.parent_id,
         st.visited || c.id
  FROM   categories c
  JOIN   safe_tree  st ON st.id = c.parent_id
  WHERE  c.id <> ALL(st.visited)   -- stop if already seen
)
SELECT id, name FROM safe_tree;

นับลูกหลานของแต่ละโหนด

เมื่อมีต้นไม้ทั้งหมดแล้ว คุณสามารถรวมผลได้ ในที่นี้เรานับจำนวนลูกหลานของแต่ละโหนดโดยจัดกลุ่มแถวลูกโดยอ้างอิงกับรายการบรรพบุรุษ วิธีนี้มีประโยชน์สำหรับแสดงจำนวนรายการถัดจากชื่อหมวดหมู่ในเมนูนำทาง

WITH RECURSIVE category_tree AS (
  SELECT id, name, parent_id, id AS root_id
  FROM   categories
  WHERE  parent_id IS NULL

  UNION ALL

  SELECT c.id, c.name, c.parent_id, ct.root_id
  FROM   categories    c
  JOIN   category_tree ct ON ct.id = c.parent_id
)
SELECT
  root_id,
  COUNT(*) - 1 AS descendant_count
FROM   category_tree
GROUP  BY root_id
ORDER  BY root_id;

ตรวจสอบความเข้าใจ

ทดสอบความเข้าใจของคุณเกี่ยวกับคำสั่งสอบถามต้นไม้หมวดหมู่แบบเรียกซ้ำ

ทบทวนบทเรียน

ในบทเรียนนี้ คุณได้เรียนรู้วิธีเดินสำรวจตารางหมวดหมู่ที่อ้างอิงถึงตัวเองโดยใช้ WITH RECURSIVE

ประเด็นสำคัญ:

- สมาชิกฐาน เลือกโหนดเริ่มต้น ซึ่งโดยปกติคือราก

- สมาชิกแบบเรียกซ้ำ เชื่อม CTE กลับเข้ากับตารางฐานเพื่อค้นหาระดับถัดไป

- เพิ่มคอลัมน์ depth เพื่อติดตามว่าแต่ละโหนดอยู่ลึกกี่ระดับ

- สร้างข้อความ path เพื่อสร้างเส้นทางนำทาง

- เดินสำรวจ ขึ้นด้านบน โดยติดตาม parent_id ย้อนกลับเพื่อค้นหาบรรพบุรุษทั้งหมด

- ใช้อาร์เรย์ visited เพื่อป้องกันวงจรในข้อมูลที่มีปัญหา

คำถามที่พบบ่อย

บทเรียน “การเดินผ่านต้นไม้หมวดหมู่” ฟรีหรือไม่

ใช่ — ข้อความเต็มของ “การเดินผ่านต้นไม้หมวดหมู่” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส SQL Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส SQL Academy มีบทเรียนทั้งหมด 4 บทเรียน

คุณจะเรียนรู้อะไรในบทเรียน “การเดินผ่านต้นไม้หมวดหมู่”

ขยายต้นไม้พ่อแม่-ลูกให้ครบถ้วน คุณปฏิบัติ SQL Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน

คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน SQL Academy หรือไม่

ไม่จำเป็นต้องมีประสบการณ์มาก่อน SQL Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 2 จากทั้งหมด 4 บทเรียน

บทเรียน “การเดินผ่านต้นไม้หมวดหมู่” ใช้เวลานานแค่ไหน

บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย

ฉันเขียนและรันโค้ดในบทเรียน SQL Academy นี้ได้ไหม

ได้ บทเรียน SQL Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ

บทเรียนทั้งหมดในหลักสูตรนี้

  1. การทำงานของ CTE แบบเรียกซ้ำ
  2. การเดินผ่านต้นไม้หมวดหมู่
  3. การสร้างชุดและลำดับ
  4. การหลีกเลี่ยงลูปไม่รู้จบ
← กลับไปที่ SQL Academy