SQL 按 parent 和 child 排序
SQL Order by parent and child
基本上我在这里的查询需要帮助。我想以正确的顺序排列,即 child 必须在 parents 名称下且按 A-Z 顺序排列。但是如果我在 child (Split 1
) 下添加一个 subChild
似乎顺序是错误的。它应该在 Room Rose
之下。
p/s : 子子也可以创建另一个子子
感谢您帮助我正确订购此商品?
SELECT A.venueID
, B.mainVenueID
, A.venueName
FROM tblAdmVenue A
LEFT
JOIN tblAdmVenueLink B
ON A.venueID = B.subVenueID
ORDER
BY COALESCE(B.mainVenueID, A.venueID)
, B.mainVenueID IS NOT NULL
, A.venueID
我想要它 return 像这样的订单。
venueName
--------------
Banquet
Big Room
-Room Daisy
-Room Rose
-Split 1
Hall
-Meeting Room WP
似乎这种递归方法也不起作用
WITH venue_ctg AS (
SELECT A.venueID, A.venueName, B.mainVenueID
FROM tblAdmVenue A LEFT JOIN tblAdmVenueLink B
ON A.venueID = B.subVenueID
WHERE B.mainVenueID IS NULL
UNION ALL
SELECT A.venueID, A.venueName, B.mainVenueID
FROM tblAdmVenue A LEFT JOIN tblAdmVenueLink B
ON A.venueID = B.subVenueID
WHERE B.mainVenueID IS NOT NULL
)
SELECT *
FROM venue_ctg ORDER BY venueName
给出的输出
只使用一个 table,而不是两个。第一个 table 包含所有需要的信息。
然后使用 WHERE mainVenueID IS NULL
行启动 CTE,不需要 JOIN
。
这可能是一个很好的教程:
它的'forest'接近你想要的。
对于您的数据,您可以使用:
要正确显示,您可以使用逗号之类的 SEPARATPR,拆分返回的数据,并检查层次结构
-- schema
CREATE TABLE tblAdmVenue (
venueID VARCHAR(225) NOT NULL,
venueName VARCHAR(225) NOT NULL,
PRIMARY KEY(venueID)
);
CREATE TABLE tblAdmVenueLink (
venueLinkID VARCHAR(225) NOT NULL,
mainVenueID VARCHAR(225) NOT NULL,
subVenueID VARCHAR(225) NOT NULL,
PRIMARY KEY(venueLinkID)
-- FOREIGN KEY (DepartmentId) REFERENCES Departments(Id)
);
-- data
INSERT INTO tblAdmVenue (venueID, venueName)
VALUES ('LA43', 'Big Room'), ('LA44', 'Hall'),
('LA45', 'Room Daisy'), ('LA46', 'Room Rose'),
('LA47', 'Banquet'), ('LA48', 'Split 1'),
('LA49', 'Meeting Room WP');
INSERT INTO tblAdmVenueLink (venueLinkID, mainVenueID, subVenueID)
VALUES ('1', 'LA43', 'LA45'), ('2', 'LA43', 'LA46'),
('3', 'LA46', 'LA48'), ('4', 'LA44', 'LA49');
✓
✓
✓
✓
with recursive cte (subVenueID, mainVenueID,level) as (
select subVenueID,
mainVenueID, 1 as level
from tblAdmVenueLink
union
select p.subVenueID,
cte.mainVenueID,
cte.level+1
from tblAdmVenueLink p
inner join cte
on p.mainVenueID = cte.subVenueID
)
select
CONCAT(GROUP_CONCAT(b.venueName ORDER BY level DESC SEPARATOR '-->') ,'-->',a.venueName)
from cte c
LEFT JOIN tblAdmVenue a ON a.venueID = c.subVenueID
LEFT JOIN tblAdmVenue b ON b.venueID = c.mainVenueID
GROUP BY subVenueID;
| CONCAT(GROUP_CONCAT(b.venueName ORDER BY level DESC SEPARATOR '-->') ,'-->',a.venueName) |
| :----------------------------------------------------------------------------------------- |
| Big Room-->Room Daisy |
| Big Room-->Room Rose |
| Big Room-->Room Rose-->Split 1 |
| Hall-->Meeting Room WP |
db<>fiddle here
我想你有:
- table tblAdmVenue A为会场列表;和
- table tblAdmVenueLink B 是树关系 table for parent-child
关于如何获得正确排序顺序的问题,我认为技巧之一是连接父场地名称。
with q0(venueID, venueName, mainVenueID, venuePath) as (
select
A.venueID,
A.venueName,
null,
A.venueName
from tblAdmVenue A
left join tblAdmVenue B on A.venueID = B.subVenueID
where B.mainVenueID is null
union all
select
A.venueID,
A.venueName,
q0.venueID,
q0.venuePath + char(9) + A.venueName
from q0
inner join tblAdmVenue B on q0.venueID = B.mainVenueID
inner join tblAdmVenue A on A.venueID = B.subVenueID
)
select venueID, venueName, mainVenueID
from q0
order by venuePath
您希望数据按字母顺序和深度优先排序。
一个常见的解决方案是从顶部元素开始遍历结构,并连接到每个项目的路径。然后就可以直接使用路径下单了。
下面是如何在 MySQL 8.0 中使用递归查询
with recursive cte(venueID, venueName, mainVenueID, path, depth) as (
select v.venueID, v.venueName, cast(null as char(100)), venueName, 0
from tblAdmVenue v
where not exists (select 1 from tblAdmVenueLink l where l.subVenueID = v.venueID)
union all
select v.venueID, v.venueName, c.venueID, concat(c.path, '/', v.venueName), c.depth + 1
from cte c
inner join tblAdmVenueLink l on l.mainVenueID = c.venueID
inner join tblAdmVenue v on v.venueID = l.subVenueID
)
select * from cte order by path
递归查询的锚点选择顶部节点(即其 ID 不存在于 link table 的列 subVenueID
中的行)。然后,递归部分遵循关系。
作为奖励,我添加了一个 level
列来表示每个节点的深度,顶部节点从 0 开始。
venueID | venueName | mainVenueID | path | depth
:------ | :-------------- | :---------- | :------------------------- | ----:
LA47 | Banquet | null | Banquet | 0
LA43 | Big Room | null | Big Room | 0
LA45 | Room Daisy | LA43 | Big Room/Room Daisy | 1
LA46 | Room Rose | LA43 | Big Room/Room Rose | 1
LA48 | Split 1 | LA46 | Big Room/Room Rose/Split 1 | 2
LA44 | Hall | null | Hall | 0
LA49 | Meeting Room WP | LA44 | Hall/Meeting Room WP | 1
基本上我在这里的查询需要帮助。我想以正确的顺序排列,即 child 必须在 parents 名称下且按 A-Z 顺序排列。但是如果我在 child (Split 1
) 下添加一个 subChild
似乎顺序是错误的。它应该在 Room Rose
之下。
p/s : 子子也可以创建另一个子子
感谢您帮助我正确订购此商品?
SELECT A.venueID
, B.mainVenueID
, A.venueName
FROM tblAdmVenue A
LEFT
JOIN tblAdmVenueLink B
ON A.venueID = B.subVenueID
ORDER
BY COALESCE(B.mainVenueID, A.venueID)
, B.mainVenueID IS NOT NULL
, A.venueID
我想要它 return 像这样的订单。
venueName
--------------
Banquet
Big Room
-Room Daisy
-Room Rose
-Split 1
Hall
-Meeting Room WP
似乎这种递归方法也不起作用
WITH venue_ctg AS (
SELECT A.venueID, A.venueName, B.mainVenueID
FROM tblAdmVenue A LEFT JOIN tblAdmVenueLink B
ON A.venueID = B.subVenueID
WHERE B.mainVenueID IS NULL
UNION ALL
SELECT A.venueID, A.venueName, B.mainVenueID
FROM tblAdmVenue A LEFT JOIN tblAdmVenueLink B
ON A.venueID = B.subVenueID
WHERE B.mainVenueID IS NOT NULL
)
SELECT *
FROM venue_ctg ORDER BY venueName
给出的输出
只使用一个 table,而不是两个。第一个 table 包含所有需要的信息。
然后使用 WHERE mainVenueID IS NULL
行启动 CTE,不需要 JOIN
。
这可能是一个很好的教程:
它的'forest'接近你想要的。
对于您的数据,您可以使用: 要正确显示,您可以使用逗号之类的 SEPARATPR,拆分返回的数据,并检查层次结构
-- schema CREATE TABLE tblAdmVenue ( venueID VARCHAR(225) NOT NULL, venueName VARCHAR(225) NOT NULL, PRIMARY KEY(venueID) ); CREATE TABLE tblAdmVenueLink ( venueLinkID VARCHAR(225) NOT NULL, mainVenueID VARCHAR(225) NOT NULL, subVenueID VARCHAR(225) NOT NULL, PRIMARY KEY(venueLinkID) -- FOREIGN KEY (DepartmentId) REFERENCES Departments(Id) ); -- data INSERT INTO tblAdmVenue (venueID, venueName) VALUES ('LA43', 'Big Room'), ('LA44', 'Hall'), ('LA45', 'Room Daisy'), ('LA46', 'Room Rose'), ('LA47', 'Banquet'), ('LA48', 'Split 1'), ('LA49', 'Meeting Room WP'); INSERT INTO tblAdmVenueLink (venueLinkID, mainVenueID, subVenueID) VALUES ('1', 'LA43', 'LA45'), ('2', 'LA43', 'LA46'), ('3', 'LA46', 'LA48'), ('4', 'LA44', 'LA49');
✓ ✓ ✓ ✓
with recursive cte (subVenueID, mainVenueID,level) as ( select subVenueID, mainVenueID, 1 as level from tblAdmVenueLink union select p.subVenueID, cte.mainVenueID, cte.level+1 from tblAdmVenueLink p inner join cte on p.mainVenueID = cte.subVenueID ) select CONCAT(GROUP_CONCAT(b.venueName ORDER BY level DESC SEPARATOR '-->') ,'-->',a.venueName) from cte c LEFT JOIN tblAdmVenue a ON a.venueID = c.subVenueID LEFT JOIN tblAdmVenue b ON b.venueID = c.mainVenueID GROUP BY subVenueID;
| CONCAT(GROUP_CONCAT(b.venueName ORDER BY level DESC SEPARATOR '-->') ,'-->',a.venueName) | | :----------------------------------------------------------------------------------------- | | Big Room-->Room Daisy | | Big Room-->Room Rose | | Big Room-->Room Rose-->Split 1 | | Hall-->Meeting Room WP |
db<>fiddle here
我想你有:
- table tblAdmVenue A为会场列表;和
- table tblAdmVenueLink B 是树关系 table for parent-child
关于如何获得正确排序顺序的问题,我认为技巧之一是连接父场地名称。
with q0(venueID, venueName, mainVenueID, venuePath) as (
select
A.venueID,
A.venueName,
null,
A.venueName
from tblAdmVenue A
left join tblAdmVenue B on A.venueID = B.subVenueID
where B.mainVenueID is null
union all
select
A.venueID,
A.venueName,
q0.venueID,
q0.venuePath + char(9) + A.venueName
from q0
inner join tblAdmVenue B on q0.venueID = B.mainVenueID
inner join tblAdmVenue A on A.venueID = B.subVenueID
)
select venueID, venueName, mainVenueID
from q0
order by venuePath
您希望数据按字母顺序和深度优先排序。
一个常见的解决方案是从顶部元素开始遍历结构,并连接到每个项目的路径。然后就可以直接使用路径下单了。
下面是如何在 MySQL 8.0 中使用递归查询
with recursive cte(venueID, venueName, mainVenueID, path, depth) as (
select v.venueID, v.venueName, cast(null as char(100)), venueName, 0
from tblAdmVenue v
where not exists (select 1 from tblAdmVenueLink l where l.subVenueID = v.venueID)
union all
select v.venueID, v.venueName, c.venueID, concat(c.path, '/', v.venueName), c.depth + 1
from cte c
inner join tblAdmVenueLink l on l.mainVenueID = c.venueID
inner join tblAdmVenue v on v.venueID = l.subVenueID
)
select * from cte order by path
递归查询的锚点选择顶部节点(即其 ID 不存在于 link table 的列 subVenueID
中的行)。然后,递归部分遵循关系。
作为奖励,我添加了一个 level
列来表示每个节点的深度,顶部节点从 0 开始。
venueID | venueName | mainVenueID | path | depth :------ | :-------------- | :---------- | :------------------------- | ----: LA47 | Banquet | null | Banquet | 0 LA43 | Big Room | null | Big Room | 0 LA45 | Room Daisy | LA43 | Big Room/Room Daisy | 1 LA46 | Room Rose | LA43 | Big Room/Room Rose | 1 LA48 | Split 1 | LA46 | Big Room/Room Rose/Split 1 | 2 LA44 | Hall | null | Hall | 0 LA49 | Meeting Room WP | LA44 | Hall/Meeting Room WP | 1