สำหรับ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
สภาพระบุซึ่งผู้ปกครองคุณต้องการที่จะดึงลูกหลานของ คุณสามารถขยายแบบสอบถามนี้ด้วยระดับที่มากขึ้นตามต้องการ