在PostgreSQL中按二进制运算符分组

时间:2013-06-28 21:58:09

标签: postgresql aggregates

我正在使用PostgreSQL 9.2.4。

问题

我有一个带有ID的表和某种类型的第二列。我们称之为X类型。我还有一个二进制函数,它在一对X s上运行并返回一个布尔值。我们将此函数称为ff是传递性的;即,如果f(a,b)f(b,c)都返回true,那么f(a,c)也是如此。

我想要做的是获取一组ID,第二列的所有对都为此二进制函数返回true。我怎么能做到这一点?

表现不是一个大问题;这是导入过程的一部分,每年只会运行一次。在导入过程中,数据库将不会被使用。

(相对)简单示例

我已经创建了一个SQL Fiddle来开始工作:http://sqlfiddle.com/#!12/57b97/3。我想通过f函数的结果来收集ID。请注意,一般情况下,f可能会更复杂。这只是一个例子。

我正在寻找的这个示例SQL Fiddle的输出类似于以下内容:

{1,3,6}
{2,4}

例如,假设我们从一组中选择任意一对ID。假设我们选择13。然后SELECT f((SELECT data FROM temp WHERE id = 1), (SELECT data FROM temp WHERE id = 3));返回true。

5没有显示在任何地方,因为'green'是唯一一个长度为5的字符串。如果我重新获得副本,那就没关系了。我可以弄清楚如何清理它们。

真实情况详情

实际上,我的“第二列”是PostGIS GEOMETRY(LINESTRING),而我的“二元功能”是ST_Equals。所以,我正在寻找一堆重复的线串。我不认为这些信息与手头的问题有关,除了显示我无法简化问题以便更容易处理操作。

2 个答案:

答案 0 :(得分:1)

开始摆弄这个SQL Fiddle

select
    t1.id id1,
    t1.data data1,
    t2.id id2,
    t2.data data2,
    f(t1.data, t2.data) f
from
    temp t1
    inner join
    temp t2 on t1.id < t2.id
order by t1.id, t2.id

然后转到最终版本SQL Fiddle

select array[id1] || array_agg(id2) id2
from (
    select t1.id id1, t2.id id2
    from
        temp t1
        inner join
        temp t2 on t1.id < t2.id
    where f(t1.data, t2.data)
) s
group by id1
order by id1, id2

答案 1 :(得分:0)

在与Clodoaldo Neto的回答一段时间之后,我终于明白了。

WITH matches AS (
    select t1.id id1, t2.id id2
    from temp t1
    inner join temp t2 on t1.id < t2.id
    where f(t1.data, t2.data)
)
SELECT id1 || ARRAY_AGG(id2)
FROM matches
WHERE id1 NOT IN (SELECT DISTINCT id2 FROM matches)
GROUP BY id1

SQL小提琴:http://sqlfiddle.com/#!12/57b97/14

CTE直接来自Clodoaldo Neto的内部询问。这非常好,因为它还允许我拆分它们并且如果我想要的话,它具有最低的ID:

WITH matches AS (select t1.id id1, t2.id id2
                 from temp t1
                 inner join temp t2 on t1.id < t2.id
                 where f(t1.data, t2.data)
                )
SELECT id1, ARRAY_AGG(id2) AS duplicates
FROM matches
WHERE id1 NOT IN (SELECT DISTINCT id2 FROM matches)
GROUP BY id1