Mysql
 sql >> база данни >  >> RDS >> Mysql

Създаване на йерархичен JSON от MySQL резултати и PHP за дърво D3.js?

Това не изглежда като приличен дизайн за йерархични данни. Помислете за друг подход като списък на съседство .

Решение №1 – Поддръжка на MySQL 8 JSON:

С MySQL 8 можете да използвате JSON_ARRAYAGG() и JSON_OBJECT() за да получите JSON резултата само с 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

Резултатът е:

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

db-fiddle демонстрация

Форматиран:

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

Решение №2 – Създаване на JSON с GROUP_CONCAT():

Ако имената не съдържат символи за цитати, можете ръчно да конструирате JSON низа в по-стари версии, като използвате 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;

Резултатът ще бъде същият (вижте демото )

Решение №3 – Конструиране на структура на nestet с PHP обекти:

Можете също да напишете по-проста SQL заявка и да конструирате вложената структура в 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
");

Резултатът е

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

демонстрация

Забележка:Името трябва да е уникално във всички таблици. Но не знам какъв резултат бихте очаквали, ако бяха възможни дубликати.

Сега запазете редовете като обекти в масив, индексиран с името:

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

$data сега ще съдържа

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

Вече можем да свържем възлите в един цикъл:

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

Резултатът:

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

демонстрация

Ако са възможни множество основни възли (множество реда в level_1_name ), след което използвайте

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. Въведение в MySQL типовете данни

  2. MySql.Data.MySqlClient.Replication.ReplicationManager хвърля System.TypeInitializationException

  3. Не може да се получи достъп до MySql root потребител, дори след задаване на паролата през безопасен режим в терминала на Linux

  4. Как да напиша REST API?

  5. Как да дефинирате уникално ограничение за колона от MySQL таблица в Ruby on Rails 3?