递归CTE来组合值

时间:2017-09-15 02:08:10

标签: sql sql-server sqlite common-table-expression recursive-query

请注意,这是与评论中引用的问题重复,因为这需要CTE。

如何创建递归的公用表表达式,它结合了分组数据(如string_agg()group_concat())?

例如,我有一个简单的数据集,如下所示:

┌──────┬──────────┐
│ code │ category │
╞══════╪══════════╡
│ 1    │ A        │
├──────┼──────────┤
│ 1    │ B        │
├──────┼──────────┤
│ 2    │ A        │
├──────┼──────────┤
│ 3    │ B        │
├──────┼──────────┤
│ 4    │ B        │
├──────┼──────────┤
│ 4    │ C        │
├──────┼──────────┤
│ 4    │ D        │
├──────┼──────────┤
│ 5    │ B        │
└──────┴──────────┘

我想生成一个结果集,按类别按组合组合类别:

┌──────┬──────────┐
│ code │ category │
╞══════╪══════════╡
│ 1    │ A,B      │
├──────┼──────────┤
│ 2    │ A        │
├──────┼──────────┤
│ 3    │ B        │
├──────┼──────────┤
│ 4    │ B,C,D    │
├──────┼──────────┤
│ 5    │ B        │
└──────┴──────────┘

我认为答案可能是通用的,但我特别感兴趣的是为PostgreSQL,SQLite和SQL Server寻找解决方案。

1 个答案:

答案 0 :(得分:0)

  

有足够的推力,猪飞得很好。但是,这不一定是个好主意    - RFC 1925

首先,获取所有不同的code值。 然后确定每个category的第一个(最小)code值。 然后,在递归中,为每个category获取下一个更大的code值。 结果包含为每个code执行最新步骤的所有行:

WITH RECURSIVE OinkOink(code, category, combined, step) AS (
  SELECT code,
         (SELECT MIN(MyTable.category)
          FROM MyTable
          WHERE MyTable.code = DistinctCodes.code),
         (SELECT MIN(MyTable.category)
          FROM MyTable
          WHERE MyTable.code = DistinctCodes.code),
         1
  FROM (SELECT DISTINCT code
        FROM MyTable) AS DistinctCodes

  UNION ALL

  SELECT code,
         (SELECT MIN(MyTable.category)
          FROM MyTable
          WHERE MyTable.code     = OinkOink.code
            AND MyTable.category > OinkOink.category),
         combined || ',' ||
           (SELECT MIN(MyTable.category)
            FROM MyTable
            WHERE MyTable.code     = OinkOink.code
              AND MyTable.category > OinkOink.category),
         step + 1
  FROM OinkOink
  WHERE EXISTS (SELECT *
                FROM MyTable
                WHERE MyTable.code     = OinkOink.code
                  AND MyTable.category > OinkOink.category)
)
SELECT code, combined
FROM OinkOink
JOIN (SELECT code,
             MAX(step) AS step
      FROM OinkOink
      GROUP BY code) AS LargestSteps
USING (code, step)
ORDER BY code;