我将如何加入 MySQL 中的两个表(多对一)并获得特定的 JSON 输出(如下所示)
How would I join two tables in MySQL (many to one) and get a specific JSON output (as shown below)
如何在 MySQL 中连接两个 table(多对一)并获得特定的 JSON 输出(如下所示)
注意:请勿将此标记为重复
之前有一个问题 posted 与此非常相似,但有几点不相同。
这不是我要找的,这个问题和这个不一样:
我在这篇 post 的底部放了一个更长的描述和更多的细节,为什么这应该 不 被标记为重复,以及它有何不同。
要求:
- return JSON
- 使用:JSON_OBJECT & JSON_ARRAYAGG(并且不使用 CONCAT 或 GROUP_CONCAT)
- 仅连接两个 table(通过 primary/foreign 键 | 行标识符)|多对一关系
- 在输出中显示来自 parent table 的字段(不仅仅是 id 外键引用
- 在输出JSON中,我需要控制每个元素或结构的名称,对应一个table名称,但JSON风格化会有所不同,而且控制每个字段的名称(JSON 程式化名称将不同于数据库字段名称)
输出JSON将是一个数组(teams),数组(struct)的每个元素将包含一个数组(persons)。
顶级数组属于 parent table 'teams'(JSON 数组的每个元素包含单行数据),嵌套数组属于child table 'persons' 与 parent.
存在多对一关系
如果一个简单的 select 仅由一个 table 完成:select * from <child_table>;
我得到了 parent table 的 id(主键),但是在 JSON 结果中,连同 parent 主键,我也想要显示 parent 中的另一个字段(parent 中的字段值,而不仅仅是行 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');
我需要输出 JSON 看起来像这样(完全展开 - 两个数组的值都来自 tables):
您在这里看到的是一组团队,'team' table.
中每行一个 JSON 元素
在每个元素中,一组人,每行一个 JSON 元素来自 'person' table 表示多对一关系。
{
"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"
}
]
}
]
}
如您在输出中所见,parent table 字段:id_team & team_name 都显示在 JSON 输出的每条记录中。
JSON中有两个数组:
- 包含列表或集合的顶级(结构)数组
团队 (parent table)
- 在每个团队中,都有一个列表或集合
团队成员
我知道 SELECT JSON_OBJECT / JSON_ARRAYAGG 会涉及。我不确定如何在两个 table 的 SQL 连接中同时使用两者来实现所需的自定义 JSON 输出。
SQL 中两个 table 的连接看起来像这样:
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;
谢谢!
请不要将此标记为重复,它不是:
我只处理两个 table,其中 JSON 输出需要从一个非常顶级的数组开始(与其他 post 不同)。
{
"team_persons": [
引用的 post 和方法存在问题:
- 引用的 post 中的示例没有提供有关 table 和关系的足够详细信息,而且它是一个实际问题,没有分解为最简单的基本要素
- 初始方法尝试使用 CONCAT / GRUOP_CONCAT,我想避免使用
有一种更好、更现代的方法可以使用其他 built-in MySQL 函数。
请不要关闭这个问题。要求差别很大
我需要一种使用方法:JSON_OBJECT / JSON_ARRAYAGG 和 NOT CONCAT 和 不是GROUP_CONCAT。还有两个非常简单的 tables。
问问题时,如果尝试解决的最简单(不准确)的事情可以帮助其他人将他们的问题映射到问题上。在下面的问题中,我去除了所有复杂性以提供一个简单的示例。
我希望提供一个更容易理解的问题,其他人可能会从中受益(使用代码复制 table 结构),以及一个更精确的答案,因为我相信那里给出的答案可以为更简单的用例变得更简单,更容易理解。
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 与另一个 exclusion-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的后半部分returns字面上的空数组,因为反正队伍里没有人。
如何在 MySQL 中连接两个 table(多对一)并获得特定的 JSON 输出(如下所示)
注意:请勿将此标记为重复
之前有一个问题 posted 与此非常相似,但有几点不相同。
这不是我要找的,这个问题和这个不一样:
我在这篇 post 的底部放了一个更长的描述和更多的细节,为什么这应该 不 被标记为重复,以及它有何不同。
要求:
- return JSON
- 使用:JSON_OBJECT & JSON_ARRAYAGG(并且不使用 CONCAT 或 GROUP_CONCAT)
- 仅连接两个 table(通过 primary/foreign 键 | 行标识符)|多对一关系
- 在输出中显示来自 parent table 的字段(不仅仅是 id 外键引用
- 在输出JSON中,我需要控制每个元素或结构的名称,对应一个table名称,但JSON风格化会有所不同,而且控制每个字段的名称(JSON 程式化名称将不同于数据库字段名称)
输出JSON将是一个数组(teams),数组(struct)的每个元素将包含一个数组(persons)。
顶级数组属于 parent table 'teams'(JSON 数组的每个元素包含单行数据),嵌套数组属于child table 'persons' 与 parent.
存在多对一关系如果一个简单的 select 仅由一个 table 完成:select * from <child_table>;
我得到了 parent table 的 id(主键),但是在 JSON 结果中,连同 parent 主键,我也想要显示 parent 中的另一个字段(parent 中的字段值,而不仅仅是行 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');
我需要输出 JSON 看起来像这样(完全展开 - 两个数组的值都来自 tables):
您在这里看到的是一组团队,'team' table.
中每行一个 JSON 元素在每个元素中,一组人,每行一个 JSON 元素来自 'person' table 表示多对一关系。
{
"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"
}
]
}
]
}
如您在输出中所见,parent table 字段:id_team & team_name 都显示在 JSON 输出的每条记录中。
JSON中有两个数组:
- 包含列表或集合的顶级(结构)数组 团队 (parent table)
- 在每个团队中,都有一个列表或集合 团队成员
我知道 SELECT JSON_OBJECT / JSON_ARRAYAGG 会涉及。我不确定如何在两个 table 的 SQL 连接中同时使用两者来实现所需的自定义 JSON 输出。
SQL 中两个 table 的连接看起来像这样:
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;
谢谢!
请不要将此标记为重复,它不是:
我只处理两个 table,其中 JSON 输出需要从一个非常顶级的数组开始(与其他 post 不同)。
{
"team_persons": [
引用的 post 和方法存在问题:
- 引用的 post 中的示例没有提供有关 table 和关系的足够详细信息,而且它是一个实际问题,没有分解为最简单的基本要素
- 初始方法尝试使用 CONCAT / GRUOP_CONCAT,我想避免使用
有一种更好、更现代的方法可以使用其他 built-in MySQL 函数。
请不要关闭这个问题。要求差别很大
我需要一种使用方法:JSON_OBJECT / JSON_ARRAYAGG 和 NOT CONCAT 和 不是GROUP_CONCAT。还有两个非常简单的 tables。
问问题时,如果尝试解决的最简单(不准确)的事情可以帮助其他人将他们的问题映射到问题上。在下面的问题中,我去除了所有复杂性以提供一个简单的示例。
我希望提供一个更容易理解的问题,其他人可能会从中受益(使用代码复制 table 结构),以及一个更精确的答案,因为我相信那里给出的答案可以为更简单的用例变得更简单,更容易理解。
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 与另一个 exclusion-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的后半部分returns字面上的空数组,因为反正队伍里没有人。