Biasanya, ada tiga jenis kueri dalam hierarki yang menyebabkan masalah:
- Kembalikan semua leluhur
- Kembalikan semua keturunan
- Kembalikan semua anak (keturunan langsung).
Berikut adalah tabel kecil yang menunjukkan kinerja berbagai metode di MySQL
:
Ancestors Descendants Children Maintainability InnoDB
Adjacency list Good Decent Excellent Easy Yes
Nested sets (classic) Poor Excellent Poor/Excellent Very hard Yes
Nested sets (spatial) Excellent Very good Poor/Excellent Very hard No
Materialized path Excellent Very good Poor/Excellent Hard Yes
Di children
, poor/excellent
berarti jawabannya tergantung pada apakah Anda mencampur metode dengan daftar adjacency, i. e. menyimpan parentID
di setiap catatan.
Untuk tugas Anda, Anda memerlukan ketiga kueri:
- Semua leluhur untuk menunjukkan hal Bumi / Inggris / Devon
- Semua anak untuk menunjukkan "Tujuan di Eropa" (item)
- Semua turunan untuk menampilkan "Tujuan di Eropa" (hitungan)
Saya akan memilih jalan yang terwujud, karena hierarki semacam ini jarang berubah (hanya dalam kasus perang, pemberontakan, dll).
Buat kolom varchar bernama path
, indeks dan isi dengan nilai seperti ini:
1:234:6345:45454:
di mana angka-angka tersebut adalah kunci utama dari orang tua yang sesuai, dalam urutan yang benar (1
untuk Eropa, 234
untuk Inggris, dll.)
Anda juga memerlukan tabel bernama levels
untuk menjaga nomor dari 1
ke 20
(atau level sarang maksimum apa pun yang Anda inginkan).
Untuk memilih semua leluhur:
SELECT pa.*
FROM places p
JOIN levels l
ON SUBSTRING_INDEX(p.path, ':', l.level) <> p.path
JOIN places pa
ON pa.path = CONCAT(SUBSTRING_INDEX(p.path, ':', l.level), ':')
WHERE p.id = @id_of_place_in_devon
Untuk memilih semua anak dan jumlah tempat di dalamnya:
SELECT pc.*, COUNT(pp.id)
FROM places p
JOIN places pc
ON pc.parentId = p.id
JOIN places pp
ON pp.path BETWEEN pc.path AND CONCAT(pc.path, ':')
AND pp.id NOT IN
(
SELECT parentId
FROM places
)
WHERE p.id = @id_of_europe
GROUP BY
pc.id