1

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 Answer 1

3

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"
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.