如何更改查询以仅保留叶节点

时间:2018-08-21 16:12:40

标签: postgresql

我的桌子上有以下数据:

 id | parent_id |   short_name   
----+-----------+----------------
  6 |         5 | cpu
  7 |         5 | ram
 14 |         9 | tier-a
 15 |         9 | rfc1918
 16 |         9 | tolerant
 17 |         9 | nononymous
 13 |        12 | cloudstack
  5 |        13 | virtualmachine
  8 |        13 | volume
  9 |        13 | ipv4
  3 |           | domain
  4 |           | account
 12 |           | vdc
(13 rows)

使用递归查询时,它看起来像这样:

with recursive tree ( id, parent_id, short_name, deep_name ) as (
select resource_type_id, parent_resource_type_id, short_name, short_name::text 
from resource_type
where parent_resource_type_id is null
union all
select rt.resource_type_id as id, rt.parent_resource_type_id, rt.short_name,
 tree.deep_name || '.' || rt.short_name
from tree, resource_type rt
where tree.id = rt.parent_resource_type_id
)
select * from tree;

 id | parent_id |   short_name   |             deep_name             
----+-----------+----------------+-----------------------------------
  4 |           | account        | account
  3 |           | domain         | domain
 12 |           | vdc            | vdc
 13 |        12 | cloudstack     | vdc.cloudstack
  9 |        13 | ipv4           | vdc.cloudstack.ipv4
  5 |        13 | virtualmachine | vdc.cloudstack.virtualmachine
  8 |        13 | volume         | vdc.cloudstack.volume
  6 |         5 | cpu            | vdc.cloudstack.virtualmachine.cpu
 15 |         9 | rfc1918        | vdc.cloudstack.ipv4.rfc1918
 17 |         9 | nononymous     | vdc.cloudstack.ipv4.nononymous
 16 |         9 | tolerant       | vdc.cloudstack.ipv4.tolerant
 14 |         9 | tier-a         | vdc.cloudstack.ipv4.tier-a
  7 |         5 | ram            | vdc.cloudstack.virtualmachine.ram
(13 rows)

如何解决查询,导致结果中只有叶子? vdc.cloudstack.volume行,没有vdcvdc.cloudstack

UPD
没有孩子的行

2 个答案:

答案 0 :(得分:1)

排除表中其他位置deep_name具有超字符串的行:

WITH RECURSIVE tree AS (...)
SELECT * FROM tree AS t1
WHERE NOT EXISTS (
   SELECT 1 FROM tree AS t2
   WHERE t2.deep_name
         LIKE t1.deep_name || '.%'
);

答案 1 :(得分:0)

Laurenz Albe的回答给了我一个主意。我认为对孩子进行计数比使用琴弦更有效。

我的解决方法是:

WITH RECURSIVE tree AS (...)
SELECT * FROM tree t1 
WHERE not EXISTS ( SELECT 1 FROM tree t2 WHERE t1.id = t2.parent_id  );