简体   繁体   English

使用连接从单个查询中获取嵌套数组

[英]Getting a nested array from a single query with join

I have the common situation, but I can't find a common solution...我有共同的情况,但我找不到共同的解决方案......

Imagine I have two tables like authors and corresponding books:想象一下,我有两个表,比如作者和相应的书籍:

Authors作者

+----+-----------+
| id | name      |
+----+-----------+
|  1 | O.Connor  |
|  2 | F.Myler   |
+----+-----------+

Books图书

+----+-----------+-----------+----------------+
| id | author_id | title     | number_of_pages|
+----+-----------+-----------+----------------+
|  1 | 1         |Book 1     |315             |
|  2 | 1         |Book 2     |265             |
+----+-----------+-----------+----------------+

I want to get the data from database in one sql query (I use mySQL but it doesn't matter, I would like to have a database independent solution) with JOIN like:我想在一个 sql 查询中从数据库中获取数据(我使用 mySQL 但没关系,我想要一个独立于数据库的解决方案),例如:

SELECT A.*, B.title as book_title, B.number_of_pages as book_pages FROM authors A LEFT JOIN books B ON B.author_id=A.id

I would like to avoid multiple queries in a loop because of productivity issues on big databases.由于大型数据库的生产力问题,我想避免循环中的多个查询。 And then I need to nest the data from the second table as a subarray to avoid having multiple copy of the same data.然后我需要将第二个表中的数据嵌套为子数组,以避免拥有相同数据的多个副本。 In other words I need to transform a flat result from database to a nested multidimensional array.换句话说,我需要将平面结果从数据库转换为嵌套的多维数组。 It should give something like:它应该给出如下内容:

[
    {
        "id": 3,
        "name": "O.Connor",
        "birth_date": "05.06.1985",
        "from": "England",
        "mother": "",
        "father": "",
        "email": "email@example.com",
        "books": [
            {
                "title": "Some Title",
                "pages": 235
            },
            {
                "title": "Some Title",
                "pages": 267
            },
            {
                "title": "Some Title",
                "pages": 317
            },
            {
                "title": "Some Title",
                "pages": 235
            },
            {
                "title": "Some Title",
                "pages": 298
            }
        ]
    },
    {
        "id": 28,
        "name": "O.Henri",
        "birth_date": "05.06.1300",
        "from": "England",
        "mother": "",
        "father": "",
        "email": "email@example.com",
        "books": [
            {
                "title": "Some Title",
                "pages": 235
            },
            {
                "title": "Some Title",
                "pages": 267
            },
            {
                "title": "Some Title",
                "pages": 317
            },
            {
                "title": "Some Title",
                "pages": 235
            },
            {
                "title": "Some Title",
                "pages": 298
            }
        ]
    }
]

The only related resources I've found so far are:到目前为止,我发现的唯一相关资源是:

SQL query with join to get nested array of objects SQL 查询与连接以获取对象的嵌套数组

https://phpdelusions.net/pdo_examples/nested_array https://phpdelusions.net/pdo_examples/nested_array

The first one uses either multiple queries or some SQL Server functionality that is not available in MySQL.第一个使用多个查询或一些 SQL 服务器功能,这些功能在 MySQL 中不可用。 The second one proposes to fetch each row from the result separately and construct the resulting array on-the-go.第二个建议分别从结果中获取每一行,并在旅途中构造结果数组。 Maybe it's not a bad solution, but maybe there are better ones, more productive.也许这不是一个糟糕的解决方案,但也许有更好的解决方案,更有效率。

There are some fetch modes in PDO, like FETCH_GROUP etc. But nothing is enough for my task. PDO 中有一些获取模式,例如 FETCH_GROUP 等。但对于我的任务来说,这还不够。

I wrote my own function with an idea to create further some DB class and insert this function as a method (so it should be really universal for most cases).我编写了自己的 function 并想进一步创建一些 DB class 并将此 function 作为一种方法插入(因此对于大多数情况它应该是通用的)。

function group_by($array, $criterias=NULL, $group_name='group') {
    if ($criterias == NULL) return $array; // add also a verification of type
    // transform input parameters for array_diff_key()
    $criterias = array_flip($criterias);
    $group = array($group_name=>0);

    $result_array = [];
    $push_index = 0;
    foreach ($array as $row) {
        $sup_array = array_diff_key($row, $criterias);
        $sub_array = array_intersect_key($row, $criterias);
        // add verification of not NULL elements in future
        $isInArray = false;

        foreach ($result_array as $index => $grouped_array) {
            // if there is no difference between arrays then this sub-array is already present in a result array.
            $array_without_groups = array_diff_key($grouped_array, $group);
            if ( empty(array_diff_assoc($array_without_groups, $sup_array)) && (count($array_without_groups)==count($sup_array)) ) {
                $isInArray = true;
                $push_index = $index;
                break;
            }
        }
        if ($isInArray) {
            array_push($result_array[$push_index][$group_name], $sub_array);
        } else {
            $sup_array[$group_name] = array();
            array_push($sup_array[$group_name], $sub_array);
            array_push($result_array, $sup_array);
        }
    }

    return $result_array;
}

And then you call this on the fetchAll result as:然后在 fetchAll 结果上调用它:

$result = group_by($result, array('book_title', 'book_pages'), 'books');

I don't think it's the best solution.我不认为这是最好的解决方案。 I am a noobie to PHP, so I'm not even sure if array_diff and array_intersect that I use are the efficient way to extract one array from another.我是 PHP 的菜鸟,所以我什至不确定我使用的 array_diff 和 array_intersect 是否是从另一个数组中提取一个数组的有效方法。 I would be thankful for any advice.我会很感激任何建议。

Here's a solution that works in MySQL 5.7 or later.这是适用于 MySQL 5.7 或更高版本的解决方案。

SELECT A.id, A.name, A.birth_date, A.`from`, A.mother, A.father, A.email, 
  JSON_ARRAYAGG(JSON_OBJECT('title', B.title, 'pages', B.number_of_pages)) AS books
FROM authors A LEFT JOIN books B ON B.author_id=A.id
GROUP BY A.id;

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM