Untuk MySQL 8+: gunakan with
rekursif
sintaks.
Untuk MySQL 5.x: gunakan variabel sebaris, ID jalur, atau self-join.
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;
Nilai yang ditentukan dalam parent_id = 19
harus disetel ke id
dari induk yang ingin Anda pilih semua keturunannya.
MySQL 5.x
Untuk versi MySQL yang tidak mendukung Ekspresi Tabel Umum (hingga versi 5.7), Anda dapat melakukannya dengan kueri berikut:
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))
Ini adalah biola .
Di sini, nilai yang ditentukan dalam @pv := '19'
harus disetel ke id
dari induk yang ingin Anda pilih semua keturunannya.
Ini akan berfungsi juga jika orang tua memiliki banyak anak-anak. Namun, setiap record harus memenuhi kondisi parent_id < id
, jika tidak, hasilnya tidak akan lengkap.
Penetapan variabel di dalam kueri
Kueri ini menggunakan sintaks MySQL khusus:variabel ditetapkan dan dimodifikasi selama eksekusi. Beberapa asumsi dibuat tentang urutan eksekusi:
from
klausa dievaluasi terlebih dahulu. Jadi di situlah@pv
akan diinisialisasi.where
klausa dievaluasi untuk setiap record dalam urutan pengambilan darifrom
alias. Jadi, di sinilah suatu kondisi dimasukkan untuk hanya menyertakan catatan yang induknya telah diidentifikasi sebagai pohon turunan (semua keturunan dari induk utama secara bertahap ditambahkan ke@pv
).- Kondisi di
where
ini klausa dievaluasi secara berurutan, dan evaluasi dihentikan setelah hasil totalnya pasti. Oleh karena itu kondisi kedua harus di tempat kedua, karena menambahkanid
ke daftar induk, dan ini hanya akan terjadi jikaid
melewati syarat pertama.length
fungsi hanya dipanggil untuk memastikan kondisi ini selalu benar, bahkan jikapv
string karena alasan tertentu akan menghasilkan nilai palsu.
Secara keseluruhan, orang mungkin menganggap asumsi ini terlalu berisiko untuk diandalkan. Dokumentasi memperingatkan:
Anda mungkin mendapatkan hasil yang Anda harapkan, tetapi ini tidak dijamin [...] urutan evaluasi untuk ekspresi yang melibatkan variabel pengguna tidak ditentukan.
Jadi meskipun bekerja secara konsisten dengan kueri di atas, urutan evaluasi mungkin masih berubah, misalnya saat Anda menambahkan kondisi atau menggunakan kueri ini sebagai tampilan atau subkueri dalam kueri yang lebih besar. Ini adalah "fitur" yang akan dihapus di masa mendatang Rilis MySQL :
Rilis MySQL sebelumnya memungkinkan untuk menetapkan nilai ke variabel pengguna dalam pernyataan selain
SET
. Fungsionalitas ini didukung di MySQL 8.0 untuk kompatibilitas mundur tetapi dapat dihapus pada rilis MySQL mendatang.
Seperti yang dinyatakan di atas, dari MySQL 8.0 dan seterusnya Anda harus menggunakan with
rekursif sintaks.
Efisiensi
Untuk kumpulan data yang sangat besar, solusi ini mungkin menjadi lambat, karena find_in_set
operasi bukanlah cara yang paling ideal untuk menemukan nomor dalam daftar, tentu saja tidak dalam daftar yang mencapai ukuran dalam urutan besarnya yang sama dengan jumlah catatan yang dikembalikan.
Alternatif 1:with recursive
, connect by
Semakin banyak basis data yang mengimplementasikan SQL:1999 standar ISO WITH [RECURSIVE]
sintaks
untuk kueri rekursif (mis. 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+
). Dan mulai versi 8.0, MySQL juga mendukungnya
. Lihat bagian atas jawaban ini untuk sintaks yang digunakan.
Beberapa database memiliki sintaks alternatif non-standar untuk pencarian hierarkis, seperti CONNECT BY
klausa tersedia di Oracle
, DB2
, Informix , CUBRID
dan basis data lainnya.
MySQL versi 5.7 tidak menawarkan fitur seperti itu. Ketika mesin database Anda menyediakan sintaks ini atau Anda dapat bermigrasi ke salah satu yang menyediakannya, maka itu tentu saja merupakan pilihan terbaik. Jika tidak, pertimbangkan juga alternatif berikut.
Alternatif 2:Pengenal gaya jalur
Segalanya menjadi jauh lebih mudah jika Anda menetapkan id
nilai yang berisi informasi hierarkis:jalur. Misalnya, dalam kasus Anda ini bisa terlihat seperti ini:
ID | NAME |
---|---|
19 | kategori1 |
19/1 | kategori2 |
19/1/1 | kategori3 |
19/1/1/1 | kategori4 |
Kemudian select
akan terlihat seperti ini:
select id,
name
from products
where id like '19/%'
Alternatif 3:Self-join berulang
Jika Anda mengetahui batas atas seberapa dalam hierarki pohon Anda, Anda dapat menggunakan sql
standar pertanyaan seperti ini:
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;
Lihat biola ini
where
condition menentukan induk mana yang ingin Anda ambil turunannya. Anda dapat memperluas kueri ini dengan lebih banyak level sesuai kebutuhan.