PostgreSQL - выбрать всю иерархию таблицы с уровнями - PullRequest
0 голосов
/ 09 сентября 2018

У меня проблема в данный момент.У меня есть таблица мест с такой структурой:

  • id
  • parent_id
  • name

Я хочу сделать выбор дляесть вся иерархия этой таблицы.Вот небольшой пример данных:

(1, null, '123 Barclay St')
(2, 1, 'Floor 1')
(3, 1, 'Floor 2')
(4, 1, 'Floor 3')
(5, 2, 'Hall 1')
(6, 2, 'Room 1')
(7, 2, 'Room 2')
(8, 3, 'Room 3')
(9, null, '10 Thames St')

Очевидно, что порядок в таблице не тот.

Итак, я хочу получить этот результат с помощью моего SELECT (с 9 строками):

123 Barclay St
   Floor 1
      Hall 1
      Room 1
      Room 2
   Floor 2
      Room 3
   Floor 3
10 Thames St

А не этот результат (который я уже знаю, как получить):

10 Thames St
123 Barclay St
   Floor 1
   Floor 2
   Floor 3
      Hall 1
      Room 1
      Room 2
      Room 3

Если вы можете мне помочь, заранее благодарю.

Ответы [ 2 ]

0 голосов
/ 09 сентября 2018

Вы не предоставили запросы, которые уже задали. Но - насколько я понимаю, вы хотите рекурсивную древовидную структуру.

https://www.db -fiddle.com / ж / og5HZDHBhBRmP1cDnqgCBB / 1

CREATE TABLE rooms (
  id INTEGER, parent_id INTEGER, name TEXT
);

INSERT INTO rooms VALUES
(1, null, '123 Barclay St'),
(2, 1, 'Floor 1'),
(3, 1, 'Floor 2'),
(4, 1, 'Floor 3'),
(5, 2, 'Hall 1'),
(6, 2, 'Room 1'),
(7, 2, 'Room 2'),
(8, 3, 'Room 3'),
(9, null, '10 Thames St');

И запрос:

WITH RECURSIVE tree AS (
    SELECT
        rooms.id,
        rooms.parent_id,
        rooms.name
    FROM
        rooms
    WHERE
        parent_id IS NULL
    UNION ALL
    SELECT
        rooms.id,
        rooms.parent_id,
        rooms.name
    FROM
        tree
        JOIN rooms ON rooms.parent_id = tree.id
)
SELECT
    *
FROM
    tree;

https://www.postgresql.org/docs/current/static/queries-with.html

0 голосов
/ 09 сентября 2018

Вот решение с использованием рекурсивных CTE:

WITH RECURSIVE cte AS (
    SELECT LPAD(id::text, 3, '0') AS marker, '   ' AS buffer,
        id, parent_id, name::text
    FROM yourTable t WHERE parent_id IS NULL
    FROM yourTable t WHERE parent_id IS NULL
    UNION ALL
        SELECT t2.marker || ':' || LPAD(t1.parent_id::text, 3, '0') || ':' ||
            LPAD(t1.id::text, 3, '0') AS marker,
            t2.buffer || '   ', t1.id, t1.parent_id, t2.buffer || t1.name
    FROM yourTable t1
    INNER JOIN cte t2
        ON t1.parent_id = t2.id
)

SELECT name FROM cte ORDER BY marker;

enter image description here

Демонстрация

Основная идея здесь состоит в том, чтобы создать строки пути, которые отслеживают полный путь от каждого узла, идущего назад к его корню (корень дается узлом, parent_id равным NULL).Затем мы просто делаем один ORDER BY на этом пути, чтобы сгенерировать нужный вам порядок.

...