带有连接的 SQL 查询以获取嵌套的对象数组

Posted

技术标签:

【中文标题】带有连接的 SQL 查询以获取嵌套的对象数组【英文标题】:SQL query with join to get nested array of objects 【发布时间】:2019-10-13 14:19:05 【问题描述】:

总结:我将从 JSON 模式开始描述预期。请注意具有嵌套对象数组的角色,我正在寻找可以获取单个查询的“智能查询”。


    "id": 1,
    "first": "John",
    "roles": [ // Expectation -> array of objects
        
            "id": 1,
            "name": "admin"
        ,
        
            "id": 2,
            "name": "accounts"
        
    ]

用户

+----+-------+
| id | first |
+----+-------+
|  1 | John  |
|  2 | Jane  |
+----+-------+

角色

+----+----------+
| id |   name   |
+----+----------+
|  1 | admin    |
|  2 | accounts |
|  3 | sales    |
+----+----------+

用户角色

+---------+---------+
| user_id | role_id |
+---------+---------+
|       1 |       1 |
|       1 |       2 |
|       2 |       2 |
|       2 |       3 |
+---------+---------+

尝试01

我会在我的 nodejs 代码中运行两个 sql 查询,在连接字符串中使用 multipleStatements:true 的帮助。 Info.

User.getUser = function(id) 
    const sql = "SELECT id, first FROM user WHERE id = ?; \
        SELECT role_id AS id, role.name from user_role \
        INNER JOIN role ON user_role.role_id = role.id WHERE user_id = ?";

    db.query(sql, [id, id], function(error, result)
        const data = result[0][0]; // first query result
        data.roles = result[1];  // second query result, join in code.
        console.log(data);
    );
;

问题:上面的代码产生了预期的 JSON 模式,但它需要两个查询,由于有多个语句,我能够以尽可能小的代码单元将其缩小,但我没有这样的像 Java 或 C# 等其他语言中的奢侈品,例如,我必须创建两个函数和两个 sql 查询。所以我正在寻找一个单一的查询解决方案。


尝试02

在较早的尝试中,在 SO 社区的帮助下,我能够使用单个查询接近以下内容,但它只能帮助生成字符串数组(而不是对象数组)。

User.getUser = function(id) 
    const sql = "SELECT user.id, user.first, GROUP_CONCAT(role.name) AS roles FROM user \
        INNER JOIN user_role ON user.id = user_role.user_id \
        INNER JOIN role ON user_role.role_id = role.id \
        WHERE user.id = ? \
        GROUP BY user.id";
    db.query(sql, id, function (error, result) 
        const data = 
            id: result[0].id, first: result[0].first,
            roles: result[0].roles.split(",") // manual split to create array
        ;
        console.log(data);
    );
;

尝试02结果


    "id": 1,
    "first": "John",
    "roles": [ // array of string
        "admin",
        "accounts"
    ]

生成对象数组是很常见的要求,所以想知道 SQL 中一定有一些我不知道的东西。有没有办法在最佳查询的帮助下更好地实现这一点。

或者让我知道没有这样的解决方案,就是这样,这就是在生产代码中通过两个查询完成的方式。


尝试 03

GROUP_CONCAT(role.id) 中使用role.id 而不是role.name,这样您就可以获取一些id,然后使用另一个子查询来获取关联的角色名称,只是想...

SQL(不起作用,只是为了思考一下)

SELECT 
  user.id,  user.first,  
  GROUP_CONCAT(role.id) AS role_ids, 
  (SELECT id, name FROM role WHERE id IN role_ids) AS roles
FROM user 
INNER JOIN user_role ON user.id = user_role.user_id 
INNER JOIN role ON user_role.role_id = role.id 
WHERE user.id = 1
GROUP BY user.id;

编辑

根据 Amit 的回答,我了解到使用 JSON AUTO 的 SQL Server 中有这样的 solution。是的,这是我在 mysql 中寻找的东西。

准确表达。

当您连接表时,第一个表中的列会生成为 根对象的属性。第二个表中的列是 作为嵌套对象的属性生成。

【问题讨论】:

【参考方案1】:

用户这个加入查询

FOR JSON AUTO 将为您的查询结果返回 JSON

SELECT U.UserID, U.Name, Roles.RoleID, Roles.RoleName  
FROM [dbo].[User] as U 
INNER JOIN [dbo].UserRole as UR ON UR.UserID=U.UserID 
INNER JOIN [dbo].RoleMaster as Roles ON Roles.RoleID=UR.RoleMasterID
FOR JSON AUTO

上述查询的输出是

[
  
    "UserID": 1,
    "Name": "XYZ",
    "Roles": [
      
        "RoleID": 1,
        "RoleName": "Admin"
      
    ]
  ,
  
    "UserID": 2,
    "Name": "PQR",
    "Roles": [
      
        "RoleID": 1,
        "RoleName": "Admin"
      ,
      
        "RoleID": 2,
        "RoleName": "User"
      
    ]
  ,
  
    "UserID": 3,
    "Name": "ABC",
    "Roles": [
      
        "RoleID": 1,
        "RoleName": "Admin"
      
    ]
  
]

【讨论】:

谢谢 Amit,至少我知道 SQL Server 支持它。有趣的是,JSON AUTO 如何将第一个表中的属性作为根对象,将第二个表中的属性作为嵌套对象。我确实需要在那里解决它,但我现在在 mysql 数据库中。 我在其他数据库环境中所做的是获取逗号分隔的连接行列表,然后在代码中拆分以形成嵌套数组。

以上是关于带有连接的 SQL 查询以获取嵌套的对象数组的主要内容,如果未能解决你的问题,请参考以下文章

带有连接的休眠自定义 SQL 查询 - 避免返回数组列表

带有 elemMatch 的 MongoDB 查询,用于从对象内部匹配嵌套数组数据 [重复]

如何将带有对象的数组中的数据动态添加到嵌套数组中?

Mongoose 查询返回带有空数组的嵌套文档

嵌套对象的 Cosmos DB SQL 查询

从嵌套数组对象中查找对象