Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/85.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 - Fatal编程技术网

Sql 递归查询中的唯一性保证

Sql 递归查询中的唯一性保证,sql,postgresql,Sql,Postgresql,我有一个非常基本的父子/树层次结构和一个递归查询,它还添加了深度,几乎完美地加载了所有内容。当我尝试加载多个节点时,其中一个节点是另一个节点的子节点,我会得到重复的行(因为depth会更新,并且行不再相同) 我确实阅读了,我没有使用UNION ALL,我确实尝试了文档中的not cycle技巧,我知道数据类型,但我不能使用它。这是另外一回事,考虑下面的树: 5 ├─9 │ └─15 ├─10 │ └─16 └─11 └─17 以及查询: WITH RECURSIVE "CTE" AS (

我有一个非常基本的父子/树层次结构和一个递归查询,它还添加了
深度
,几乎完美地加载了所有内容。当我尝试加载多个节点时,其中一个节点是另一个节点的子节点,我会得到重复的行(因为
depth
会更新,并且行不再相同)

我确实阅读了,我没有使用
UNION ALL
,我确实尝试了文档中的
not cycle
技巧,我知道数据类型,但我不能使用它。这是另外一回事,考虑下面的树:

5
├─9
│ └─15
├─10
│ └─16
└─11
  └─17
以及查询:

WITH RECURSIVE "CTE" AS
(
    SELECT "id", 0 AS "depth"
    FROM "Node" WHERE "id" IN (5, 9, 15)
    UNION
    SELECT "Node"."id", "CTE"."depth" + 1
    FROM "CTE" JOIN "Node" ON "Node"."parentId" = "CTE"."id"
)
SELECT *
FROM "CTE"
ORDER BY "id";
其结果是:

id  depth 
5   0
9   0
9   1
10  1
11  1
15  0
15  1
15  2
16  2
17  2
而不是期望的结果:

id  depth 
5   0
9   0
10  1
11  1
15  0
16  2
17  2
使用
运行相同的查询,其中“id”=5
会产生以下结果(请注意,深度有多大差异,因为选择是从根开始的):

解决方案是将join修改为:

FROM "CTE" JOIN "Node" ON 
    "Node"."parentId" = "CTE"."id" AND 
    "Node"."id" NOT IN (SELECT "id" FROM "CTE")
但是Postgres不允许从子查询引用“CTE”。我想知道是否有一个适当的方法来解决这个问题

顺便说一句,我确实想出了一个有效的解决方案,我在几个不同的场景中进行了尝试,但我不能100%确定它是否在所有情况下都有效。它基本上消除了最初选择的值,确保迭代不会“输入”它们。我做得对吗/这种方法有什么缺陷吗

WITH RECURSIVE "CTE" AS
(
    SELECT "id", 0 AS "depth"
    FROM "Node" WHERE "id" IN (5, 9, 15)
    UNION
    SELECT "Node"."id", "CTE"."depth" + 1
    FROM "CTE" JOIN "Node" ON 
        "Node"."parentId" = "CTE"."id" 
        AND NOT IN (5, 9, 15)
)
SELECT *
FROM "CTE"
ORDER BY "id";

您想要的输出到底是什么?以及(5、9、15)中的“id”有什么特别之处?它们只构成了树中的一条可能路径。您的查询很简单,正如您所问的:它返回一个具有三个根节点(5、9、15)的林。但从层次结构来看,这些节点不在同一级别上(这就是为什么存在重复节点:林中的每棵树对应一个)。如果您只想查询示例树,您只需要
其中“id”=5
。@a_horse_与_no_name道歉,添加了预期的输出。@wildplasser没有什么特别之处,它可以是5、10或任何其他包含来自同一层次结构分支的元素的节点集。哇,这太疯狂了!我没有想到要在cte之外消除复制品。谢谢是的,有一个强烈的倾向,修剪在早期阶段。(在您必须中止它们之前避免它们…)我昨天查看了过滤,没有找到任何解决方法。我刚刚在(“id”)上选中了
DISTINCT,它在没有子查询的情况下完成任务,
按“id”排序,“depth”DESC
使它也按最大深度排序。我等着看是否有人有其他想法。谢谢你,你给了我一个完全正确的主意!最后,我选择了
DISTINCT ON
。谢谢你的解决方案!
WITH RECURSIVE "CTE" AS
(
    SELECT "id", 0 AS "depth"
    FROM "Node" WHERE "id" IN (5, 9, 15)
    UNION
    SELECT "Node"."id", "CTE"."depth" + 1
    FROM "CTE" JOIN "Node" ON 
        "Node"."parentId" = "CTE"."id" 
        AND NOT IN (5, 9, 15)
)
SELECT *
FROM "CTE"
ORDER BY "id";
-- Data
CREATE TABLE node
        ( id integer NOT NULL PRIMARY KEY
        , parentid integer REFERENCES node(id)
        );

INSERT INTO node(id,parentid) VALUES
(5, NULL)
, (9,5), (10,5), (11,5)
, (15,9), (16,10), (17,11)
        ;

-- query
WITH RECURSIVE tree AS (
    SELECT id, 0 AS depth
    FROM node WHERE id IN (5, 9, 15)
    UNION
    SELECT node.id, tree.depth + 1
    FROM tree JOIN node ON node.parentid = tree.id
    )
SELECT *
FROM tree tr
WHERE NOT EXISTS ( -- trivial way to suppress duplicates with longer path
        SELECT *
        FROM tree nx
        WHERE nx.id = tr.id
        AND nx.depth < tr.depth
        )
ORDER BY id
        ;
WITH RECURSIVE tree AS (
    SELECT id, 0 AS depth
    FROM node WHERE id IN (5, 9, 15)
    UNION
    SELECT node.id, tree.depth + 1
    FROM tree JOIN node ON node.parentid = tree.id
    WHERE node.id NOT IN (5, 9, 15)
    )
SELECT *
FROM tree tr
ORDER BY id
        ;