2015-12-10 2 views
2

Я хочу создать график для моего набора данных за последние 24 часа.SQL Count с нулевыми значениями

Я нашел решение, которое работает, но это очень плохо, поскольку таблица, в которой я являюсь внешним, объединяет каждую отдельную строку в БД, так как я использую (теперь устаревший) параметр «все» в группе.

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

Declare @StartDate datetime = dateadd(hour, -24, getdate()) 
Declare @StartDateProc datetime = dateadd(hour, -24, getdate()) 
Declare @EndDate datetime = getdate() 

Я заполняю даты в таблице темп, включая специальную форматированную datetsring.

create table #tempTable 
(
    Date datetime, 
    DateString varchar(11) 
) 

while @StartDate <= @EndDate 
begin 
    insert into #tempTable (Date, DateString) 
    values (@StartDate, convert(varchar(8), @StartDate, 5) + '-' + convert(varchar(2), @StartDate, 108)); 

    SET @StartDate = dateadd(hour,1, @StartDate); 
end 

Это дает мне данные, выглядит следующим образом:

Date        DateString 
--------------------------------------------- 
2015-12-09 13:59:01.970   09-12-15-13 
2015-12-09 14:59:01.970   09-12-15-14 
2015-12-09 15:59:01.970   09-12-15-15 
2015-12-09 16:59:01.970   09-12-15-16 

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

Здесь пока остальная часть запроса

select 
    Date = c.Date, 
    Amount = sum(c.Amount) 
from 
    DbTable a 
outer apply 
    (select 
     Date = b.DateString, 
     Amount = count(*) 
    from 
     #tempTable b 
    where 
     convert(varchar(8), a.DateColumn, 5) + '-' + convert(varchar(2), a.DateColumn, 108) = b.DateString 
    group by all 
     b.DateString) c 
where 
    a.SomeParameter = 'test' and 
    a.DateColumn >= @StartDateProc and 
    a.DateColumn <= @EndDate 
group by 
    c.Date 

drop table #tempTable 

тест, чтобы показать фактические данные:

Declare @StartDate datetime = dateadd(hour, -24, getdate()) 
Declare @EndDate datetime = getdate() 

select 
    dateString = convert(varchar(8),a.DateColumn,5) + '-' + convert(varchar(2),a.DateColumn, 108), 
    Amount = COUNT(*) 
from 
    DbTable a 

where 
    a.someParameter = 'test' and 
    a.DateColumn>= dateadd(hour, -24, getdate()) and 
    a.DateColumn<= getdate() 

group by 
    convert(varchar(8),a.DateColumn,5) + '-' + convert(varchar(2),a.DateColumn, 108) 

Первые выходные строки:

dateString  Amount 
09-12-15-14 1 
09-12-15-15 1 
09-12-15-16 1 
09-12-15-17 3 
09-12-15-18 1 
09-12-15-22 3 
09-12-15-23 2 

Как вы можете видеть, здесь нет данные за период с 19.00 до 21.00. Это, как я хочу, чтобы данные, которые будут отображаться:

dateString  Amount 
09-12-15-14 1 
09-12-15-15 1 
09-12-15-16 1 
09-12-15-17 3 
09-12-15-18 1 
09-12-15-19 0 
09-12-15-20 0 
09-12-15-21 0 
09-12-15-22 3 
09-12-15-23 2 
+0

Результат набор с одной стороны от объединения, даже если другая сторона не там звучит как LEFT JOIN –

+0

Попытался заставить его работать с левым соединением, но я не могу заставить его показать значения 0. – stibay

+0

Wow, 'group by all' - Я этого раньше не видел. Корпорация Майкрософт рекомендует не использовать эту функцию, она устарела. –

ответ

3

Обычно, это было бы подходить с left join, а не outer apply. Логика проста: сохраняйте все строки в первой таблице вместе с любой совпадающей информацией со второй. Это означает, что поставить стол даты первым:

select tt.DateString, count(t.DateColumn) as Amount 
from #tempTable tt left join 
    DbTable t 
    on convert(varchar(8), t.DateColumn, 5) + '-' + convert(varchar(2), t.DateColumn, 108) = tt.DateString and 
     t.SomeParameter = 'test' 
where tt.Date >= @StartDateProc and 
     tt.Date <= @EndDate 
group by tt.DateString; 

Кроме того, ваше сравнение для дат кажется слишком сложным, но если он работает для вас, это работает.

+0

Отсутствует проверка NULL функции Sum. как Sum (IsNull (t.Amount, 0)) – hazimdikenli

+0

Хм кажется, что это может работать с некоторым редактированием.В БД нет поля под названием «Сумма», поэтому догадайтесь, что это счет (*). Я также хочу группировать DateString, поэтому выберите tt.DateString и группу. Если это простой способ получить только дату и час, я бы с радостью оценил это;) – stibay

+0

Я также вижу, что вы проверяете дату против tt.date, а не на дату в базе данных? Я вижу, могу ли я изменить это на t.DateColumn> = [at] StartDateProc и t.DateColumn <= [at] EndDate, процедура выполняется намного быстрее, но она не включает нулевые значения. – stibay

0

Лучше всего здесь будет использовать DATETIME Типу себя и не потерять возможность использовать индексы:

Declare @d datetime = GETDATE() 

;WITH cte1 AS(SELECT TOP 25 -1 + ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) h 
       FROM master..spt_values), 
     cte2 AS(SELECT DATEADD(hh, -h, @d) AS startdate, 
        DATEADD(hh, -h + 1, @d) AS enddate 
       FROM cte1) 
SELECT c.startdate, c.enddate, count(*) as amount 
FROM cte2 c 
LEFT JOIN DbTable a ON a.DateColumn >= c.startdate AND 
         a.DateColumn < c.enddate AND 
         a.SomeParameter = 'test' 
GROUP BY c.startdate, c.enddate 
+0

Хм, этот запрос занимает очень много времени, чтобы выполнить от 7 до 8 секунд по сравнению с ~ 0,1 сек другими (и моя группа все) Я также получаю очень разные результаты от других методов. – stibay

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