繁体   English   中英

我将如何加入MySQL中的两个表(多对一)并获得特定的JSON output(如下图)

[英]How would I join two tables in MySQL (many to one) and get a specific JSON output (as shown below)

我将如何加入MySQL中的两个表(多对一)并获得特定的JSON output(如下图)

注意:请不要将其标记为重复

之前发布的一个问题与此非常相似,但在几点上并不相同。

不是我要找的,这个问题与此不同: Mysql concat 和 group_concat

我在这篇文章的底部放了一个更长的描述和更多的细节,为什么应该将其标记为重复,以及它有何不同。


要求:

  1. 返回 JSON
  2. 使用:JSON_OBJECT & JSON_ARRAYAGG(不要使用 CONCAT 或 GROUP_CONCAT)
  3. 仅连接两个表(通过主键/外键 | 行标识符) | 多对一关系
  4. 显示在 output 中,来自父表的字段(不仅仅是 id 外键引用
  5. 在输出 JSON 中,我需要控制每个元素或结构的名称,它对应一个表名,但是 JSON 程式化会有所不同,并且还要控制每个字段的名称(JSON 程式化名称会与数据库字段名)

output JSON 将是一个数组(teams),数组(struct)的每个元素都将包含一个数组(persons)。

顶级数组属于父表“teams”(JSON 数组的每个元素包含单行数据),嵌套数组属于子表“persons”,它与父表具有多对一关系。


如果一个简单的 select 仅从一张表完成: select * from <child_table>;

我得到了父表的 id(主键),但是在 JSON 结果中,除了父主键,我还想显示父表的另一个字段(父表中的字段值,而不仅仅是行 id / 键,这对 JSON 输出没有帮助)。


此处提供: .sql 文件以创建数据库、架构、插入数据(以测试解决方案)

create schema if not exists test;

use test;
create table if not exists team
(
    id          int unsigned auto_increment primary key,
    team_name   varchar(30) unique not null,
    description text
);

use test;
create table if not exists person
(
    id          int unsigned auto_increment primary key,
    id_team     int unsigned not null,
    person_name varchar(40)  not null,
    notes       varchar(40)  not null,
    constraint team_person unique (id, id_team),
    foreign key (id_team) references team (id)
);

-- insert teams (2)
use test;
insert into team(team_name)
values ('team1');

insert into team(team_name)
values ('team2');

insert into team(team_name)
values ('team3');

-- insert persons (x2 per team = 4)
use test;
insert into person(id_team, person_name)
values ((select id from team where team_name = 'team1'),
        'john');

insert into person(id_team, person_name)
values ((select id from team where team_name = 'team1'),
        'tom');

insert into person(id_team, person_name)
values ((select id from team where team_name = 'team1'),
        'marie');

-- team 2
insert into person(id_team, person_name)
values ((select id from team where team_name = 'team2'),
        'scott');

insert into person(id_team, person_name)
values ((select id from team where team_name = 'team2'),
        'mark');

我需要 output JSON 看起来像这样(完全展开 - 两个 arrays 具有来自两个表的值):

您在这里看到的是一组团队,“团队”表中每行一个 JSON 元素。

在每个元素中,一组人,每行一个 JSON 元素,来自“人”表,代表多对一关系。

{
  "team_persons": [
    {
      "team": "team1",
      "id_team": 1,
      "persons": [
        {
          "id_person": 1,
          "personaName": "john"
        },
        {
          "id_person": 2,
          "personaName": "allison"
        }
      ]
    },
    {
      "team": "team2",
      "id_team": 2,
      "persons": [
        {
          "id_person": 3,
          "personaName": "katrina"
        },
        {
          "id_person": 4,
          "personaName": "scott"
        }
      ]
    }
  ]
}

output中可以看到,JSON output中的每条记录中都显示了父表字段: id_team & team_name

JSON中有两个arrays:

  1. 包含团队列表或集合(父表)的顶级(结构)数组
  2. 在每个团队中,都有属于该团队的人员列表或集合

我知道SELECT JSON_OBJECT / JSON_ARRAYAGG会涉及。 我不确定如何在两个表的 SQL 连接中同时使用两者,以实现所需的自定义 JSON output。

SQL 中的两个表的连接如下所示:

select t.id id_team, p.id id_person, p.person_name, t.team_name
from team t,
     person p
where t.id = p.id_team;

谢谢你!


请不要将其标记为重复,它不是:

我只处理两个表,其中 JSON output 需要从一个非常顶级的数组开始(与其他帖子不同)。

{
  "team_persons": [

引用的帖子和方法存在问题:

  1. 参考帖子中的示例没有提供有关表和关系的足够详细信息,而且这是一个实际问题,没有分解为最简单的基本要素
  2. 最初的方法尝试使用CONCAT / GRUOP_CONCAT ,我想避免使用

有一种更好、更现代的方法可以使用其他内置 MySQL 函数来执行此操作。

请不要关闭这个问题。 要求非常不同。

我需要一种使用的方法: JSON_OBJECT / JSON_ARRAYAGG and NOT CONCAT and NOT GROUP_CONCAT 并且也仅在两个非常简单的表上。

问问题时,如果试图解决的最简单(不准确)的事情能帮助其他人 map 他们的问题就成了问题。 在下面的问题中,我去除了所有复杂性以提供一个简单示例。

我希望提供一个更容易理解的问题,其他人可能会从中受益(使用复制表结构的代码),以及一个更精致的答案,因为我相信给出的答案对于更简单的用例来说可以变得更简单,并且更容易理解。

SELECT 
  JSON_PRETTY(
    JSON_OBJECT(
      'team_persons', JSON_ARRAYAGG(
        JSON_OBJECT(
          'team', team,
          'id_team', id_team,
          'persons', persons
        )
      )
    )
  ) AS _result
FROM (
  SELECT 
    t.id AS id_team,
    t.team_name AS team,
    JSON_ARRAYAGG(
      JSON_OBJECT(
        'id_person', p.id, 
        'personName', p.person_name
      )
    ) AS persons
  FROM team t JOIN person p ON t.id = p.id_team
  GROUP BY id_team
) AS p;

在 MySQL 8.0.28 上测试过,但它也应该适用于 MySQL 5.7.22(或更高版本)。


包括空队是棘手的。 一开始只能使用 LEFT OUTER JOIN,但随后它会抱怨,除非我将 GROUP BY 更改为引用基列,而不是别名:

  ...
  FROM team t LEFT OUTER JOIN person p ON t.id = p.id_team
  GROUP BY t.id

但是,这可能不会产生您想要的结果,我假设它是一个空的 JSON 数组。 因为外部联接的结果确实有一行,但是带有 NULL,所以您会得到一个带有 NULL 的假团队成员:

{
  "team": "team3",
  "id_team": 3,
  "persons": [
    {
      "id_person": null,
      "personName": null
    }
  ]
}

一种解决方法是将当前查询与 JOIN 与另一个排除连接查询联合起来:

SELECT
  JSON_PRETTY(
    JSON_OBJECT(
      'team_persons', JSON_ARRAYAGG(
        JSON_OBJECT(
          'team', team,
          'id_team', id_team,
          'persons', persons
        )
      )
    )
  ) AS _result
FROM (
  SELECT 
    t.id AS id_team,
    t.team_name AS team,
    JSON_ARRAYAGG(
      JSON_OBJECT(
        'id_person', p.id,
        'personName', p.person_name
      )
    ) AS persons
  FROM team t JOIN person p ON t.id = p.id_team
  GROUP BY t.id
  UNION
  SELECT 
    t.id,
    t.team_name,
    JSON_ARRAY()
  FROM team t LEFT OUTER JOIN person p ON t.id = p.id_team
  WHERE p.id_team IS NULL
) AS p;

UNION 的后半部分返回一个文字空数组,因为反正团队中没有人。

暂无
暂无

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

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