SQL Server получает различное количество с помощью «Группировать по ... с кубом» - PullRequest
5 голосов
/ 03 ноября 2010

В основном я пытаюсь получить отчетливый счет в этом кубе.Но, к сожалению, вы не можете использовать Count (отличный (Поле)) с кубом и накоплением (, как указано здесь )

Вот как выглядят данные.(Это простой пример, который я ожидаю дубликатов в данных)

    Category1       Category2       ItemId
    a               b               1
    a               b               1
    a               a               1
    a               a               2
    a               c               1
    a               b               2
    a               b               3
    a               c               2
    a               a               1
    a               a               3
    a               c               4

Вот что я хотел бы сделать, но это не работает.

SELECT
  Category1,
  Category2,
  Count(Distinct(ItemId))
FROM ItemList IL
GROUP BY
  Category1,
  Category2
WITH CUBE

Я знаю, что могу сделать подобранный подвыбор, чтобы получить желаемые результаты:

SELECT
  *,
  (SELECT
     Count(Distinct(ItemId)) 
   FROM ItemList IL2 
   WHERE 
     (Q1.Category1 IS NULL OR Q1.Category1 IS NOT NULL AND Q1.Category1 = IL2.Category1) 
     AND
     (Q1.Category2 IS NULL OR Q1.Category2 IS NOT NULL AND Q1.Category2 = IL2.Category2))
       AS DistinctCountOfItems 
FROM (SELECT
        Category1,
        Category2
      FROM ItemList IL
      GROUP BY
        Category1,
        Category2
      WITH CUBE) Q1

Но это происходит медленно, когда набор результатов велик из-за подвыбора.Есть ли какой-нибудь другой способ получить отличительное количество из результата в кубе?

Это результат, который я хочу увидеть

Category1     Category2    DistinctCountOfItems
a             a            3
a             b            3
a             c            3
a             NULL         4
NULL          NULL         4
NULL          a            3
NULL          b            3
NULL          c            3

Ответы [ 5 ]

6 голосов
/ 12 ноября 2010

Вы должны быть в состоянии убрать свой "грязный" ответ так:

select Category1, Category2, count(distinct ItemId)
from ItemList
group by Category1, Category2
UNION ALL
select Category1, null, count(distinct ItemId)
from ItemList
group by Category1
UNION ALL
select null, Category2, count(distinct ItemId)
from ItemList
group by Category2
UNION ALL
select null, null, count(distinct ItemId)
from ItemList

Затем я выбрал другой вариант:

select IL1.Category1, IL1.Category2, count(distinct ItemId)
from ( 
  select Category1, Category2
  from ItemList
  group by Category1, Category2
  with cube
 ) IL1
 join ItemList IL2 on (IL1.Category1=IL2.Category1 and IL1.Category2=IL2.Category2)
      or (IL1.Category1 is null and IL1.Category2=IL2.Category2)
      or (IL1.Category2 is null and IL1.Category1=IL2.Category1)
      or (IL1.Category1 is null and IL1.Category2 is null)
group by IL1.Category1, IL1.Category2

Эффективность может варьироваться в зависимости от индексов, количества группируемых столбцов и т. Д. Для написанной мной тестовой таблицы sub-select и join (в отличие от Unions) были несколько лучше. У меня нет доступа к экземпляру MSSQL 2000 (я тестировал на экземпляре 2005 года), но я не думаю, что здесь что-то недопустимо.

UPDATE

Еще лучший вариант, особенно если вы группируете по более чем 2 столбцам (если вы группируете по 8 столбцам, приведенный выше код потребует 256 предложений объединения, чтобы перехватить все нулевые комбинации!):

select IL1.Category1, IL1.Category2, count(distinct ItemId)
from ( 
  select Category1, Category2
  from ItemList
  group by Category1, Category2
  with cube
 ) IL1
 inner join ItemList IL2 on isnull(IL1.Category1,IL2.Category1)=IL2.Category1
                  and isnull(IL1.Category2,IL2.Category2)=IL2.Category2
group by IL1.Category1, IL1.Category2
1 голос
/ 09 ноября 2010

Вот еще одна возможность, которую я нашел, но она очень грязная. Однако он работает быстрее, чем при использовании подвыбора.

SELECT 
  category1, 
  category2, 
  count(distinct itemid)
FROM (SELECT DISTINCT 
        category1, 
        category2, 
        itemid
      FROM ItemList
) x
GROUP BY category1, category2
UNION ALL
SELECT 
  category1, 
  NULL, 
  count(distinct itemid)
FROM (SELECT DISTINCT 
        category1, 
        category2, 
        itemid
      FROM ItemList
) x
GROUP BY category1
UNION ALL
SELECT 
  NULL, 
  category2, 
  count(distinct itemid)
FROM (SELECT DISTINCT 
        category1, 
        category2, 
        itemid
      FROM ItemList
) x
GROUP BY category2
UNION ALL
SELECT 
  NULL, 
  NULL, 
  count(distinct itemid)
FROM (SELECT DISTINCT 
        category1, 
        category2, 
        itemid
      FROM ItemList
) x
0 голосов
/ 03 ноября 2010

Как насчет этого?

Внутренний запрос выдаст отличный результат.

SELECT ORIGINAL_ITEM.Category1, DISTINCT_ITEM.Category2, DISTINCT_ITEM.cnt
FROM
  ( SELECT DISTINCT category2, COUNT(*) as CNT
    FROM ItemList ) DISTINCT_ITEM
JOIN ItemList ORIGINAL_ITEM on ORIGINAL_ITEM.category2 = DISTINCT_ITEM.category2 
GROUP BY ORIGINAL_ITEM.category1, DISTINCT_ITEM.category2 
0 голосов
/ 08 ноября 2010

У меня есть следующая версия:

Microsoft SQL Server 2008 R2 (окончательная первоначальная версия) - 10.50.1600.1 (Intel X86) 2 апреля 2010 15:53:02 Авторское право (c) Microsoft Corporation Express Edition с расширенными службамив Windows NT 5.1 (сборка 2600: пакет обновления 3)

Когда я запускаю ваш запрос

SELECT 
  Category1, 
  Category2, 
  COUNT(DISTINCT(ItemId))
FROM ItemList IL 
GROUP BY 
  Category1, 
  Category2 
WITH CUBE 

Получаю эти результаты

a       a       3
a       b       3
a       c       3
NULL    a       3
NULL    b       3
NULL    c       3
a       NULL    4
NULL    NULL    4
0 голосов
/ 03 ноября 2010

Это очень интересно. Я могу выполнить ваш первый запрос в SQL Server 2008 R2, но в документации сказано, что он не будет работать.

Вот вариант вашего второго запроса, который может работать лучше. Это делает различный счет в подзапросе и куб во внешнем запросе

SELECT Category1, Category2, MAX(DistinctCount) as DistinctCount
FROM (
    SELECT Category1, Category2, COUNT(DISTINCT ItemId) as DistinctCount
    FROM ItemList
    GROUP BY Category1, Category2
    ) Q1
GROUP BY Category1, Category2
WITH CUBE
...