Запрос Postgresql для поиска родителей со всеми детьми, упорядоченными по глубине - PullRequest
0 голосов
/ 30 октября 2018

предположим, у меня есть следующие таблицы:

Таблица Счета :

parent_id | id

......
10         | 101
20         | 201
30         | 301
30         | 302
40         | 401
40         | 402
401        | 4011
401        | 4012
4012       | 40121

и таблица accounts_tree :

ancestor | descentant | depth

1         | 10         | 1
1         | 20         | 1
1         | 30         | 1
1         | 40         | 1
1         | 101        | 2
1         | 201        | 2
1         | 301        | 2
1         | 302        | 2
1         | 401        | 2
1         | 402        | 2
1         | 4011       | 3
1         | 4012       | 3
1         | 40121      | 4
10        | 101        | 1
20        | 201        | 1
30        | 301        | 1
30        | 302        | 1
40        | 401        | 1
40        | 402        | 1
40        | 4011       | 2
40        | 4012       | 2
40        | 40121      | 3
401       | 4011       | 1
401       | 4012       | 1
4012      | 40121      | 1

Что мне нужно, так это отобразить идентификаторы учетной записи (родителей) со всеми их детьми, а для каждого ребенка отобразить своих детей, сгруппированных по возрастанию по глубине; До сих пор я использовал:

SELECT
    a.parent_id,
    a.id,
    p.depth
FROM
    accounts a
    INNER JOIN account_tree p ON a.id = p.descendant
    WHERE
        p.ancestor = 1
        AND p.depth <= 4
    ORDER BY
        a.parent_id;

, который возвращает все учетные записи, упорядоченные по родительскому идентификатору. Мои ожидания:

parent_id | id        | depth

1         | 10         | 1
10        | 101        | 2
1         | 20         | 1
20        | 201        | 2
1         | 30         | 1
30        | 301        | 2
30        | 302        | 2
1         | 40         | 1
40        | 401        | 2
401       | 4011       | 3
401       | 4012       | 3
4012      | 40121      | 4
40        | 402        | 2

Я должен упомянуть, что в проекте, над которым я работаю, есть более 500 учетных записей, и их идентификаторы не настолько «предсказуемы», как в моем примере, и глубина превышает 5 уровней.

Ответы [ 2 ]

0 голосов
/ 30 октября 2018

Адаптация ответа TomC к postgres

with recursive tree as (
    select parent_id, id, lpad(id::varchar(12),12,'0')::varchar(144) as idPath, 1::int as depth 
    from accounts 
    where parent_id = '1'
    union all 
    select a.parent_id, a.id, concat(idPath, lpad(a.id,12,'0'))::varchar(144)  idPath, depth + 1::int as depth
    from accounts a
    join tree on tree.id=a.parent_id
)
select parent_id, id, depth, idpath
from tree 
order by idpath

Если вы используете lpad () разной длины строки учетной записи на любом уровне, не изменяйте общий порядок. Вам нужно выбрать длины, которые соответствуют вашим фактическим номерам счета. Я использовал 12, и объединенный путь должен быть кратным любому числу, которое вы выберете.

+----+-----------+-------+-------+--------------------------------------------------+
|    | parent_id | id    | depth | idpath                                           |
+----+-----------+-------+-------+--------------------------------------------------+
| 1  | 1         | 10    | 1     | 000000000010                                     |
| 2  | 10        | 101   | 2     | 000000000010000000000101                         |
| 3  | 1         | 20    | 1     | 000000000020                                     |
| 4  | 20        | 201   | 2     | 000000000020000000000201                         |
| 5  | 1         | 30    | 1     | 000000000030                                     |
| 6  | 30        | 301   | 2     | 000000000030000000000301                         |
| 7  | 30        | 302   | 2     | 000000000030000000000302                         |
| 8  | 1         | 40    | 1     | 000000000040                                     |
| 9  | 40        | 401   | 2     | 000000000040000000000401                         |
| 10 | 401       | 4011  | 3     | 000000000040000000000401000000004011             |
| 11 | 401       | 4012  | 3     | 000000000040000000000401000000004012             |
| 12 | 4012      | 40121 | 4     | 000000000040000000000401000000004012000000040121 |
| 13 | 40        | 402   | 2     | 000000000040000000000402                         |
+----+-----------+-------+-------+--------------------------------------------------+

выборка данных:

CREATE TABLE accounts(
   parent_id VARCHAR(12) 
  ,id        VARCHAR(12) 
);
INSERT INTO accounts(parent_id,id) VALUES ('1','10');
INSERT INTO accounts(parent_id,id) VALUES ('1','20');
INSERT INTO accounts(parent_id,id) VALUES ('1','30');
INSERT INTO accounts(parent_id,id) VALUES ('1','40');
INSERT INTO accounts(parent_id,id) VALUES ('10','101');
INSERT INTO accounts(parent_id,id) VALUES ('20','201');
INSERT INTO accounts(parent_id,id) VALUES ('30','301');
INSERT INTO accounts(parent_id,id) VALUES ('30','302');
INSERT INTO accounts(parent_id,id) VALUES ('40','401');
INSERT INTO accounts(parent_id,id) VALUES ('40','402');
INSERT INTO accounts(parent_id,id) VALUES ('401','4011');
INSERT INTO accounts(parent_id,id) VALUES ('401','4012');
INSERT INTO accounts(parent_id,id) VALUES ('4012','40121');
0 голосов
/ 30 октября 2018

Это случай для рекурсивного CTE. Я предполагаю, что ваши ключи на самом деле varchar, поскольку они не представляют числовые значения - если нет, то обновите согласно моему последнему фрагменту.

Это создаст тестовые данные. вам нужна только ваша таблица учетных записей, а не ваша древовидная таблица

create table #account(parent_id varchar(10), id varchar(10))
insert #account values ('1','10'),('1','20'),('1','30'),('1','40'),('10','101'),('20','201'),('30','301')
    ,('30','302'),('40','401'),('40','402'),('401','4011'),('401','4012'),('4012','40121')

Теперь ваш рекурсивный запрос, сначала найдите все строки верхнего уровня (parent = 1), затем найдите все дочерние элементы, создавая составной путь по ходу

;with tree as (
    select parent_id, id, convert(varchar(100),id) as idPath, 1 as depth 
    from #account 
    where parent_id=1
    union all 
    select a.parent_id, a.id, convert(varchar(100),idPath+a.id) as idPath, depth+1 as depth
    from #account a
    join tree on tree.id=a.parent_id
)
select parent_id, id, depth from tree order by idpath

Если идентификаторы на самом деле являются целочисленными типами данных, измените конкатенацию на

convert(varchar(100),convert(varchar(10),idPath)+convert(varchar(10),a.id)) as idPath
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...