如何使用 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;

在线示例:https://rextester.com/YKUJ56922

我想你想要:

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。之所以有效,是因为 FALSETRUE 之前排序。看:
    • 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