Mysql
 sql >> Baza danych >  >> RDS >> Mysql

Tworzysz hierarchiczny JSON z wyników MySQL i PHP dla drzewa D3.js?

To nie wygląda na przyzwoity projekt dla danych hierarchicznych. Rozważ inne podejście, takie jak lista sąsiedztwa .

Rozwiązanie nr 1 — obsługa MySQL 8 JSON:

W MySQL 8 możesz użyć JSON_ARRAYAGG() i JSON_OBJECT() aby uzyskać wynik JSON tylko z 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

Wynik:

{"name": "Bob", "children": [{"name": "Ted", "children": [{"name": "Fred"}]}, {"name": "Carol", "children": [{"name": "Harry"}]}, {"name": "Alice", "children": [{"name": "Mary"}]}]}

demonstracja db-fiddle

Sformatowany:

{
    "name": "Bob",
    "children": [
        {
            "name": "Ted",
            "children": [
                {
                    "name": "Fred"
                }
            ]
        },
        {
            "name": "Carol",
            "children": [
                {
                    "name": "Harry"
                }
            ]
        },
        {
            "name": "Alice",
            "children": [
                {
                    "name": "Mary"
                }
            ]
        }
    ]
}

Rozwiązanie nr 2 — konstruowanie JSON za pomocą GROUP_CONCAT():

Jeśli nazwy nie zawierają znaków cudzysłowu, możesz ręcznie skonstruować ciąg JSON w starszych wersjach za pomocą 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;

Wynik byłby taki sam (patrz demo )

Rozwiązanie nr 3 — Konstruowanie struktury zagnieżdżenia z obiektami PHP:

Możesz także napisać prostsze zapytanie SQL i skonstruować zagnieżdżoną strukturę w 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
");

Wynik to

name    | parent
----------------
Bob     | null
Ted     | Bob
Carol   | Bob
Alice   | Bob
Fred    | Ted
Harry   | Carol
Mary    | Alice

demo

Uwaga:nazwa powinna być unikalna we wszystkich tabelach. Ale nie wiem, jakiego rezultatu można by się spodziewać, gdyby duplikaty były możliwe.

Teraz zapisz wiersze jako obiekty w tablicy o nazwie zindeksowanej:

$data = []
while ($row = $result->fetch_object()) {
    $data[$row->name] = $row;
}

$data będzie teraz zawierać

[
    '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'],
]

Możemy teraz połączyć węzły w jednej pętli:

$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);

Wynik:

{
    "name": "Bob",
    "children": [
        {
            "name": "Ted",
            "children": [
                {
                    "name": "Fred"
                }
            ]
        },
        {
            "name": "Carol",
            "children": [
                {
                    "name": "Harry"
                }
            ]
        },
        {
            "name": "Alice",
            "children": [
                {
                    "name": "Mary"
                }
            ]
        }
    ]
}

demo

Jeśli możliwych jest wiele węzłów głównych (wiele wierszy w level_1_name ), a następnie użyj

json_encode($roots);


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Grupuj według Union mysql select query

  2. MySQL:Uzyskaj n-tą najwyższą wartość dla każdej grupy w tabeli

  3. ponowne użycie aliasu w SELECT

  4. Czy możesz pomóc zmodyfikować zapytanie lub inne zapytanie, aby uzyskać oczekiwany wynik?

  5. Wordpress SQL:pobierz kategorię postów i tagi