Rumah  >  Soal Jawab  >  teks badan

Buat pertanyaan MySQL rekursif untuk data hierarki

Saya mempunyai jadual MySQL seperti yang ditunjukkan di bawah:

id Nama id_ibu bapa
19 Kategori 1 0
20 Kategori 2 19
21 Kategori 3 20
22 Kategori 4 21
... ... ...

Sekarang, saya mahukan pertanyaan MySQL di mana saya hanya menyediakan id [cth. id=19] dan kemudian saya harus mendapatkan semua sub-idnya [iaitu hasilnya harus mempunyai id '20,21,22']....

Hierarki kanak-kanak tidak diketahui; ia mungkin berbeza-beza...

Saya tahu cara melakukan ini menggunakan gelung for...tetapi bagaimana saya boleh mencapai perkara yang sama menggunakan satu pertanyaan MySQL?

P粉092778585P粉092778585396 hari yang lalu545

membalas semua(1)saya akan balas

  • P粉662089521

    P粉6620895212023-10-13 16:31:36

    Untuk MySQL 8+: Gunakan sintaks rekursif 使用.
    Untuk MySQL 5.x: Gunakan pembolehubah sebaris, ID laluan atau sambung sendiri.

    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

    Untuk versi MySQL (sehingga versi 5.7) yang tidak menyokong ungkapan jadual biasa, anda boleh menggunakan pertanyaan berikut untuk mencapai ini:

    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 fiddle.

    Di sini, @pv := '19' 中指定的值应设置为您要选择其所有后代的父级的 id.

    Ini juga akan berfungsi jika ibu bapa mempunyai ramai anak. Tetapi setiap rekod diperlukan untuk memenuhi syarat parent_id < id, jika tidak, hasilnya akan menjadi tidak lengkap.

    Tugasan boleh ubah dalam pertanyaan

    Pertanyaan ini menggunakan sintaks MySQL khusus: pembolehubah diperuntukkan dan diubah suai semasa pelaksanaan. Membuat beberapa andaian tentang susunan pelaksanaan:

    • Menilai dahulu di mana from 子句。这就是 @pv dimulakan.
    • Ikuti daripada from 别名检索的顺序对每条记录评估 where 子句。因此,这里设置的条件仅包括父级已被识别为位于后代树中的记录(主要父级的所有后代都将逐步添加到 @pv).
    • Rentetan where 子句中的条件按顺序求值,一旦总结果确定,求值就会中断。因此,第二个条件必须位于第二位,因为它将 id 添加到父列表中,并且只有在 id 通过第一个条件时才会发生这种情况。调用 length 函数只是为了确保此条件始终为真,即使 pv ini menghasilkan nilai palsu atas sebab tertentu.

    Secara keseluruhan, seseorang mungkin mendapati andaian ini terlalu berisiko untuk dipercayai. DokumentasiAmaran:

    Jadi, walaupun ia konsisten dengan pertanyaan di atas, susunan penilaian mungkin masih berubah, contohnya apabila anda menambah syarat atau menggunakan pertanyaan ini sebagai paparan atau subquery dalam pertanyaan yang lebih besar. Ini ialah "ciri" yang akan dialih keluar dalam versi MySQL masa hadapan :

    Seperti yang dinyatakan di atas, bermula dengan MySQL 8.0, anda harus menggunakan sintaks with rekursif.

    kecekapan

    Untuk set data yang sangat besar, penyelesaian ini mungkin lambat kerana operasi find_in_set bukanlah cara yang paling ideal untuk mencari nombor dalam senarai, dan pastinya bukan untuk memadankan bilangan rekod yang dikembalikan.

    Alternatif 1:使用递归连接

    Semakin banyak pangkalan data melaksanakan SQL:1999 standard ISO WITH [RECURSIVE]递归查询的 sintaks (cth. Postgres 8.4+ , SQL Server 2005+, DB2 , QLite 3.8.4+, Firebird 2.1 +, H2, HyperSQL 2.1.0+, Teradata, MariaDB 10.2.2+). Bermula dengan versi 8.0, MySQL juga menyokongnya. Lihat bahagian atas jawapan ini untuk digunakan sintaks.

    Pangkalan data

    some mempunyai sintaks bukan standard alternatif untuk carian hierarki, seperti CUBRID dan pangkalan data lain . MySQL versi 5.7 tidak menyediakan fungsi sedemikian. Apabila enjin pangkalan data anda menyediakan sintaks ini atau anda boleh berhijrah ke enjin pangkalan data yang menyediakan sintaks ini, maka ini sudah pasti pilihan terbaik. Jika tidak, pertimbangkan alternatif berikut. Alternatif 2: Pengecam Gaya Laluan

    Perkara menjadi lebih mudah jika anda memberikan nilai id yang mengandungi maklumat hierarki (laluan). Contohnya, dalam kes anda ini mungkin kelihatan seperti ini:

    ID
    Nama19Kategori 119/1Kategori 219/1Kategori 319/1/1/1Kategori 4

    Kemudian 选择 anda akan kelihatan seperti ini:

    select  id,
            name 
    from    products
    where   id like '19/%'

    Alternatif 3: Ulangi penyertaan diri

    Jika anda mengetahui had atas kedalaman pokok hierarki, anda boleh menggunakan pertanyaan sql standard 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 ini Violin

    where Syarat menentukan keturunan ibu bapa yang ingin anda dapatkan. Anda boleh mengembangkan pertanyaan ini ke lebih banyak tahap mengikut keperluan.

    balas
    0
  • Batalbalas