Mysql
 sql >> Cơ Sở Dữ Liệu >  >> RDS >> Mysql

Tạo JSON phân cấp từ kết quả MySQL và PHP cho cây D3.js?

Đây không phải là một thiết kế phù hợp cho dữ liệu phân cấp. Xem xét một cách tiếp cận khác như danh sách gần kề .

Giải pháp # 1 - Hỗ trợ MySQL 8 JSON:

Với MySQL 8, bạn có thể sử dụng JSON_ARRAYAGG() JSON_OBJECT() để nhận kết quả JSON chỉ với 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

Kết quả là:

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

bản trình diễn db-fiddle

Đã định dạng:

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

Giải pháp # 2 - Tạo JSON với GROUP_CONCAT ():

Nếu tên không chứa bất kỳ bộ đệm trích dẫn nào, bạn có thể tạo chuỗi JSON theo cách thủ công trong các phiên bản cũ hơn bằng cách sử dụng 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;

Kết quả sẽ giống nhau (xem bản trình diễn )

Giải pháp # 3 - Xây dựng cấu trúc nestet với các đối tượng PHP:

Bạn cũng có thể viết một truy vấn SQL đơn giản hơn và xây dựng cấu trúc lồng nhau trong 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
");

Kết quả là

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

bản trình diễn

Lưu ý:Tên phải là duy nhất trên tất cả các bảng. Nhưng tôi không biết bạn sẽ mong đợi kết quả gì, nếu có thể trùng lặp.

Bây giờ, hãy lưu các hàng dưới dạng các đối tượng trong một mảng được lập chỉ mục bằng tên:

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

$data bây giờ sẽ chứa

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

Bây giờ chúng ta có thể liên kết các nút trong một vòng lặp duy nhất:

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

Kết quả:

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

bản trình diễn

Nếu có thể có nhiều nút gốc (nhiều hàng trong level_1_name ), sau đó sử dụng

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. Câu hỏi thiết kế:làm thế nào để hiển thị số lượng người dùng trực tuyến?

  2. Kết xuất tất cả các bảng ở định dạng CSV bằng cách sử dụng 'mysqldump'

  3. MySQL 1292 Giá trị ngày giờ không chính xác

  4. Nhận hàng cuối cùng PER Group

  5. MySQL:sự khác biệt của hai tập kết quả