สำหรับMySQL 8+:ใช้withไวยากรณ์ซ้ำ
สำหรับMySQL 5.x:ใช้ตัวแปรอินไลน์, ID พา ธ หรือการรวมตัวเอง
MySQL 8+
with recursive cte (id, name, parent_id) as (
select id,
name,
parent_id
from products
where parent_id = 19
union all
select p.id,
p.name,
p.parent_id
from products p
inner join cte
on p.parent_id = cte.id
)
select * from cte;
parent_id = 19ควรระบุค่าที่ระบุในเป็นidของพาเรนต์ที่คุณต้องการเลือกการสืบทอดทั้งหมด
MySQL 5.x
สำหรับเวอร์ชัน MySQL ที่ไม่สนับสนุน Common Table Expressions (จนถึงรุ่น 5.7) คุณจะได้รับสิ่งนี้โดยใช้แบบสอบถามต่อไปนี้:
select id,
name,
parent_id
from (select * from products
order by parent_id, id) products_sorted,
(select @pv := '19') initialisation
where find_in_set(parent_id, @pv)
and length(@pv := concat(@pv, ',', id))
นี่คือไวโอลิน
ในที่นี้ค่าที่ระบุใน@pv := '19'ควรถูกตั้งค่าเป็นidของพาเรนต์ที่คุณต้องการเลือกการสืบทอดทั้งหมดของ
วิธีนี้จะใช้ได้หากผู้ปกครองมีลูกหลายคน อย่างไรก็ตามจำเป็นต้องให้แต่ละเรคคอร์ดเป็นไปตามเงื่อนไขparent_id < idมิฉะนั้นผลลัพธ์จะไม่สมบูรณ์
การมอบหมายตัวแปรภายในแบบสอบถาม
แบบสอบถามนี้ใช้ไวยากรณ์ MySQL ที่เฉพาะเจาะจง: ตัวแปรถูกกำหนดและแก้ไขระหว่างการดำเนินการ สมมติฐานบางอย่างเกี่ยวกับลำดับของการดำเนินการ:
fromประโยคแรกที่ได้รับการประเมิน นั่นคือที่ที่@pvจะเริ่มต้นได้
whereข้อคือการประเมินผลสำหรับแต่ละระเบียนในคำสั่งของการดึงจากที่fromนามแฝง ดังนั้นนี่คือที่ที่เงื่อนไขถูกใส่เพื่อรวมเฉพาะเร็กคอร์ดที่พาเรนต์ถูกระบุว่าอยู่ในทรีลูกหลาน (ลูกหลานของพาเรนต์หลักจะถูกเพิ่มไป@pvเรื่อย ๆ )
- เงื่อนไขใน
whereข้อนี้มีการประเมินตามลำดับและการประเมินผลจะถูกขัดจังหวะเมื่อผลรวมแน่นอน ดังนั้นเงื่อนไขที่สองจะต้องอยู่ในตำแหน่งที่สองเนื่องจากมันจะเพิ่มidลงในรายการพาเรนต์และสิ่งนี้จะเกิดขึ้นก็ต่อเมื่อidผ่านเงื่อนไขแรก lengthฟังก์ชั่นที่เรียกว่าเพียงเพื่อให้แน่ใจว่าสภาพเช่นนี้เป็นความจริงเสมอแม้ว่าpvสตริงจะด้วยเหตุผลบางอย่างให้ผลคุ้มค่า falsy
ทั้งหมดในทุกคนอาจพบว่าสมมติฐานเหล่านี้เสี่ยงเกินไปที่จะพึ่งพา เอกสารเตือน:
คุณอาจได้รับผลลัพธ์ตามที่คาดหวัง แต่สิ่งนี้ไม่รับประกัน [... ] ลำดับการประเมินผลสำหรับนิพจน์ที่เกี่ยวข้องกับตัวแปรผู้ใช้นั้นไม่ได้กำหนดไว้
ดังนั้นแม้ว่าจะใช้งานได้อย่างสอดคล้องกับแบบสอบถามด้านบนลำดับการประเมินอาจยังเปลี่ยนแปลงเช่นเมื่อคุณเพิ่มเงื่อนไขหรือใช้แบบสอบถามนี้เป็นมุมมองหรือแบบสอบถามย่อยในแบบสอบถามที่มีขนาดใหญ่ขึ้น มันเป็น "คุณสมบัติ" ที่จะถูกลบออกในรุ่น MySQL ในอนาคต :
รุ่นก่อนหน้านี้ของ MySQL ทำให้มันเป็นไปได้ที่จะกำหนดค่าให้กับตัวแปรของผู้ใช้ในงบอื่น ๆ SETกว่า ฟังก์ชั่นนี้รองรับใน MySQL 8.0 สำหรับความเข้ากันได้แบบย้อนหลัง แต่ขึ้นอยู่กับการลบใน MySQL รุ่นใหม่ในอนาคต
ตามที่ระบุไว้ข้างต้นจาก MySQL 8.0 เป็นต้นไปคุณควรใช้withไวยากรณ์ซ้ำ
อย่างมีประสิทธิภาพ
สำหรับชุดข้อมูลที่มีขนาดใหญ่มากโซลูชันนี้อาจช้าลงเนื่องจากการfind_in_setดำเนินการไม่ใช่วิธีที่ดีที่สุดในการค้นหาตัวเลขในรายการแน่นอนไม่อยู่ในรายการที่มีขนาดเท่ากับลำดับความสำคัญเท่ากับจำนวนระเบียนที่ส่งคืน
ทางเลือกที่ 1: with recursive,connect by
ฐานข้อมูลมากขึ้นใช้SQL มาตรฐาน ISO WITH [RECURSIVE]ไวยากรณ์สำหรับการสอบถามซ้ำ (เช่นPostgres 8.4+ , SQL Server 2005+ , DB2 , Oracle 11gR2 + , SQLite 3.8.4+ , Firebird 2.1+ , H2 , HyperSQL 2.1.0+ , Teradata , MariaDB 10.2.2+ ) และในเวอร์ชั่น 8.0 นั้น MySQL ก็รองรับเช่นกัน ดูด้านบนของคำตอบนี้สำหรับไวยากรณ์ที่จะใช้
ฐานข้อมูลบางตัวมีไวยากรณ์ที่เป็นทางเลือกและไม่ใช่มาตรฐานสำหรับการค้นหาแบบลำดับชั้นเช่นส่วนCONNECT BYคำสั่งที่มีอยู่ในOracle , DB2 , Informix , CUBRIDและฐานข้อมูลอื่น ๆ
MySQL เวอร์ชั่น 5.7 ไม่มีคุณสมบัติดังกล่าว เมื่อเอ็นจิ้นฐานข้อมูลของคุณมีไวยากรณ์นี้หรือคุณสามารถโยกย้ายไปยังที่ทำอยู่นั่นเป็นทางเลือกที่ดีที่สุด ถ้าไม่เช่นนั้นให้พิจารณาทางเลือกต่อไปนี้
ทางเลือก 2: ตัวระบุลักษณะเส้นทาง
สิ่งต่าง ๆ จะกลายเป็นเรื่องง่ายขึ้นถ้าคุณจะกำหนดidค่าที่มีข้อมูลลำดับชั้น: พา ธ ตัวอย่างเช่นในกรณีของคุณสิ่งนี้อาจมีลักษณะเช่นนี้:
ID | NAME
19 | category1
19/1 | category2
19/1/1 | category3
19/1/1/1 | category4
จากนั้นคุณselectจะมีลักษณะเช่นนี้:
select id,
name
from products
where id like '19/%'
ทางเลือก 3: การรวมตัวเองซ้ำแล้วซ้ำอีก
หากคุณรู้ว่าขีด จำกัด สูงสุดของต้นไม้ลำดับชั้นของคุณลึกแค่ไหนคุณสามารถใช้sqlแบบสอบถามมาตรฐานเช่นนี้:
select p6.parent_id as parent6_id,
p5.parent_id as parent5_id,
p4.parent_id as parent4_id,
p3.parent_id as parent3_id,
p2.parent_id as parent2_id,
p1.parent_id as parent_id,
p1.id as product_id,
p1.name
from products p1
left join products p2 on p2.id = p1.parent_id
left join products p3 on p3.id = p2.parent_id
left join products p4 on p4.id = p3.parent_id
left join products p5 on p5.id = p4.parent_id
left join products p6 on p6.id = p5.parent_id
where 19 in (p1.parent_id,
p2.parent_id,
p3.parent_id,
p4.parent_id,
p5.parent_id,
p6.parent_id)
order by 1, 2, 3, 4, 5, 6, 7;
ดูซอนี้
whereสภาพระบุซึ่งผู้ปกครองคุณต้องการที่จะดึงลูกหลานของ คุณสามารถขยายแบบสอบถามนี้ด้วยระดับที่มากขึ้นตามต้องการ