Postgresql recursive CTE results ordering

非 Y 不嫁゛ 提交于 2019-12-11 13:31:12

问题


I'm working on a query to pull data out of a hierarchy

e.g.

CREATE table org (
   id   INT PRIMARY KEY,
   name TEXT NOT NULL,
   parent_id INT);

INSERT INTO org (id, name) VALUES (0, 'top');
INSERT INTO org (id, name, parent_id) VALUES (1, 'middle1', 0);
INSERT INTO org (id, name, parent_id) VALUES (2, 'middle2', 0);
INSERT INTO org (id, name, parent_id) VALUES (3, 'bottom3', 1);

WITH RECURSIVE parent_org (id, parent_id, name) AS (
  SELECT id, parent_id, name
  FROM org
  WHERE id = 3
UNION ALL
    SELECT o.id, o.parent_id, o.name
    FROM   org o, parent_org po
    WHERE  po.parent_id = o.id)
SELECT id, parent_id, name
FROM parent_org;

It works as expected.

3 1 "bottom3"
1 0 "middle1"
0   "top"

It's also returning the data in the order that I expect, and it makes sense to me that it would do this because of the way that the results would be discovered.

The question is, can I count on the order being like this?


回答1:


Yes, there is a defined order. In the Postgres WITH doc, they give the following example:

WITH RECURSIVE search_graph(id, link, data, depth, path, cycle) AS (
        SELECT g.id, g.link, g.data, 1,
          ARRAY[ROW(g.f1, g.f2)],
          false
        FROM graph g
      UNION ALL
        SELECT g.id, g.link, g.data, sg.depth + 1,
          path || ROW(g.f1, g.f2),
          ROW(g.f1, g.f2) = ANY(path)
        FROM graph g, search_graph sg
        WHERE g.id = sg.link AND NOT cycle
)
SELECT * FROM search_graph;

About which they say in a Tip box (formatting mine):

The recursive query evaluation algorithm produces its output in breadth-first search order. You can display the results in depth-first search order by making the outer query ORDER BY a "path" column constructed in this way.

You do appear to be getting breadth-first output in your case above based on the INSERT statements, so I would say you could, if you wanted, modify your outer SELECT to order it in another fashion.

I believe the analog for depth-first in your case would probably be this:

WITH RECURSIVE parent_org (id, parent_id, name) AS (
  SELECT id, parent_id, name
  FROM org
  WHERE id = 3
UNION ALL
    SELECT o.id, o.parent_id, o.name
    FROM   org o, parent_org po
    WHERE  po.parent_id = o.id)
SELECT id, parent_id, name
FROM parent_org
ORDER BY id;

As I would expect (running things through in my head) that to yield this:

0   "top"
1 0 "middle1"
3 1 "bottom3"


来源:https://stackoverflow.com/questions/30336265/postgresql-recursive-cte-results-ordering

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!