【问题标题】:SQL - Group by unique column setsSQL - 按唯一列集分组
【发布时间】:2016-01-26 08:31:40
【问题描述】:

在“SQL - Turn relationship IDs into a delimited list”问题的基础上,我想进一步按独特的网站集对结果进行分组。例如,在该问题中使用相同的数据:

站点 15 和 16 一起共享 a、b、c 的一个排列。站点 18、19、20 共享另一个排列。站点 17 使用两种排列。

我想找到一个结果类似于链接问题的查询,但在 site_ids 中没有任何重叠:

我不确定仅使用 SQL 是否可行,我可能只需要构建一些东西来处理代码中的数据,但我正在祈祷...

我正在使用 SQL Server,但如果知道如何使用 postgres 也很高兴。

更新:
有人建议Simulating group_concat MySQL function in Microsoft SQL Server 2005? 可能是重复的。根据我对 group_concat 的(有限)理解,它似乎可能会重复 question referenced above,但不是这个问题。这个问题不需要在 site_ids 中重叠。

【问题讨论】:

  • 为什么 17 被列为第二个 foo,bar,baz 行的单个条目?但总的来说,在 Postgres 中你会使用 string_agg(site_id, ',')
  • 17 有不同的条目,因为它有来自 15,16 组的不同数据,以及来自 18,19,20 组的不同数据。 string_agg() 让我得到链接问题的结果。这个问题试图更进一步,消除site_id col之间的重叠。
  • 我没有看到第一个屏幕截图中前三行的 a、b、c 列有什么不同。前两排和第三排到底有什么不同? (顺便说一句:作为屏幕截图的示例数据不受欢迎。将其发布为格式化文本 - 或者甚至更好地作为 insert 声明。
  • 17 同时具有“foo/bar/baz”排列和“bar/baz/blah”排列。

标签: sql sql-server postgresql


【解决方案1】:

我不知道这是否是最有效的方法,但想出它确实很有趣。 :)

;WITH CTE_unique_groups AS (SELECT DISTINCT a, b, c FROM dbo.My_Table),
CTE_numbered_groups AS (SELECT a, b, c, ROW_NUMBER() OVER(ORDER BY a, b, c) AS row_num FROM CTE_unique_groups),
CTE_exponented_groups AS (SELECT a, b, c, POWER(2, row_num) AS group_value FROM CTE_numbered_groups),
CTE_unique_sets AS (
    SELECT
        MT.site_id,
        SUM(grps.group_value) AS total_group_value
    FROM
        CTE_exponented_groups AS grps
    INNER JOIN dbo.My_Table MT ON MT.a = grps.a AND MT.b = grps.b AND MT.c = grps.c
    GROUP BY
        MT.site_id
),
CTE_grouped_sites AS
(SELECT total_group_value, STUFF((SELECT ', ' + CAST(site_id AS VARCHAR(10)) FROM CTE_unique_sets t2 WHERE t2.total_group_value = t1.total_group_value FOR XML PATH('')), 1, 2, '') AS site_ids
FROM CTE_unique_sets t1)
SELECT DISTINCT
    x.a, x.b, x.c, gs.site_ids
FROM
    CTE_grouped_sites gs
INNER JOIN CTE_exponented_groups x ON
    gs.total_group_value & x.group_value = x.group_value

它的要点是,首先您必须识别每组独特的组。完成此操作后,您可以使用按位 & 运算符将站点 ID 分解回它们所属的组。

【讨论】:

    【解决方案2】:

    如果你对数组没问题(它以逗号分隔的字符串形式表现出来),这是 PostgreSQL 中一种可能的方法。

    with perms as (
      select
        f.a, f.b, f.c, f.site_id,
        count(1) over (partition by f.site_id) as cnt
      from
        your_table f
    )
    select
      p1.a, p1.b, p1.c,
      array (select p2.site_id
             from perms p2
             where
               p1.a = p2.a and
               p1.b = p2.b and
               p1.c = p2.c and
               p1.cnt = p2.cnt)
    from perms p1
    group by
      p1.a, p1.b, p1.c, p1.cnt
    

    结果如下所示:

    bar    baz    blah    {20,18,19}
    foo    bar    baz     {17}
    foo    bar    baz     {16,15}
    bar    baz    blah    {17}
    

    【讨论】:

      猜你喜欢
      • 2011-08-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-12-08
      • 1970-01-01
      相关资源
      最近更新 更多