【问题标题】:Group by binary operator in PostgreSQL在 PostgreSQL 中按二元运算符分组
【发布时间】:2013-06-28 21:58:09
【问题描述】:

我使用的是 PostgreSQL 9.2.4。

问题

我有一个带有 ID 的表和某种类型的第二列。我们将类型称为X。我还有一个二进制函数,它在一对Xs 上运行并返回一个布尔值。我们将此函数称为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。所以真的,我正在寻找一堆重复的线串。除了表明我无法将问题简化为更易于处理的操作之外,我认为这些信息与手头的问题无关。

【问题讨论】:

  • 如果我能在不添加大量文本的情况下澄清这一点,我将不胜感激。

标签: postgresql aggregates


【解决方案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

【讨论】:

  • 首先,谢谢!第二,对不起。我的问题应该更清楚。我的意思是数组中的重复项。关于消除第三行(包含第一行的子集)有什么想法吗?
【解决方案2】:

在使用 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

【讨论】:

    猜你喜欢
    • 2011-11-27
    • 1970-01-01
    • 1970-01-01
    • 2017-03-22
    • 2021-08-03
    • 2018-10-16
    • 2018-01-07
    • 2017-10-13
    • 2018-01-07
    相关资源
    最近更新 更多