PostgreSQL分层关系函数

时间:2011-06-26 15:13:42

标签: postgresql plpgsql relation

CREATE TABLE sectors
(
    sector_id integer PRIMARY KEY,
    sector_name varchar(100) NOT NULL,
    parent_sector_id integer REFERENCES sectors(sector_id)
);

INSERT INTO sectors(sector_id, sector_name, parent_sector_id)
SELECT 1, 'All sectors', NULL UNION ALL
SELECT 2, 'Business', 1 UNION ALL
SELECT 3, 'Manufacturing', 2 UNION ALL
SELECT 4, 'Retail', 2 UNION ALL
SELECT 5, 'Trading', 1 UNION ALL
SELECT 6, 'Nonprofit', 1 UNION ALL
SELECT 7, 'Agriculture', 1;

问题1:通过功能查找父母关系

SELECT is_parent(1/*All sectors*/, 4/*Retail*/) should be true
SELECT is_parent(2/*Business*/, 4/*Retail*/) should be true

问题2:通过功能查找子女关系

SELECT is_child(4/*Retail*/, 1/*All sectors*/) should be true
SELECT is_child(4/*Retail*/, 2/*Business*/) should be true

对此的任何帮助都将受到高度赞赏。

2 个答案:

答案 0 :(得分:3)

如果您真的需要回答这类查询,我建议您查看PostgreSQL's recursive queries。如果它是某种需要实际编写这些函数的函数(is_parentis_child),我还建议您使用递归查询来实现它们。

答案 1 :(得分:2)

加入Pablo的回应......

使用递归查询,is_parent()非常快。假设你有parent_sector_id的索引,你基本上每个深度级别都会进行一次索引扫描。

相比之下,如果你以一种天真的方式实现它并拥有一棵巨大的树,而不是抓住所有孩子并检查你的节点,那么

is_child()会非常慢。

如果你有这样一棵树并且偶尔需要检索所有孩子,一个好的选择是实现预先排序的树算法(使用浮点数或数值;不是整数,因为它们极大地减慢了写入)或嵌套间隔。

如果没有,只需反转参数并调用is_parent(),即sql函数is_child(a, b)将返回is_parent(b, a)

最后但并非最不重要的是,您可能希望查看的是contrib中的ltree datatype。使用它,您可以在任意节点上使用gist索引执行is_parent / is_child查询。