Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/postgresql/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何使用SQL查询对表记录进行排序,父记录后跟子记录_Sql_Postgresql_Hierarchical Data - Fatal编程技术网

如何使用SQL查询对表记录进行排序,父记录后跟子记录

如何使用SQL查询对表记录进行排序,父记录后跟子记录,sql,postgresql,hierarchical-data,Sql,Postgresql,Hierarchical Data,我有一个表,其中几乎没有记录有一个父记录,如下所示。并非所有这些文件都有父记录 id | parent_id -------------- 1 | 0 2 | 0 3 | 1 4 | 0 5 | 0 6 | 0 7 | 5 我希望先订购父项,然后订购子项: id | parent_id -------------- 1 | 0 3 | 1 2 | 0 4 | 0 5 | 0 7 | 5 6 | 0 如何在不使用存储过程的情况下使用SQL查询实现这一点 我使用的是

我有一个表,其中几乎没有记录有一个父记录,如下所示。并非所有这些文件都有父记录

id | parent_id
--------------
1 |  0
2 |  0
3 |  1
4 |  0
5 |  0
6 |  0
7 |  5
我希望先订购父项,然后订购子项:

id | parent_id
--------------
1 |  0
3 |  1
2 |  0
4 |  0
5 |  0
7 |  5
6 |  0

如何在不使用存储过程的情况下使用SQL查询实现这一点

我使用的是postgres。

您需要一个在所有级别上都携带根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

他是一把小提琴

此版本假定父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
只有当我们按一些附加属性(如名称)排序时才需要连接,这是典型的情况,因为代理项ID的值没有意义。虽然像您演示的那样只按ID排序,但我们不需要连接,因为所有信息都已经存在,就像Gordon演示的那样。然后我们可以简化:

SELECT *
FROM   tbl
ORDER  BY CASE WHEN parent_id = 0 THEN id ELSE parent_id END
        , parent_id <> 0
        , id;
需要按项排序的第二个顺序将父项排序在其子项之前。因为假在真之前排序。见: 仅当可以有多个子项时,才需要最后一个按项目排序的订单。
dbfiddle-使用扩展测试用例来演示项目顺序的相关性。

我使用这种方式来进行Postgres:

SELECT id, parent_id, name 
FROM   my_table 
ORDER BY 
COALESCE(parent_id,id)||id::varchar

不相关,但是:存储0而不是null来表示没有父对象是个坏主意。这会阻止您使用正确的外键约束。您的示例正好建议1级层次结构。是这样吗?这并没有给我想要的结果,我想在我的原始版本中发布的一个question@m.beginner:联机示例将准确返回问题中列出的结果。这将首先生成父id为0的所有记录,然后打印具有正确父id和子链接的记录。我不想再次转储父id为0的所有记录:这将准确返回您在问题中显示为所需输出的内容。如果这不是您想要的,您需要更新您的问题以显示您真正想要的。这似乎只实现了parent后跟child,因为OP的测试用例构造得很糟糕,总是parent.idchild.id失败。这非常有用而且非常简单。但是,这也会产生与下面建议的递归查询相同的结果。这将首先转储父id为0的所有记录,然后生成具有正确父子顺序的记录列表。但是,我不想列出源\u id为0的所有记录first@m.beginner . . . 当然不是。它完全符合你的问题要求。我添加了一个DBFIDLE来演示这一点。虽然很聪明,但仍然无法在孩子之前对父母进行排序。@ErwinBrandstetter。它适用于提供的数据,我认为在孩子之前定义父母通常是有意义的。但是,我编辑了答案,以防样本数据不相关。@Gordon:是的,在子对象之前创建父对象似乎是有意义的。但在没有FK的情况下也不必如此,即使是在可以延期的情况下也不必如此。此外,ID也不必因为行是先添加的而变小。甚至连连载栏都没有。@m.初学者:我添加了更多的解释。@m.初学者:如果你觉得这是对你来说更好的答案:以后更改接受的答案没有什么错。