【问题标题】:如何比较多行
【发布时间】:2022-01-22 22:47:24
【问题描述】:

我有一个包含如下数据的表,想要返回具有唯一数据的那些 group_id。 group_id 3 和 4 都有两个分量 123 和 456,所以它们是“重复的”,我们只需要返回较小的 group_id,即 3。另外 group_id 5 没有重复,可以返回。所以我们希望返回 group_id 3 和 5。

如何针对 postgres 数据库编写 SQL 查询来实现这一点?谢谢!

id group_id component_id
1 3 123
2 3 456
3 4 123
4 4 456
5 5 123

【问题讨论】:

    标签: sql postgresql group-by min string-agg


    【解决方案1】:

    使用 2 级聚合:

    SELECT MIN(group_id) group_id
    FROM (
      SELECT group_id, STRING_AGG(component_id::text, ',' ORDER BY component_id) components
      FROM tablename
      GROUP BY group_id
    ) t
    GROUP BY components;
    

    请参阅demo

    【讨论】:

    • 非常感谢!很高兴知道 STRING_AGG,这正是我正在寻找的解决方案。
    【解决方案2】:
    SELECT group_id, MIN(component_id)
    FROM   MyTable
    GROUP  BY group_id
    HAVING COUNT(*) > 1
    

    【讨论】:

    • 感谢您的建议。上表中有 3 个组,group_id 3 与组件 123、456,group_id 4 与组件 123、456,group_id 5 与组件 123 我们认为 group_id 3 和 4 是重复的,因为它们都具有相同的组件。我们需要返回 3 和 5。我认为您的查询返回 3、123; 4, 123.
    • 只需从 SELECT 语句的 SELECT 子句中删除“MIN(component_id)”即可。
    【解决方案3】:

    这是一种将 group_id 分配给 component_id 的方法。

    它使用带有数组的递归 CTE 来查找可能的组合。
    递归从孤独的 group_id 开始。

    然后下一个 CTE 选择最长的组合之一。

    WITH RECURSIVE RCTE AS (
        SELECT id, group_id, component_id
        , 1 as Lvl
        , array[group_id] as group_ids
        , array[component_id] as component_ids
        FROM YourTable
        WHERE group_id IN (
          SELECT group_id
          FROM YourTable
          GROUP BY group_id
          HAVING COUNT(*) = 1
        )
        UNION ALL
        SELECT t.id, t.group_id, t.component_id
        , Lvl+1
        , cte.group_ids || t.group_id
        , cte.component_ids || t.component_id
        FROM RCTE cte
        JOIN YourTable t 
          ON t.group_id != ALL(group_ids)
         AND t.component_id != ALL(component_ids)
    )
    , CTE_ARRAYS AS (
        SELECT group_ids, component_ids
        FROM RCTE
        ORDER BY array_length(group_ids, 1) desc, Lvl desc
        LIMIT 1
    ) 
    SELECT a.group_id, a.component_id
    FROM CTE_ARRAYS c
    CROSS JOIN LATERAL UNNEST(c.group_ids, c.component_ids) WITH ORDINALITY AS a(group_id, component_id)
    ORDER BY a.group_id;
    
    group_id component_id
    3 456
    5 123

    db小提琴here

    【讨论】:

    • 谢谢!这看起来是个不错的解决方案。
    • 如果将最后一行更改为 , (5, 5, 789) 并再添加一行 (6, 3, 789) 并更改 ,则预期结果是组 id 3, 4, 5。但是结果是 4、4、5。dbfiddle.uk/…
    • @zhaoxiongwei 解决方案已经彻底改变。它现在是递归的。
    猜你喜欢
    • 2015-11-15
    • 1970-01-01
    • 1970-01-01
    • 2020-05-22
    • 1970-01-01
    • 2016-08-31
    • 1970-01-01
    • 1970-01-01
    • 2012-01-18
    相关资源
    最近更新 更多