Mysql
 sql >> Teknologi Basis Data >  >> RDS >> Mysql

Cetak data hierarkis dalam bentuk anak induk dari daftar tidak berurutan php?

OK bekerja dari backend menuju front-end...

Anda dapat memanggil satu prosedur tersimpan non rekursif (sproc) dari skrip php Anda yang menghasilkan hierarki pesan untuk Anda. Keuntungan dari pendekatan ini adalah Anda hanya perlu membuat TUNGGAL panggilan dari php ke database Anda sedangkan jika Anda menggunakan SQL sebaris maka Anda akan melakukan panggilan sebanyak mungkin level (minimal). Keuntungan lain adalah karena ini adalah sproc non rekursif, ia sangat berkinerja dan juga menjaga kode php Anda tetap bagus dan bersih. Akhirnya, dan saya harus mengatakan ini sebagai catatan, bahwa memanggil prosedur tersimpan lebih aman dan lebih efisien daripada metode lain karena Anda hanya perlu MEMBERIKAN izin eksekusi kepada pengguna aplikasi Anda dan prosedur tersimpan memerlukan lebih sedikit perjalanan pulang pergi ke database daripada metode lain termasuk kueri berparameter yang memerlukan setidaknya 2 panggilan untuk satu kueri (1 untuk menyiapkan template kueri di db, yang lain untuk mengisi params)

Jadi, inilah cara Anda memanggil prosedur tersimpan dari baris perintah MySQL.

call message_hier(1);

dan inilah hasil yang dibuatnya.

msg_id  emp_msg    parent_msg_id    parent_msg   depth
======  =======    =============    ==========   =====
1        msg 1            NULL          NULL          0
2        msg 1-1             1          msg 1         1
3        msg 1-2             1          msg 1         1
4        msg 1-2-1           3          msg 1-2       2
5        msg 1-2-2           3          msg 1-2       2
6        msg 1-2-2-1         5          msg 1-2-2     3
7        msg 1-2-2-1-1       6          msg 1-2-2-1   4
8        msg 1-2-2-1-2       6          msg 1-2-2-1   4

Oke, jadi sekarang kami memiliki kemampuan untuk mengambil pohon pesan penuh atau sebagian hanya dengan memanggil sproc kami dengan simpul awal apa pun yang kami butuhkan, tetapi apa yang akan kami lakukan dengan kumpulan hasil ??

Nah dalam contoh ini saya telah memutuskan kita akan membuat XML DOM dengannya, maka yang perlu saya lakukan adalah mengubah (XSLT) XML dan kita akan memiliki halaman web pesan bersarang.

skrip PHP

Skrip php cukup sederhana, hanya terhubung ke database, memanggil sproc dan mengulang hasil untuk membangun XML DOM. Ingat kita hanya menelepon ke db sekali.

<?php

// i am using the resultset to build an XML DOM but you can do whatever you like with it !

header("Content-type: text/xml");

$conn = new mysqli("localhost", "foo_dbo", "pass", "foo_db", 3306);

// one non-recursive db call to get the message tree !

$result = $conn->query(sprintf("call message_hier(%d)", 1));

$xml = new DomDocument;
$xpath = new DOMXpath($xml);

$msgs = $xml->createElement("messages");
$xml->appendChild($msgs);

// loop and build the DOM

while($row = $result->fetch_assoc()){

    $msg = $xml->createElement("message");
    foreach($row as $col => $val) $msg->setAttribute($col, $val); 

    if(is_null($row["parent_msg_id"])){
        $msgs->appendChild($msg);
    }
    else{
        $qry = sprintf("//*[@msg_id = '%d']", $row["parent_msg_id"]);
        $parent = $xpath->query($qry)->item(0);
        if(!is_null($parent)) $parent->appendChild($msg);
    }
}
$result->close();
$conn->close();

echo $xml->saveXML();
?>

keluaran XML

Ini adalah XML yang dihasilkan skrip php. Jika Anda menyimpan XML ini dalam file dan membukanya di browser, Anda akan dapat memperluas dan menciutkan level.

<messages>
    <message msg_id="1" emp_msg="msg 1" parent_msg_id="" parent_msg="" depth="0">
        <message msg_id="2" emp_msg="msg 1-1" parent_msg_id="1" parent_msg="msg 1" depth="1"/>
        <message msg_id="3" emp_msg="msg 1-2" parent_msg_id="1" parent_msg="msg 1" depth="1">
            <message msg_id="4" emp_msg="msg 1-2-1" parent_msg_id="3" parent_msg="msg 1-2" depth="2"/>
            <message msg_id="5" emp_msg="msg 1-2-2" parent_msg_id="3" parent_msg="msg 1-2" depth="2">
                <message msg_id="6" emp_msg="msg 1-2-2-1" parent_msg_id="5" parent_msg="msg 1-2-2" depth="3">
                    <message msg_id="7" emp_msg="msg 1-2-2-1-1" parent_msg_id="6" parent_msg="msg 1-2-2-1" depth="4"/>
                    <message msg_id="8" emp_msg="msg 1-2-2-1-2" parent_msg_id="6" parent_msg="msg 1-2-2-1" depth="4"/>
                </message>
            </message>
        </message>
    </message>
</messages>

Sekarang Anda dapat meninggalkan pembuatan XML DOM dan menggunakan XSL untuk merender halaman web jika Anda menginginkannya dan mungkin hanya mengulang kumpulan hasil dan merender pesan secara langsung. Saya hanya memilih metode ini untuk membuat contoh saya selengkap dan seinformatif mungkin.

skrip MySQL

