如何使用 SQL 查询使用 parent 后跟 child 来订购 table 记录
How to Order table records with parent followed by child using SQL Query
我有一个 table,很少有记录有 parent 记录,如下所示。并非所有人都有 parent 条记录。
id | parent_id
--------------
1 | 0
2 | 0
3 | 1
4 | 0
5 | 0
6 | 0
7 | 5
我希望记录按 parent 后跟 child:
排序
id | parent_id
--------------
1 | 0
3 | 1
2 | 0
4 | 0
5 | 0
7 | 5
6 | 0
如何在不使用存储过程的情况下使用 SQL 查询实现此目的?
我正在使用 postgres。
您需要一个 recursive query 携带所有级别的根 ID,然后您可以按此对行进行排序:
with recursive entries as (
select id, parent_id, id as root_id, 1 as level
from the_table
where parent_id = 0 -- this should be IS NULL
union all
select c.id, c.parent_id, p.root_id, p.level + 1
from the_table c
join entries p on p.id = c.parent_id
)
select id, parent_id
from entries
order by root_id, level, id;
我想你想要:
order by coalesce(nullif(parent_id, 0), id), id
基本上,忽略 parent_id
中的零。然后使用 parent_id
(如果存在),否则使用 id
.
Here 是一个 db<>fiddle.
此版本假定父 ID 小于子 ID -- 这在您的数据中是正确的,并且在大多数情况下都有意义。如果您想明确说明顺序:
order by coalesce(nullif(parent_id, 0), id),
(parent_id = 0) desc,
id
假设正如您的示例所暗示的那样,只有一层可能的层次结构:
SELECT child.*
FROM tbl AS child
LEFT JOIN tbl AS parent ON parent.id = child.parent_id
ORDER BY COALESCE(parent.id, child.id) -- order by parent if exists
, parent.id IS NOT NULL -- parent first per group
, child.id; -- order rest by id
仅当我们按 "name" 等其他属性排序时才需要连接(这是典型情况,因为代理 ID 的值没有意义)。虽然只像您展示的那样按 ID 排序,但我们不需要连接,因为所有信息都已经存在(就像 Gordon 展示的那样)。然后我们可以简化:
SELECT *
FROM tbl
ORDER BY CASE WHEN parent_id = 0 THEN id ELSE parent_id END
, parent_id <> 0
, id;
- 需要第 2 个
ORDER BY
项目才能在其 children 之前排序 parent。之所以有效,是因为 FALSE
在 TRUE
之前排序。看:
- Sorting null values after all others, except special
- 只有在可以有多个 children 时才需要最后一个
ORDER BY
项。
db<>fiddle here - 使用扩展测试用例来证明 ORDER BY
项的相关性。
我使用这种方式(Postgres):
SELECT id, parent_id, name
FROM my_table
ORDER BY
COALESCE(parent_id,id)||id::varchar
我有一个 table,很少有记录有 parent 记录,如下所示。并非所有人都有 parent 条记录。
id | parent_id
--------------
1 | 0
2 | 0
3 | 1
4 | 0
5 | 0
6 | 0
7 | 5
我希望记录按 parent 后跟 child:
排序id | parent_id
--------------
1 | 0
3 | 1
2 | 0
4 | 0
5 | 0
7 | 5
6 | 0
如何在不使用存储过程的情况下使用 SQL 查询实现此目的?
我正在使用 postgres。
您需要一个 recursive query 携带所有级别的根 ID,然后您可以按此对行进行排序:
with recursive entries as (
select id, parent_id, id as root_id, 1 as level
from the_table
where parent_id = 0 -- this should be IS NULL
union all
select c.id, c.parent_id, p.root_id, p.level + 1
from the_table c
join entries p on p.id = c.parent_id
)
select id, parent_id
from entries
order by root_id, level, id;
我想你想要:
order by coalesce(nullif(parent_id, 0), id), id
基本上,忽略 parent_id
中的零。然后使用 parent_id
(如果存在),否则使用 id
.
Here 是一个 db<>fiddle.
此版本假定父 ID 小于子 ID -- 这在您的数据中是正确的,并且在大多数情况下都有意义。如果您想明确说明顺序:
order by coalesce(nullif(parent_id, 0), id),
(parent_id = 0) desc,
id
假设正如您的示例所暗示的那样,只有一层可能的层次结构:
SELECT child.*
FROM tbl AS child
LEFT JOIN tbl AS parent ON parent.id = child.parent_id
ORDER BY COALESCE(parent.id, child.id) -- order by parent if exists
, parent.id IS NOT NULL -- parent first per group
, child.id; -- order rest by id
仅当我们按 "name" 等其他属性排序时才需要连接(这是典型情况,因为代理 ID 的值没有意义)。虽然只像您展示的那样按 ID 排序,但我们不需要连接,因为所有信息都已经存在(就像 Gordon 展示的那样)。然后我们可以简化:
SELECT *
FROM tbl
ORDER BY CASE WHEN parent_id = 0 THEN id ELSE parent_id END
, parent_id <> 0
, id;
- 需要第 2 个
ORDER BY
项目才能在其 children 之前排序 parent。之所以有效,是因为FALSE
在TRUE
之前排序。看:- Sorting null values after all others, except special
- 只有在可以有多个 children 时才需要最后一个
ORDER BY
项。
db<>fiddle here - 使用扩展测试用例来证明 ORDER BY
项的相关性。
我使用这种方式(Postgres):
SELECT id, parent_id, name
FROM my_table
ORDER BY
COALESCE(parent_id,id)||id::varchar