2

我正在使用 PostgreSQL 9.2.4。

问题

我有一个带有 ID 的表和某种类型的第二列。我们称之为类型X。我还有一个二进制函数,它对一对Xs 进行操作并返回一个布尔值。我们将调用此函数ff是传递的;即,如果f(a,b)f(b,c)都返回真,那么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));返回真。

5没有出现在任何地方,因为'green'它是唯一长度为 5 的字符串。如果我得到重复的就可以了;我可以弄清楚如何清理它们。

真实情况详情

实际上,我的“第二列”是 PostGIS GEOMETRY(LINESTRING),而我的“二进制函数”是ST_Equals. 所以真的,我正在寻找一堆重复的线串。除了表明我无法将问题简化为更易于处理的操作之外,我认为这些信息与手头的问题无关。

4

2 回答 2

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
于 2013-06-28T22:35:09.510 回答
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
于 2013-06-29T00:28:51.247 回答