3

我一直在研究一个我无法弄清楚的问题。我已经尝试过交叉连接、CTE、窗口函数等的不同组合,但永远无法做到。我也不想走动态 SQL 路线。有人可以帮忙吗?

给定一组可变的分组值,垂直产生所有可能的组合(派生组,值)

附加信息:

  1. 无论顺序如何,任何 2 个组合都不应具有相同的一组值。示例:如果您已经有 (1,2) 则不产生 (2,1),如果 (1,2,3) 则不产生 (1,3,2),(2,1,3),(2 ,3,1),(3,1,2),(3,2,1)
  2. 同一组的值不应合并
  3. 所有值都是唯一的,与组无关。初始分组的唯一原因是应用规则 #2

示例:给定起始组和值

输入组值

  • 1 8
  • 2 7
  • 2 9
  • 3 1
  • 3 6
  • 3 3

产生这个输出

输出组值

  • 1 8
  • 2 7
  • 3 9
  • 4 1
  • 5 6
  • 6 3
  • 7 8
  • 7 7
  • 8 8
  • 8 9
  • 9 8
  • 9 1
  • 10 8
  • 10 6
  • 11 8
  • 11 3
  • 12 7
  • 12 1
  • 13 7
  • 13 6
  • 14 7
  • 14 3
  • 15 9
  • 15 1
  • 16 9
  • 16 6
  • 17 9
  • 17 3
  • 18 8
  • 18 7
  • 18 1
  • 19 8
  • 19 7
  • 19 6
  • 20 8
  • 20 7
  • 20 3
  • 21 8
  • 21 9
  • 21 1
  • 22 8
  • 22 9
  • 22 6
  • 23 8
  • 23 9
  • 23 3

这是生成输出的手动非垂直方法

CREATE TABLE #temp1 (GroupID INT, MyValue INT)

INSERT INTO #temp1 (GroupID, MyValue)
VALUES  (1,8),(2,7),(2,9),(3,1),(3,6),(3,3)

--1st set of possibilities
SELECT MyValue
FROM #temp1

--2nd set of possibilities
SELECT a.MyValue, b.MyValue
FROM #temp1 a
JOIN #temp1 b
ON a.GroupID < b.GroupID

--3rd set
SELECT a.MyValue, b.MyValue, c.MyValue
FROM #temp1 a
JOIN #temp1 b
ON a.GroupID < b.GroupID
JOIN #temp1 c
ON b.GroupID < c.GroupID

DROP TABLE #temp1 

我的问题是可以有可变数量的起始值考虑到这一点,我的输出需要在分组的垂直集中,所以我只返回 2 列。1 将数字和数字本身组合在一起。对于这个特定示例,应该有 46 行和 23 个不同的组,如上所示

我写了 CTE,我一直在修改并最终报废:

WITH    MyCTE
          AS (SELECT    1 AS Level, DENSE_RANK() OVER (ORDER BY GroupID, MyValue) AS DgroupID, GroupID, MyValue
              FROM      #temp1
              UNION ALL
              SELECT    a.Level + 1, DENSE_RANK() OVER (ORDER BY b.GroupID, b.MyValue), b.GroupID, b.MyValue
              FROM      MyCTE a
              JOIN      #temp1 b
                        ON a.GroupID < b.GroupID)

SELECT  DENSE_RANK() OVER (ORDER BY Level, DgroupID), MyValue
FROM    MyCTE 

这样做的明显问题:

1) 我用来为每一行赋予增量值的窗口函数没有按预期工作。这可能是由于 CTE 的工作方式。对性能好,对我不好。ROW_NUMBER 窗口函数做同样的事情。我要做的就是在每次迭代中自动增加行数,以便在表“未透视”时识别组。我相信 CTE 如此之快的原因是因为它们实际上是基于集合的操作,所以即使存在递归,我也不能依赖循环/迭代的思维模式来产生预期的结果。随时纠正我的所有假设

2) 去中心化。我需要获取一组行并将列转换为行,每个行都保留原始行的标识符以显示它们被组合在一起。SQL Server 有一个名为 UNPIVOT 的绝妙命令,它对我完全没有帮助,因为您需要知道在设计时要取消多少列。这样做的重点是能够提供可变数量的输入并产生可预测的输出

4

1 回答 1

0

因此,您尝试将所有“Group 1”值与所有“Group 2”值和所有“Group 3”值分组,但要防止重复,如您所说的 ex:1,2 和 2,1。您的手动方法看起来不错,但是我不明白为什么您要比较组,而不是“值”小于先前的值,这样..

SELECT a.MyValue, b.MyValue
FROM #temp1 a
JOIN #temp1 b
ON a.MyValue < b.MyValue AND a.GroupID <> b.GroupID

--3rd set
SELECT a.MyValue, b.MyValue, c.MyValue
FROM #temp1 a
JOIN #temp1 b
ON a.MyValue < b.MyValue AND a.GroupID <> b.GroupID 
JOIN #temp1 c
ON b.MyValue < c.MyValue AND a.GroupID <> c.GroupID AND b.GroupID <> c.GroupID

根据您的反馈,上述调整应该有效,只是需要额外的肌肉,因为它必须渗透到第 1 组、第 2 组以及第 2 组、第 1 组,因为第 1 组可能存在于第 2 组中,但第 1 组有5 的低数字。如果您始终使 a.Group 小于 b.Group,则您永远不会在第 2 个位置获得值 1,因为第 2 组大于第 1 组。

这对你的场景有意义吗?

于 2012-10-22T18:44:51.083 回答