รวมตัวเองแบบเรียกซ้ำ


15

ฉันมีcommentsตารางซึ่งสามารถทำให้ง่ายลงไปนี้:

comments
=======
id
user_id
text
parent_id

โดยที่parent_idnullable แต่อาจเป็นกุญแจสำคัญสำหรับความคิดเห็นหลัก


ตอนนี้ฉันจะselectทายาทของความคิดเห็นเฉพาะได้อย่างไร
ความคิดเห็นอาจลดลงหลายระดับ ...

คำตอบ:


16

แบบสอบถามแบบลำดับชั้นซึ่งเป็นที่รู้จักกันว่าแบบสอบถามแบบเรียกซ้ำเหล่านั้นไม่ได้รับการสนับสนุนสำหรับ MySQL

อย่างไรก็ตามได้รับการสนับสนุนใน Oracle, Microsoft SQL Server, DB2 และ PostgreSQL และอื่น ๆ

หากคุณต้องการวิธีแก้ปัญหาคุณสามารถหาเคล็ดลับแบบไดนามิก (และอาจเป็นอันตราย) ที่นี่: /programming/8104187/mysql-hierarchical-queries

นอกจากนี้คุณยังสามารถค้นหาการอภิปรายเกี่ยวกับวิธีการจัดเก็บข้อมูลแบบลำดับชั้นด้วยรุ่นอื่น ๆ นอกเหนือจากรายการ Adjacency (เช่นคอลัมน์ผู้ปกครอง ) ได้ที่นี่: /programming/192220/what-is-the-most-e-- สง่างามทางเพื่อแยก-a-แบนตารางลงใน-a-ต้น /

โชคดี!


ฉันสงสัยว่าโซลูชันในลิงก์ที่สองของคุณอาจเป็นอันตรายได้อย่างไร คุณอธิบายได้ไหม มิฉะนั้นยินดีต้อนรับสู่เว็บไซต์!
dezso

3
@dezso: สิ่งที่น่าสงสัยของแบบสอบถาม Quassnoi " * มันไม่ได้อัพเกรดปลอดภัย" เพราะ MySQL ไม่ได้กำหนดพฤติกรรมของตัวแปรเซสชันอย่างชัดเจนอย่างไรก็ตามเป็นวิธีเดียวที่จะจัดการกับรายการ adjacency ในเวลาที่ต้องการ " คำที่เป็นอันตรายอาจมีความแรงเกินไป ( อาจจะไม่เสถียร ?) แต่ฉันชอบที่จะทำอย่างระมัดระวัง (บวกฉันมีความรู้ใน Oracle มากกว่า MySQL ดังนั้นฉันจึงต้องการมีความระมัดระวังเป็นพิเศษ) ขอบคุณสำหรับการต้อนรับโดยวิธี! ฉันเป็นคนแฝงตัวมาเป็นเวลานานในเครือข่าย SE และฉันตัดสินใจว่ามันถึงเวลาแล้วที่จะต้องจ่ายคืนสักหน่อย
Valmoer

2
ตอนนี้ไวยากรณ์ WITH [RECURSIVE] ได้รับการสนับสนุนจาก mysql 8.0 แล้ว dev.mysql.com/doc/refman/8.0/en/with.html
ClearCrescendo

6

การออกแบบตารางนี้เป็น SQL antipattern "ต้นไม้ไร้เดียงสา" ตามที่อธิบายโดย Bill Karwin (จ้องมองจากสไลด์ที่ 48 ในการนำเสนอSQL Antipatterns Strike Backของเขา) ปัญหาเกี่ยวกับการออกแบบนี้โดยเฉพาะคือความยากลำบากในการรับลูกหลานทั้งหมด (หรือผู้ปกครอง) ของโหนด เนื่องจากคุณใช้ MySQL คุณไม่สามารถใช้นิพจน์ตารางทั่วไป (คำสั่ง WITH และตัวแก้ไข RECURSIVE) ที่มีอยู่ใน RDBMS อื่น

สิ่งที่คุณเหลืออยู่คือ:

  • ใช้การดำเนินการทางเลือกของโครงสร้างข้อมูลแบบลำดับชั้น (คำตอบสำหรับคำถามนี้อาจเป็นการอ้างอิงที่ดีในเรื่องนี้)
  • สร้างแบบสอบถามเข้าร่วมด้วยตนเองด้วยขีด จำกัด เชิงลึก สำหรับ depth = 5 คุณสามารถใช้บางอย่างในบรรทัด:

    SELECT *
    FROM comments AS c1
      JOIN comments AS c2 ON (c2.parent_id = c1.id)
      JOIN comments AS c3 ON (c3.parent_id = c2.id)
      JOIN comments AS c4 ON (c4.parent_id = c3.id)
      JOIN comments AS c5 ON (c5.parent_id = c4.id)
  • ใช้ RDBMS ซึ่งรองรับด้วย RECURSIVE (แม้ว่าสิ่งนี้อาจไม่ใช่ตัวเลือกสำหรับคนส่วนใหญ่)


2
ฉันไม่เห็นด้วยกับ Bill Karwin ที่นี่ โมเดล adjacency ไม่ใช่ anti-pattern ด้วย DBMS ที่ทันสมัยซึ่งรองรับการสืบค้นแบบเรียกซ้ำ (Oracle สนับสนุนสิ่งนี้มานานกว่า 20 ปี) รูปแบบดังกล่าวมีประสิทธิภาพมากในการเรียกและอัปเดต
a_horse_with_no_name

5

MySQL ไม่รองรับการสืบค้นแบบเรียกซ้ำเช่นที่คุณต้องการ

สิ่งที่ฉันทำในขณะที่กลับมาเขียนขั้นตอนการจัดเก็บที่ให้รูปแบบการทำเช่นนั้น

ฉันจะให้ลิงค์ไปยังโพสต์ที่ผ่านมาของฉันแทนสิ่งนี้:

กล่าวโดยย่อคือขั้นตอนการจัดเก็บที่ฉันทำจะทำการสำรวจต้นไม้ล่วงหน้าโดยใช้การประมวลผลคิว

  • GetParentIDByID
  • GetAncestry
  • GetFamilyTree

ผู้ปกครองถึงเด็กทุกคน (เช่นขั้นตอนการเก็บ GetFamilyTree)

  • STEP01) เริ่มด้วย a parent_idในคิว
  • ขั้นตอนที่ 02) ทำสำเนาถัดไปparent_idเป็นปัจจุบัน
  • STEP03) จัดคิวidค่าทั้งหมดที่มีอยู่ในปัจจุบันparent_id
  • STEP04) พิมพ์หรือรวบรวมความคิดเห็น
  • STEP05) หากคิวไม่ว่างให้ข้ามไป STEP02
  • ขั้นตอนที่ 06) เสร็จแล้ว !!!

เด็กกับผู้ปกครองทั้งหมด (เช่นขั้นตอนการจัดเก็บ GetAncestry)

  • STEP01) เริ่มด้วยida ในคิว
  • ขั้นตอนที่ 02) ทำสำเนาถัดไปidเป็นปัจจุบัน
  • STEP03) เข้าคิวparent_idค่าปัจจุบันid
  • STEP04) พิมพ์หรือรวบรวมความคิดเห็น
  • STEP05) หากคิวไม่ว่างให้ข้ามไป STEP02
  • ขั้นตอนที่ 06) เสร็จแล้ว !!!

โปรดดูขั้นตอนการจัดเก็บในโพสต์อื่น ๆ ของฉันเพื่อดูการใช้งาน

ให้มันลอง !!!


โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.