Diri rekursif bergabung

15

Saya punya commentstabel, yang bisa disederhanakan menjadi ini:

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

di mana parent_idnullable, tetapi mungkin menjadi kunci untuk komentar orang tuanya.


Sekarang, bagaimana saya bisa selectsemua keturunan dari komentar tertentu?
Komentar mungkin turun beberapa tingkat ...

Josh
sumber

Jawaban:

16

Kueri hierarki , seperti kueri rekursif yang diketahui, tidak didukung untuk MySQL.

Namun mereka didukung di Oracle, Microsoft SQL Server, DB2, dan PostgreSQL, antara lain.

Jika Anda memerlukan solusi, Anda dapat menemukan trik dinamis (dan karenanya, berpotensi berbahaya) di sini: /programming/8104187/mysql-hierarchical-queries

Anda juga dapat menemukan diskusi tentang cara menyimpan data hierarkis dengan model lain selain dengan Daftar Adjacency (yaitu kolom Induk ) di sini: /programming/192220/what-is-the-most-efisien- elegan-cara-untuk mengurai-meja-datar-ke-pohon-/

Semoga berhasil!

Valmoer
sumber
Saya ingin tahu bagaimana solusi di tautan kedua Anda bisa berbahaya. Bisakah Anda menjelaskannya? Kalau tidak, selamat datang di situs ini!
dezso
3
@dezso: Quoth sendiri perajin kueri, Quassnoi " * Ini bukan pemutakhiran yang aman * karena MySQL tidak secara jelas mendefinisikan perilaku variabel sesi. Namun, itu satu-satunya cara untuk menangani daftar kedekatan secara tepat waktu dalam in-query ." Berbahaya mungkin kata yang terlalu kuat ( berpotensi tidak stabil ?) Tapi saya lebih suka berbuat salah di sisi kehati-hatian (ditambah, saya lebih berpengetahuan di Oracle daripada MySQL, jadi saya ingin lebih berhati-hati). Ngomong-ngomong, selamat datang! Saya telah lama menjadi lurker ke jaringan SE, dan saya memutuskan sudah waktunya untuk membayar kembali sedikit.
Valmoer
2
Sintaks WITH [RECURSIVE] sekarang didukung dari mysql 8.0. dev.mysql.com/doc/refman/8.0/id/with.html
ClearCrescendo
6

Desain tabel ini adalah antipattern SQL "Naive trees" seperti yang dijelaskan oleh Bill Karwin (menatap dari slide 48 dalam presentasi SQL Antipatterns Strike Back ). Masalah dengan desain ini secara khusus adalah kesulitan untuk mendapatkan semua keturunan (atau orang tua) dari suatu simpul. Karena Anda menggunakan MySQL, Anda tidak dapat menggunakan ekspresi tabel umum (pernyataan WITH dan itu adalah pengubah RECURSIVE) yang ada di RDBMSes lain.

Yang tersisa adalah:

  • gunakan implementasi alternatif dari struktur data hierarkis (jawaban untuk pertanyaan ini mungkin menjadi referensi yang bagus untuk ini)
  • membangun kueri gabung sendiri dengan batas kedalaman. Untuk kedalaman = 5 Anda dapat menggunakan sesuatu di baris:

    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)
  • gunakan RDBMS yang mendukung WITH RECURSIVE (walaupun ini kemungkinan besar bukan pilihan bagi kebanyakan orang)

redguy
sumber
2
Saya tidak setuju dengan Bill Karwin di sini. Model adjacency bukan anti-pola. Dengan DBMS modern yang mendukung permintaan rekursif (Oracle telah mendukung ini selama lebih dari 20 tahun) model seperti itu sangat efisien untuk mengambil dan memperbarui.
a_horse_with_no_name
5

MySQL tidak mendukung permintaan rekursif seperti yang Anda butuhkan.

Apa yang saya lakukan beberapa waktu lalu adalah menulis Stored Procedures yang menyediakan model untuk melakukannya.

Daripada menemukan kembali roda, saya akan memberi Anda tautan ke pos lama saya tentang ini:

Singkatnya, Stored Procedures yang saya buat melakukan preorder tree traversal menggunakan pemrosesan antrian

  • GetParentIDByID
  • GetAncestry
  • GetFamilyTree

Induk Semua Anak (seperti Prosedur Tersimpan GetFamilyTree)

  • LANGKAH01) Mulailah dengan parent_idantrian
  • LANGKAH02) Dequeue yang berikutnya parent_idsebagai arus
  • STEP03) Enqueue semua idnilai yang ada saat iniparent_id
  • LANGKAH04) Cetak atau Kumpulkan Komentar
  • LANGKAH05) Jika antrian tidak kosong, goto STEP02
  • LANGKAH06) Anda selesai !!!

Child to all Parent (seperti Prosedur yang Disimpan GetAncestry)

  • LANGKAH01) Mulailah dengan idantrian
  • LANGKAH02) Dequeue yang berikutnya idsebagai arus
  • LANGKAH03) Enqueue parent_idnilai arusid
  • LANGKAH04) Cetak atau Kumpulkan Komentar
  • LANGKAH05) Jika antrian tidak kosong, goto STEP02
  • LANGKAH06) Anda selesai !!!

Silakan lihat Prosedur Tersimpan di posting saya yang lain untuk melihat implementasinya.

Cobalah !!!

RolandoMySQLDBA
sumber
2
SELECT  group_concat(@id :=
        (
        SELECT  id
        FROM    comments
        WHERE   parent_id = @id
        )) AS comment
FROM    (
        SELECT  @id := 1
        ) vars
STRAIGHT_JOIN
        comments
WHERE   @id IS NOT NULL

biola

Praveen Prasannan
sumber