2015-08-10 4 views
0

У меня есть запрос, который возвращает некоторые данныеВозвратившись верхние значения для каждого столбца запроса SQL

Name Hour1 hour2 hour3 etc 
A 1  2  3 ... 
B 50 2  25 ... 
C 25 2  3 ... 
D 1  30  50 ... 
E 1  40  3 ... 

Я хотел бы просто иметь значения для двух верхних результатов в каждом столбце (значения составляют)

Name Hour1 hour2 hour3 etc 
A null null null ... 
B 50 null 25 ... 
C 25 null null ... 
D null 30 50 ... 
E null 40 null ... 

Может быть много имен и 24-часовых столбцов. Возможно ли это?

Существующий запрос в виде

SELECT Name, 
    ISNULL(Count(CASE WHEN DATEPART(HOUR,OpenedDate)=1 THEN 1 ELSE null END), 0) AS Hour1, 
etc 
etc 
From DataTable 

ответ

1

Я хотел бы написать запрос как:

SELECT Name, 
     SUM(CASE WHEN DATEPART(HOUR, OpenedDate) = 1 THEN 1 ELSE 0 END) AS Hour1, 
     . . . 
FROM DataTable 
GROUP BY Name; 

Чтобы получить верхние 2 значения, вы можете перечислить DataTable:

select name, 
     max(case when hr = 1 and seqnum <= 2 then cnt end) as hr_1, 
     . . . 
from (select t.*, DATEPART(HOUR, OpenedDate) as hr, count(*) as cnt, 
      row_number() over (partition by datepart(hour, OpenedDate) 
           order by count(*) desc) as seqnum 
     from datatable t 
     group by name, DATEPART(HOUR, OpenedDate) 
    ) t 
group by name; 

Подзапрос суммирует данные по имени и часу. Затем он перечисляет значения и использует их для условной агрегации.

Возможно, вам понадобится dense_rank(), а не row_number() в зависимости от того, как вы хотите обрабатывать связи.

+0

У меня был 'SUM', но попробовал' Count' по прихоти, и он сократил время на запрос пополам! – Loofer

+0

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

1

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

with cte as (
    select 
     name 
     , h = datepart(hour,openeddate) 
     , c = count(*) 
     , r = rank() over (partition by datepart(hour,openeddate) order by count(*) desc) 
    from datatable 
    group by name, datepart(hour,openeddate) 
) 

select 
    name 
    , hour1 = max(case when r <= 2 then [1] else null end) 
    , hour2 = max(case when r <= 2 then [2] else null end) 
    , hour3 = max(case when r <= 2 then [3] else null end) 
from cte 
pivot (sum(c) for h in ([1],[2],[3]))p 
group by name 
order by name 

Обратите внимание, что функция ранга вернет более двух строк, если есть связи.

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