Ini adalah skrip lengkap termasuk tabel, sprocs, dan data pengujian.

drop table if exists messages;
create table messages
(
msg_id smallint unsigned not null auto_increment primary key,
msg varchar(255) not null,
parent_msg_id smallint unsigned null,
key (parent_msg_id)
)
engine = innodb;

insert into messages (msg, parent_msg_id) values
('msg 1',null), 
  ('msg 1-1',1), 
  ('msg 1-2',1), 
      ('msg 1-2-1',3), 
      ('msg 1-2-2',3), 
         ('msg 1-2-2-1',5), 
            ('msg 1-2-2-1-1',6), 
            ('msg 1-2-2-1-2',6);


drop procedure if exists message_hier;

delimiter #

create procedure message_hier
(
in p_msg_id smallint unsigned
)
begin

declare v_done tinyint unsigned default(0);
declare v_dpth smallint unsigned default(0);

create temporary table hier(
 parent_msg_id smallint unsigned, 
 msg_id smallint unsigned, 
 depth smallint unsigned
)engine = memory;

insert into hier select parent_msg_id, msg_id, v_dpth from messages where msg_id = p_msg_id;

/* http://dev.mysql.com/doc/refman/5.0/en/temporary-table-problems.html */

create temporary table tmp engine=memory select * from hier;

while not v_done do

    if exists( select 1 from messages e inner join hier on e.parent_msg_id = hier.msg_id and hier.depth = v_dpth) then

        insert into hier select e.parent_msg_id, e.msg_id, v_dpth + 1 
            from messages e inner join tmp on e.parent_msg_id = tmp.msg_id and tmp.depth = v_dpth;

        set v_dpth = v_dpth + 1;            

        truncate table tmp;
        insert into tmp select * from hier where depth = v_dpth;

    else
        set v_done = 1;
    end if;

end while;

select 
 m.msg_id,
 m.msg as emp_msg,
 p.msg_id as parent_msg_id,
 p.msg as parent_msg,
 hier.depth
from 
 hier
inner join messages m on hier.msg_id = m.msg_id
left outer join messages p on hier.parent_msg_id = p.msg_id;

drop temporary table if exists hier;
drop temporary table if exists tmp;

end #

delimiter ;

-- call this sproc from your php

call message_hier(1);

Sumber lengkap untuk jawaban ini dapat ditemukan di sini:http://pastie.org/1336407 . Seperti yang telah Anda ketahui, saya telah menghilangkan XSLT tetapi Anda mungkin tidak akan menggunakan rute XML dan jika Anda melakukannya, ada banyak contoh di web.

Semoga bermanfaat :)

EDIT:

Menambahkan sedikit lebih banyak data sehingga Anda memiliki lebih dari satu pesan root (msg_ids 1,9,14).

truncate table messages;

insert into messages (msg, parent_msg_id) values
('msg 1',null), -- msg_id = 1
  ('msg 1-1',1), 
  ('msg 1-2',1), 
      ('msg 1-2-1',3), 
      ('msg 1-2-2',3), 
         ('msg 1-2-2-1',5), 
            ('msg 1-2-2-1-1',6), 
            ('msg 1-2-2-1-2',6),
('msg 2',null), -- msg_id = 9
    ('msg 2-1',9), 
    ('msg 2-2',9), 
    ('msg 2-3',9), 
        ('msg 2-3-1',12),
('msg 3',null); -- msg_id = 14

Sekarang jika Anda hanya ingin mendapatkan pesan yang khusus untuk node root (pesan awal), Anda dapat memanggil prosedur tersimpan asli dengan meneruskan msg_id awal dari root yang Anda butuhkan. Menggunakan data baru di atas yaitu msg_ids 1,9,14.

call message_hier(1); -- returns all messages belonging to msg_id = 1

call message_hier(9); -- returns all messages belonging to msg_id = 9

call message_hier(14); -- returns all messages belonging to msg_id = 14

Anda dapat mengirimkan msg_id apa pun yang Anda suka, jadi jika saya ingin semua pesan di bawah ini, msg 1-2-2-1, Anda dapat memasukkan msg_id =6:

call message_hier(6); -- returns all messages belonging to msg_id = 6

Namun, jika Anda ingin semua pesan untuk semua root, Anda dapat memanggil sproc baru yang saya buat sebagai berikut:

call message_hier_all(); -- returns all messages for all roots.

Masalah utama dengan ini adalah ketika tabel pesan Anda tumbuh, itu akan mengembalikan banyak data, itulah sebabnya saya berfokus pada sproc yang lebih spesifik yang hanya mengambil pesan untuk node root tertentu atau memulai msg_id.

Saya tidak akan memposting kode sproc baru karena hampir sama dengan aslinya tetapi Anda dapat menemukan semua amandemennya di sini :http://pastie.org/1339618

Perubahan terakhir yang harus Anda lakukan adalah pada skrip php yang sekarang akan memanggil sproc baru sebagai berikut:

//$result = $conn->query(sprintf("call message_hier(%d)", 1)); // recommended call

$result = $conn->query("call message_hier_all()"); // new sproc call

Semoga membantu :)

call message_hier_all();


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. pekerjaan untuk menghapus baris yang lebih lama dari 3 bulan di database mysql

  2. Papan peringkat mySQL cepat dengan peringkat pemain (&pemain di sekitarnya)

  3. PostgreSQL vs MySQL, sebuah perbandingan

  4. membuat koneksi di Eclipse - ClassNotFoundException:com.mysql.jdbc.Driver

  5. Oracle Database Link - Setara dengan MySQL?