Ini tidak terlihat seperti desain yang layak untuk data hierarkis. Pertimbangkan pendekatan lain seperti daftar kedekatan .
Solusi #1 - Dukungan MySQL 8 JSON:
Dengan MySQL 8 Anda dapat menggunakan JSON_ARRAYAGG()
dan JSON_OBJECT()
untuk mendapatkan hasil JSON hanya dengan SQL:
select json_object(
'name', l1.level_1_name,
'children', json_arrayagg(json_object('name', l2.level_2_name, 'children', l2.children))
) as json
from level_1 l1
left join (
select l2.level_2_name
, l2.level_1_fk
, json_arrayagg(json_object('name', l3.level_3_name)) as children
from level_2 l2
left join level_3 l3 on l3.level_2_fk = l2.level_2_pk
group by l2.level_2_pk
) l2 on l2.level_1_fk = l1.level_1_pk
group by level_1_pk
Hasilnya adalah:
{"name": "Bob", "children": [{"name": "Ted", "children": [{"name": "Fred"}]}, {"name": "Carol", "children": [{"name": "Harry"}]}, {"name": "Alice", "children": [{"name": "Mary"}]}]}
Diformat:
{
"name": "Bob",
"children": [
{
"name": "Ted",
"children": [
{
"name": "Fred"
}
]
},
{
"name": "Carol",
"children": [
{
"name": "Harry"
}
]
},
{
"name": "Alice",
"children": [
{
"name": "Mary"
}
]
}
]
}
Solusi #2 - Membangun JSON dengan GROUP_CONCAT():
Jika nama tidak mengandung carachter kutipan, Anda dapat membuat string JSON secara manual di versi lama menggunakan GROUP_CONCAT()
:
$query = <<<MySQL
select concat('{',
'"name": ', '"', l1.level_1_name, '", ',
'"children": ', '[', group_concat(
'{',
'"name": ', '"', l2.level_2_name, '", ',
'"children": ', '[', l2.children, ']',
'}'
separator ', '), ']'
'}') as json
from level_1 l1
left join (
select l2.level_2_name
, l2.level_1_fk
, group_concat('{', '"name": ', '"', l3.level_3_name, '"', '}') as children
from level_2 l2
left join level_3 l3 on l3.level_2_fk = l2.level_2_pk
group by l2.level_2_pk
) l2 on l2.level_1_fk = l1.level_1_pk
group by level_1_pk
MySQL;
Hasilnya akan sama (lihat demo )
Solusi #3 - Membangun struktur nestet dengan objek PHP:
Anda juga dapat menulis kueri SQL yang lebih sederhana dan membuat struktur bersarang di PHP:
$result = $connection->query("
select level_1_name as name, null as parent
from level_1
union all
select l2.level_2_name as name, l1.level_1_name as parent
from level_2 l2
join level_1 l1 on l1.level_1_pk = l2.level_1_fk
union all
select l3.level_3_name as name, l2.level_2_name as parent
from level_3 l3
join level_2 l2 on l2.level_2_pk = l3.level_2_fk
");
Hasilnya adalah
name | parent
----------------
Bob | null
Ted | Bob
Carol | Bob
Alice | Bob
Fred | Ted
Harry | Carol
Mary | Alice
Catatan:Nama harus unik di sepanjang semua tabel. Tapi saya tidak tahu apa hasil yang Anda harapkan, jika duplikat mungkin terjadi.
Sekarang simpan baris sebagai objek dalam array yang diindeks dengan nama:
$data = []
while ($row = $result->fetch_object()) {
$data[$row->name] = $row;
}
$data
sekarang akan berisi
[
'Bob' => (object)['name' => 'Bob', 'parent' => NULL],
'Ted' => (object)['name' => 'Ted', 'parent' => 'Bob'],
'Carol' => (object)['name' => 'Carol', 'parent' => 'Bob'],
'Alice' => (object)['name' => 'Alice', 'parent' => 'Bob'],
'Fred' => (object)['name' => 'Fred', 'parent' => 'Ted'],
'Harry' => (object)['name' => 'Harry', 'parent' => 'Carol'],
'Mary' => (object)['name' => 'Mary', 'parent' => 'Alice'],
]
Sekarang kita dapat menautkan node dalam satu loop:
$roots = [];
foreach ($data as $row) {
if ($row->parent === null) {
$roots[] = $row;
} else {
$data[$row->parent]->children[] = $row;
}
unset($row->parent);
}
echo json_encode($roots[0], JSON_PRETTY_PRINT);
Hasilnya:
{
"name": "Bob",
"children": [
{
"name": "Ted",
"children": [
{
"name": "Fred"
}
]
},
{
"name": "Carol",
"children": [
{
"name": "Harry"
}
]
},
{
"name": "Alice",
"children": [
{
"name": "Mary"
}
]
}
]
}
Jika beberapa simpul akar dimungkinkan (beberapa baris di level_1_name
), lalu gunakan
json_encode($roots);