在PostgreSQL中存储和查询间隔树

时间:2013-03-03 15:36:20

标签: sql postgresql

我有一些数据集(假设它是示例的整数),我想在Postgres中存储和查询。
例如:
数据集A:1,7,9-13
数据集B:1,7,10 我想运行查询,如:
1. B是A的子集吗? (是)
2. A和B的交点是什么? (B)
数据集可包含数千个整数范围 我想知道是否有一些扩展支持这种数据分析 任何示例/链接将不胜感激。

2 个答案:

答案 0 :(得分:0)

您可以使用范围数据类型并将每个不相交的类型存储在一行中。

您的样本:

-- The table
CREATE TABLE sets(id text, range int4range);
-- Values of set A
INSERT INTO sets VALUES('A', '[1,1]'),('A','[7,7]'),('A','[9,13]');
-- Values of set B
INSERT INTO sets VALUES('B','[1,1]'),('B','[7,7]'),('B','[10,10]');

要检查B是否是A的子集,您可以同时加入A的范围包含B范围的所有元组:

 SELECT b.range
 FROM sets b JOIN sets a
     ON a.range @> b.range
 WHERE a.id='A' AND b.id='B'

这样,您可以检查集合B中的所有值是否都在上面的结果中(这意味着B的所有范围都包含在A的至少一个范围内):

 SELECT NOT EXISTS(
     SELECT 1 FROM sets q WHERE q.id='B' AND q.range NOT IN (
         SELECT b.range
         FROM sets b JOIN sets a
             ON a.range @> b.range
         WHERE a.id='A' AND b.id='B'
     ));

要获得交叉点,您可以交叉连接两者并排除空的交集:

 SELECT * FROM (
     SELECT a.range * b.range AS intersec
     FROM sets a CROSS JOIN sets b WHERE  a.id='A' AND b.id='B'
 ) i WHERE NOT isempty(i.intersec);

这种方法的一个问题是,你必须通过不同的元组保持不相交的范围。例如,集合中的范围[1,5]和[4,7]必须仅位于[1,7]的元组中。为了确保它,你可以将它们插入一个临时表(插入或更新时),它们将表本身与重叠的元组交叉连接,然后将它们连接起来并保持其他元素的存在。

答案 1 :(得分:0)

SQL Fiddle

不需要数组或范围。这只是纯粹的关系。

拦截非常明显:

select v
from t
where set = 'A'
intersect
select v
from t
where set = 'B'
order by v

这个子集并没有那么难:

select count(*) = 0
from (
    select v
    from t
    where set = 'B'
    except
    select b.v
    from
        (select v from t where set = 'A') a
        inner join
        (select v from t where set = 'B') b on b.v = a.v
) s