假设我有以下表格:
表帐户:
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
我需要的是与所有孩子一起显示帐户ID(父母),并为每个孩子显示他们的孩子(按深度递增分组); 到目前为止,我使用过:
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;
将返回按父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多个帐户,并且它们的ID并不是像我的示例中那样“可预测的”编号,并且深度超过5个级别。
答案 0 :(得分:1)
使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');
答案 1 :(得分:0)
这是递归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')
现在,您进行递归查询,首先找到所有顶层行(父级= 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
如果ID实际上是整数数据类型,则将串联更改为
convert(varchar(100),convert(varchar(10),idPath)+convert(varchar(10),a.id)) as idPath