Mysql SQL查询以将实体的子实体与父实体放在同一行中
我有一个包含以下字段的表:Mysql SQL查询以将实体的子实体与父实体放在同一行中,mysql,sql,Mysql,Sql,我有一个包含以下字段的表: | entity_id | parent_entity_id | name | status | |----------------------------------------------| 我正在尝试编写一个查询,其中显示每个没有父实体的实体,并内联显示其子实体的名称和状态,结果如下: | entity_id | name | child_entity_1_name | child_entity_1_status |...| child_entity_4_na
| entity_id | parent_entity_id | name | status |
|----------------------------------------------|
我正在尝试编写一个查询,其中显示每个没有父实体的实体,并内联显示其子实体的名称和状态,结果如下:
| entity_id | name | child_entity_1_name | child_entity_1_status |...| child_entity_4_name | child_entity_4_status |
--------------------------------------------------------------------------------------------------------------------
我知道数据是结构化的,因此每个实体至少有3个子实体,但不是每个实体都有4个子实体(因此,有3个子实体的第4个子实体名称和状态列中有NULL)。此外,我知道没有一个拥有父实体的实体本身就是父实体
从我所学的介绍性数据库类来看,这似乎是一个复杂的查询。让我大吃一惊的是把所有的子实体放在同一行。我可以在与其父实体相同的行中获取一个子实体,但不能获取多个子实体
编辑:数据库基本上是一组树,每个树的高度为2。没有祖父母
PARENT_ENT_1 PARENT_ENT_2
| | | | | | | |
| | | | | | | |
C1 C2 C3 C4 C5 C6 C7 C8
我的结果查询中的每一行都应该表示这些树中的一个这有点凌乱,可能有更好的存储方法,特别是因为它只能手动伸缩 假设一张桌子:
CREATE TABLE
parents
(
entity_id INT PRIMARY KEY AUTO_INCREMENT,
parent_entity_id INT,
name VARCHAR(15),
`status` VARCHAR(15)
);
已编辑
使用一些示例数据:
INSERT INTO
`parents`
(entity_id, parent_entity_id, name, `status`)
VALUES
(1, NULL, 'Parent1', 'sfsd'),
(2, 1, 'Child1A', 'sfsd'),
(3, 1, 'Child1B', 'sfsd'),
(4, 1, 'Child1C', 'sfsd'),
(5, NULL, 'Parent2', 'sfsd'),
(6, 5, 'Child2A', 'sfsd'),
(7, 5, 'Child2B', 'sfsd');
您可以创建存储以下内容的视图、临时表或永久表(取决于最终目标):
SET @row_number = 0;
SET @parent_id = 0;
SELECT
@row_number:=CASE
WHEN @parent_id = parent_entity_id THEN @row_number + 1
ELSE 1
END AS `child_num`,
entity_id,
@parent_id:= parent_entity_id as parent_entity_id,
name,
`status`
FROM
`parents`
WHERE
`parent_entity_id` IS NOT NULL
ORDER BY
parent_entity_id ASC,
entity_id ASC;
使用SQL Server并使用按分区
和行编号
可以更轻松地完成上述操作,但这是一种解决方法
给了我们:
然后,您可以连接该表/视图3次,为子编号添加第二个join
条件。这是在这里演示的,由于SQL中的限制,它使用了一个派生表来修改数据,我认为这可以全部完成3次,不过您必须研究效率和基准测试
最终,它给了我们:
这有点混乱,可能有更好的存储方法,特别是因为它只能手动扩展 假设一张桌子:
CREATE TABLE
parents
(
entity_id INT PRIMARY KEY AUTO_INCREMENT,
parent_entity_id INT,
name VARCHAR(15),
`status` VARCHAR(15)
);
已编辑
使用一些示例数据:
INSERT INTO
`parents`
(entity_id, parent_entity_id, name, `status`)
VALUES
(1, NULL, 'Parent1', 'sfsd'),
(2, 1, 'Child1A', 'sfsd'),
(3, 1, 'Child1B', 'sfsd'),
(4, 1, 'Child1C', 'sfsd'),
(5, NULL, 'Parent2', 'sfsd'),
(6, 5, 'Child2A', 'sfsd'),
(7, 5, 'Child2B', 'sfsd');
您可以创建存储以下内容的视图、临时表或永久表(取决于最终目标):
SET @row_number = 0;
SET @parent_id = 0;
SELECT
@row_number:=CASE
WHEN @parent_id = parent_entity_id THEN @row_number + 1
ELSE 1
END AS `child_num`,
entity_id,
@parent_id:= parent_entity_id as parent_entity_id,
name,
`status`
FROM
`parents`
WHERE
`parent_entity_id` IS NOT NULL
ORDER BY
parent_entity_id ASC,
entity_id ASC;
使用SQL Server并使用按分区
和行编号
可以更轻松地完成上述操作,但这是一种解决方法
给了我们:
然后,您可以连接该表/视图3次,为子编号添加第二个join
条件。这是在这里演示的,由于SQL中的限制,它使用了一个派生表来修改数据,我认为这可以全部完成3次,不过您必须研究效率和基准测试
最终,它给了我们:
SET@cNum:=0;
设置@prevParent:=0;
选择p.id、p.Name
,GROUP_CONCAT(如果(numberedChildren.childNum=1,c.Name,NULL))作为子实体_1_名称
,组CONCAT(如果(numberedChildren.childNum=1,c.Status,NULL))作为子实体
,GROUP_CONCAT(如果(numberedChildren.childNum=2,c.Name,NULL))作为子实体_2_名称
,将组_CONCAT(IF(numberedChildren.childNum=2,c.Status,NULL))作为子实体_2_Status
, ...
从(
选择@cNum:=IF(@prevParent orderedChildren.parent_id,@cNum+1,1)作为childNum
,orderedChildren.id作为子项id
,@prevParent:=orderedChildren.parent\u id作为parent\u id
从(
选择父项\u id,id
从某处
按父项下单\u id,id
)孩子们
)作为无数的孩子
在numberedChildren.parent\u id=p.id上以p的形式内部连接sometable
在numberedChildren.child\u id=c.id上以c的形式内部连接sometable
按p.id、p.Name分组
;
我认为这个脚本可能有用。它依赖于GROUP\u CONCAT
,以及几乎所有其他聚合函数,忽略空值
您也可以通过更改此行将其设置为单个查询(删除初始集合语句):
)作为orderedChildren
到
)作为orderedChildren,(选择@cNum作为cnInit,@prevParent作为ppInit)作为init
但对于会话变量init,这不是我通常的风格
编辑:此外,有序子查询可能不需要是子查询(您可以在同一子查询中进行ORDER BY和childNum计算),但这样使用会话变量可能会非常微妙。SET@cNum:=0;
设置@prevParent:=0;
选择p.id、p.Name
,GROUP_CONCAT(如果(numberedChildren.childNum=1,c.Name,NULL))作为子实体_1_名称
,组CONCAT(如果(numberedChildren.childNum=1,c.Status,NULL))作为子实体
,GROUP_CONCAT(如果(numberedChildren.childNum=2,c.Name,NULL))作为子实体_2_名称
,将组_CONCAT(IF(numberedChildren.childNum=2,c.Status,NULL))作为子实体_2_Status
, ...
从(
选择@cNum:=IF(@prevParent orderedChildren.parent_id,@cNum+1,1)作为childNum
,orderedChildren.id作为子项id
,@prevParent:=orderedChildren.parent\u id作为parent\u id
从(
选择父项\u id,id
从某处
按父项下单\u id,id
)孩子们
)作为无数的孩子
在numberedChildren.parent\u id=p.id上以p的形式内部连接sometable
在numberedChildren.child\u id=c.id上以c的形式内部连接sometable
按p.id、p.Name分组
;
我认为这个脚本可能有用。它依赖于GROUP\u CONCAT
,以及几乎所有其他聚合函数,忽略空值
您也可以通过更改此行将其设置为单个查询(删除初始集合语句):
)作为orderedChildren
到
)作为orderedChildren,(选择@cNum作为cnInit,@prevParent作为ppInit)作为init
但对于会话变量init,这不是我通常的风格
编辑:此外,有序子查询可能不需要是子查询(您可以在同一子查询中执行ORDER BY和childNum计算),但这样使用会话变量可能会非常微妙。
select
p.entity_id, p.name,
c1.name as child_entity_1_name,
c1.status as child_entity_1_status,
c2.name as child_entity_2_name,
c2.status as child_entity_2_status
from entities p
left join entities c1 on c1.entity_id = (
select c.entity_id
from entities c
where c.parent_entity_id = p.entity_id
order by c.entity_id asc
limit 1
offset 0
)
left join entities c2 on c2.entity_id = (
select c.entity_id
from entities c
where c.parent_entity_id = p.entity_id
order by c.entity_id asc
limit 1
offset 1
)
where p.parent_entity_id is null
select p.entity_id, p.name
from entities p
where p.parent_entity_id is null;
select p.entity_id as parent_id, c.name, c.status
from entities p
join entities c on c.parent_entity_id = p.entity_id
where p.parent_entity_id is null
order by p.entity_id, c.entity_id;