2016-05-26 5 views
3

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

[CustomerName], [Device], [A], [B], [C] 
'Customer A', '1234', 1, 0, 0 
'Customer A', '1235', 1, 1, 1 
'Customer A', '1234', 1, 1, 1 
'Customer B', '1236', 1, 1, 0 
'Customer B', '1236', 1, 0, 0 
'Customer C', '1235', 1, 1, 1 

Мне нужен доклад, содержащий 3-х типов данных одновременно:

  • Общее количество строк с каждым флагом
  • Число строк с каждой флаг для каждого клиента
  • количество уникальных устройств, которые появляются в любой строке с каждым флагом

Первые два предмета были относительно просты в создании с использованием ROLLUP, но последний элемент был более сложным. Единственный способ, которым я мог понять, как сделать это с UNION:

SELECT CASE WHEN (GROUPING([CustomerName]) = 1) THEN 'ALL CUSTOMERS' 
     ELSE [CustomerName] END [CustomerName], 
     COUNT(*) [Rows], 
     SUM(CAST([A] AS [int])) [A], 
     SUM(CAST([B] AS [int])) [B], 
     SUM(CAST([C] AS [int])) [C] 
    FROM [MyTable] 
GROUP BY [CustomerName] WITH ROLLUP 
UNION 
SELECT 'UNIQUE DEVICES', 
     COUNT(*), 
     SUM(CASE WHEN [A] > 0 THEN 1 ELSE 0 END), 
     SUM(CASE WHEN [B] > 0 THEN 1 ELSE 0 END), 
     SUM(CASE WHEN [C] > 0 THEN 1 ELSE 0 END) 
    FROM (
    SELECT [Device], 
      COUNT(*) [Rows], 
      SUM(CAST([A] AS [int])) [A], 
      SUM(CAST([B] AS [int])) [B], 
      SUM(CAST([C] AS [int])) [C] 
     FROM [MyTable] 
    GROUP BY [Device]) q 

Результаты:

[CustomerName], [Rows], [A], [B], [C] 
'ALL CUSTOMERS', 6,  6, 4, 3 
'Customer A',  3,  3, 2, 2 
'Customer B',  2,  2, 1, 0 
'Customer C',  1,  1, 1, 1 
'UNIQUE DEVICES', 3,  3, 3, 2 

Это работает достаточно хорошо для моих целей в настоящее время, но, не имел большого опыта работы с ROLLUP или CUBE раньше, я думал, что постараюсь посмотреть, смогу ли я избавиться от этого UNION и у вас есть SELECT. С examples on MSDN, ROLLUP поддерживает несколько группировок, но я не могу понять, как получить его для получения результатов, которые я хочу. Может ли кто-нибудь продемонстрировать, как использовать один SELECT, чтобы получить эти результаты?

+0

Группировка, свертывание и куб являются иерархическими, но желаемого результата нет. То, что вы сделали, - это единственный способ получить нужный результат :) –

+0

@ P.Salmon Это то, чего я боялся, но я продолжаю думать, что это возможно, если я использую двойную агрегацию, как это было в второй SELECT. –

+0

Есть способы получить это в «одном» запросе (т. Е. Не использовать UNION), но все они будут включать более сложный/менее понятный/менее эффективный код, чем тот, который у вас уже есть. Я могу опубликовать пример позже, если вы действительно захотите, или можете принять, что @ P.Salmon в основном ударил его по голове. – Jeff

ответ

0

Мне нужен доклад, содержащий 3 вида данных одновременно:

Это не обязательно означает, что вам нужно один запрос. Результаты, которые вы хотите, логически различны. Есть другие способы группировки их всех вместе, но самый простой запрос является объединение всех трех:

select CustomerName 
     , count(*) as Rows 
     , sum(cast(A as int)) as A 
     , sum(cast(B as int)) as B 
     , sum(cast(C as int)) as C 
from T 
group by CustomerName 
UNION 
select 'ALL CUSTOMERS' 
     , count(*) as Rows 
     , sum(cast(A as int)) as A 
     , sum(cast(B as int)) as B 
     , sum(cast(C as int)) as C 
from T 
UNION 
select 'UNIQUE DEVICES' 
     , count(*) as Rows 
     , sum(A) as A 
     , sum(B) as B 
     , sum(C) as C 
from (
     select Device 
       , max(cast(A as int)) as A 
       , max(cast(B as int)) as B 
       , max(cast(C as int)) as C 
     from T 
     group by Device 
) as A 

Весь Накопительный/куб вещь всегда была своеобразной катастрофой. Если вы воспользуетесь его подробностями, хорошо, используйте его, иначе я рекомендую дать ему широкий причал. Я не мог с готовностью понять ваш запрос без вашего объяснения; напротив, я полагаю, что первые две части моей легко поняты без объяснения причин.

Вы можете создавать виды каждого из трех компонентов UNION и устраивать их другими интересными способами (в дополнение к One Big Query).

Может ли кто-нибудь продемонстрировать, как использовать один SELECT для получения этих результатов?

Ваш запрос и мой являются как отдельные SELECT заявления; UNION является частью SELECT. Я думаю, вы имеете в виду, что это можно сделать без UNION, и этот ответ №. Или, может быть, «да, но вам это не понравится». Как вы сами сформулировали вопрос, вы хотите суммировать данные в двумя разными способами:. Этими двумя способами являются логически отличные: по клиенту и по флагом.UNION - оператор реляционной алгебры, который объединяет два отношения, что именно вы просили! :-)

SQL-сервер также поддерживает OVER clause; он допускает более сложные виды группировки, и вы можете получить его для получения желаемых результатов без UNION. Но я сомневаюсь, что SQL будет так же легко понять и изменить, либо несколько строк, как то, что у вас есть до сих пор.

Смежные вопросы