Как рассчитать уникальные комбинации из таблицы данных? - PullRequest
0 голосов
/ 10 мая 2018

Мне нужно написать запрос в SQL для подсчета количества уникальных комбинаций записи.У меня есть таблица элементов с опциями дочерней таблицы для каждого элемента.Каждый элемент может иметь от 0 до x количества вариантов.Я хочу посчитать, сколько существует каждой комбинации.Я думал, что смогу взять дочерний стол и переставить его, используя pivot и unpivot, но я не понял этого.Затем я попытался создать список комбинаций, но я не знаю, как подсчитать вхождения.Может кто-нибудь показать мне, как это сделать, или указать мне правильное направление?

Вот таблица, которую я хочу использовать:

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 собирались вместе 1 раз.(Цифры после звездочки не являются частью результата, они просто показывают, какие элементы подсчитываются.)

Наиболее близким из приведенных мной является запрос ниже.Он дает мне уникальные комбинации, но не говорит мне, сколько раз эта комбинация встречалась:

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 голосов
/ 24 августа 2018

Чтобы удовлетворить дополнительное требование, которое вы упомянули в комментариях, я бы добавил CTE, еще немного обработки XML и динамический TSQL к Отличный ответ Вамси Прабхалы (+1 с моей стороны):

--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

0 голосов
/ 10 мая 2018

Вы должны 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
...