如何计算详细信息表中的唯一组合?

时间:2018-05-10 20:07:19

标签: sql sql-server pivot transpose unpivot

我需要在SQL中编写一个查询来计算记录的唯一组合数。我有一个带有子表的项目表,列出了每个项目的选项。每个项目可能有0到x个选项。我想计算每种组合中有多少种。我以为我可以拿着儿童桌并使用枢轴和透视转换它,但我还没想到它。然后我尝试创建组合列表,但我不知道如何计算出现次数。有人能告诉我如何做到这一点或指出我正确的方向吗?

以下是我要使用的表格:

Item   |  Option 
----------------
1      |  A
1      |  B
2      |  B
3      |  B
4      |  B
4      |  C
5      |  A
6      |  A
6      |  B
6      |  C
7      |  A
7      |  B
7      |  C
8      |  A
8      |  B
9      |  A
10     |  A
10     |  B

我想要的结果是:

Option 1  | Option 2  |  Option 3  |  Count
--------------------------------------------
A         | B         |            |  3       * 1, 8, 10
B         |           |            |  2       * 2, 3
B         | C         |            |  1       * 4
A         |           |            |  2       * 5, 9
A         | B         | C          |  2       * 6, 7

这就是说A和B的组合发生了两次,两次B是唯一的选择,B和C一起被挑选了一次。 (星号后面的数字不是结果的一部分,它们只是用于显示正在计算的项目。)

我最接近的是下面的查询。它给了我独特的组合,但没有告诉我这种组合发生了多少次:

SELECT ItemCombo, Count(*) AS ItemComboCount
FROM
(
    SELECT
        Item       
          ,STUFF((SELECT ',' + CAST(Option AS varchar(MAX))
                  FROM itemDetail a 
                  WHERE a.Item = b.Item
                  FOR XML PATH(''), TYPE).value('.', 'VARCHAR(MAX)'),1,1,''
                  ) AS ItemCombo
    FROM itemDetail b
) AS Combos
GROUP BY ItemCombo
ORDER BY Count(*) DESC

2 个答案:

答案 0 :(得分:2)

您应该在内部查询中group by以及order by option,以便可以正确地对连接值进行分组。

SELECT ItemCombo, Count(*) AS ItemComboCount
FROM
(
    SELECT
        Item       
          ,STUFF((SELECT ',' + CAST(Option AS varchar(MAX))
                  FROM itemDetail a 
                  WHERE a.Item = b.Item
                  ORDER BY Option
                  FOR XML PATH(''), TYPE).value('.', 'VARCHAR(MAX)'),1,1,''
                  ) AS ItemCombo
    FROM itemDetail b
    GROUP BY item
) AS Combos
GROUP BY ItemCombo
ORDER BY Count(*) DESC

答案 1 :(得分:0)

要解决您在注释中提到的其他要求,我将在Vamsi Prabhala's excellent answer(我旁边为+1)中添加CTE,更多XML处理和动态TSQL:

--create test table
create table  tmp (Item int, [Option] char(1))

--populate test table
insert into tmp values ( 1, 'A') ,( 1, 'B') ,( 2, 'B') ,( 3, 'B') ,( 4, 'B') ,( 4, 'C') ,( 5, 'A') ,( 6, 'A') ,( 6, 'B') ,( 6, 'C') ,( 7, 'A') ,( 7, 'B') ,( 7, 'C') ,( 8, 'A') ,( 8, 'B') ,( 9, 'A') ,(10, 'A') ,(10, 'B')

declare @count         int
declare @loop          int = 1
declare @dynamicColums nvarchar(max) = ''
declare @sql           nvarchar(max) = ''

--count possible values 
select @count = max(c.options_count) from (
    select count(*) as options_count from tmp group by item
) c

--build dynamic headers for all combinations
while @loop <= @count
    begin
        set @dynamicColums = @dynamicColums + ' Parts.value(N''/x['+ cast(@loop as nvarchar(max)) +']'', ''char(1)'') AS [Option ' + cast(@loop as nvarchar(max)) + '],'
        set @loop = @loop + 1
    end

--build dynamic TSQL statement
set @sql = @sql + ';WITH Splitted'
set @sql = @sql + ' AS ('
set @sql = @sql + ' SELECT ItemComboCount'
set @sql = @sql + '     ,ItemCombo'
set @sql = @sql + '     ,CAST(''<x>'' + REPLACE(ItemCombo, '','', ''</x><x>'') + ''</x>'' AS XML) AS Parts'
set @sql = @sql + ' FROM '
set @sql = @sql + '     ('
set @sql = @sql + '         SELECT ItemCombo, Count(*) AS ItemComboCount'
set @sql = @sql + '         FROM'
set @sql = @sql + '         ('
set @sql = @sql + '             SELECT'
set @sql = @sql + '                 Item       '
set @sql = @sql + '                   ,STUFF((SELECT '','' + CAST([Option] AS varchar(MAX))'
set @sql = @sql + '                           FROM tmp a '
set @sql = @sql + '                           WHERE a.Item = b.Item'
set @sql = @sql + '                           ORDER BY [Option]'
set @sql = @sql + '                           FOR XML PATH(''''), TYPE).value(''.'', ''VARCHAR(MAX)''),1,1,'''''
set @sql = @sql + '                           ) AS ItemCombo'
set @sql = @sql + '             FROM tmp b'
set @sql = @sql + '             GROUP BY item'
set @sql = @sql + '         ) AS Combos'
set @sql = @sql + '         GROUP BY ItemCombo'
set @sql = @sql + '     ) t'
set @sql = @sql + ' )'
set @sql = @sql + ' SELECT  '
set @sql = @sql + @dynamicColums
set @sql = @sql + ' ItemComboCount as [Count]'
set @sql = @sql + ' FROM Splitted' 

--execute dynamic TSQL statement
exec(@sql)

结果:

enter image description here

现在,如果您通过几个插入语句添加另一个值(例如'D'):

insert into tmp values ( 1, 'D')
insert into tmp values ( 7, 'D')

您将看到新生成的列:

enter image description here