MySQL一对多到JSON格式

时间:2019-01-26 18:32:01

标签: python mysql sql python-3.x

我有两个MySQL表:

User (id, name)
Sale (id, user, item)

Sale(user)User(id)的外键,因此这是一对多关系(一个用户可以进行很多销售)。

我正在尝试从数据库中获取此信息,并以JSON格式返回给多个用户,所以它看起来像这样:

[
  {
    "id": 1,
    "name": "User 1",
    "sales": [
      {
        "id": 1,
        "item": "t-shirt"
      },
      {
        "id": 2,
        "item": "jeans"
      }
    ]
  },
  {
    "id": 2,
    "name": "User 2",
    "sales": [
      {
        "id": 3,
        "item": "sweatpants"
      },
      {
        "id": 4,
        "item": "gloves"
      }
    ]
  }
]

“销售”实体嵌套在其相应“用户”的实体中。

问题是,从数据库中查询并将其转换为JSON的最佳方法是什么?我可以对所有用户运行查询,然后遍历每个用户并运行查询以获取其销售量,但这很慢。或者,我可以在用户和销售人员之间进行外部联接,然后将其解析为JSON格式的代码,但这会从数据库发送多余的信息(包括每笔销售的整套用户数据集),并需要在其中进行遍历码。有方便的方法吗?顺便说一下,我正在使用Python 3.7。

1 个答案:

答案 0 :(得分:3)

这是一个可能满足您要求的SQL查询。它使用MySQL JSON_ARRAYAGG() aggregate function生成JSON对象数组(使用JSON_OBJECT()创建)。

在联接内执行中间级别的分组,以生成每个用户的sales JSON数组。然后将结果汇总到一行中,其中一列包含结果的JSON对象数组。

SELECT
  JSON_ARRAYAGG(JSON_OBJECT('id', u.id, 'name', u.name, 'sales', s.sales))
FROM
    user u
    LEFT JOIN (
        SELECT 
            user, 
            JSON_ARRAYAGG(JSON_OBJECT('id', id, 'item', item)) sales 
        FROM sale 
        GROUP BY user
    ) s ON s.user = u.id

Demo on DB Fiddle

如果用JSON_PRETTY包装返回值,则输出如下:

[
  {
    "id": 1,
    "name": "User 1",
    "sales": [
      {
        "id": 1,
        "item": "t-shirt"
      },
      {
        "id": 2,
        "item": "jeans"
      }
    ]
  },
  {
    "id": 2,
    "name": "User 2",
    "sales": [
      {
        "id": 3,
        "item": "sweatpants"
      },
      {
        "id": 4,
        "item": "gloves"
      }
    ]
  }
]

编辑:这是MySQL <5.7的(难看)解决方案,其中不提供JSON支持。它仅依赖于字符串操作函数。请注意,这仅在varchar字段不包含"字符的情况下有效:

SELECT
    CONCAT(
        '[', 
        GROUP_CONCAT( CONCAT( '{ "id":', u.id, ', "name":"', u.name, '", "sales":', s.sales, ' }' )  SEPARATOR ', ' ),
        ']'
    )
FROM 
    user u
    LEFT JOIN (
        SELECT 
            user, 
            CONCAT( 
               '[', 
                GROUP_CONCAT( CONCAT( '{ "id":', id, ', "item":"', item, '" }' ) SEPARATOR ', '),
                ']'
            ) sales 
    FROM sale
    GROUP BY user ) s ON s.user = u.id

Demo on DB Fiddle