Подсчет строк между датами - PullRequest
1 голос
/ 12 февраля 2010

Я использую CTE для генерации диапазона дат.

12/02/2010 10:00:00 12/02/2010 10:59:59
12/02/2010 11:00:00 12/02/2010 11:59:59
12/02/2010 12:00:00 12/02/2010 12:59:59

Затем я оставил присоединение к индексированному представлению, содержащему огромное количество дат.

У меня есть 2 варианта для подсчета между диапазонами дат

1) Я бы СУММ (случай) проверил log_date, чтобы проверить, находится ли он между датами начала и окончания, + 1 для истины, 0 для ложной - поэтому, если результатов нет, я всегда получу '0'

12/02/2010 10:00:00 12/02/2010 10:59:59    0
12/02/2010 11:00:00 12/02/2010 11:59:59    1
12/02/2010 12:00:00 12/02/2010 12:59:59    0

2) я могу считать (*), используя предложение WHERE для диапазона дат.

12/02/2010 11:00:00 12/02/2010 11:59:59    1

Как и следовало ожидать, 1) эффективен, но имеет значительные потери производительности 2), возможно, на 8000% эффективнее, НО не возвращает диапазон, если применяется фильтр, который возвращает нулевые результаты в указанном диапазоне дат.

Есть ли способ использовать действующее предложение WHERE, но сохранить строку диапазона дат, детализирующую '0'?

Вот несколько SQL для решения кейса:

SELECT     [LABEL], [Display Start Date], [Display End Date], 
    SUM(CASE WHEN ([LOG].line_date BETWEEN [Start Date] AND [End Date]) THEN 1 ELSE 0 END) AS [Total Calls], 
    SUM(CASE WHEN ([LOG].line_date BETWEEN [Start Date] AND [End Date]) AND ([LOG].line_result = 1) THEN 1 ELSE 0 END) AS [1 Calls], 

FROM         [DATE RANGE FUNCTION] LEFT JOIN
                      dbo.vCallLog WITH (noexpand) as [LOG] on 0 > -1
GROUP BY [Start Date], [End Date], [Display Start Date], [Display End Date], [LABEL]

Вот несколько SQL для решения WHERE:

SELECT     [LABEL], [Display Start Date], [Display End Date], 
                    COUNT(dbo.vCallLog.line_id) AS [Total Calls], 
                    SUM(CASE WHEN ([LOG].line_result = 1) THEN 1 ELSE 0 END) AS [1 Calls], 
FROM         [DATE RANGE FUNCTION] LEFT JOIN
                      dbo.vCallLog WITH (noexpand) as [LOG] on 0> -1
WHERE     ([LOG].line_date BETWEEN [Start Date] AND [End Date]) 
GROUP BY [Start Date], [End Date], [Display Start Date], [Display End Date], [LABEL]

Ответы [ 3 ]

2 голосов
/ 12 февраля 2010

Хорошо, немного покеры, и я понял, что сделал для себя небольшую проблему:

Проблема заключается в предложении WHERE и его положении относительно предложения COUNT. Если я использую WHERE и рассчитываю на один и тот же набор результатов, то я ничего не получаю за нулевые строки между датами. Если, однако, я считаю все и опускаю WHERE из того же набора результатов и помещаю предложение WHERE в JOIN т.е. [x] левое соединение (выберите [a] из [b] где [a] между @x & @y) as [c] я возвращаю все строки, считаю, а затем подсчитываю буквально.

Я думаю, что проблема заключалась в том, что предыдущее предложение WHERE не указывало счетчик select, потому что не было предпринято никаких действий (согласно компилятору)

1 голос
/ 12 февраля 2010

Если я вас правильно понимаю, вы можете попробовать что-то вроде

DECLARE @DateRanges TABLE(
        StartDate DATETIME,
        EndDate DATETIME
)

INSERT INTO @DateRanges (StartDate,EndDate) SELECT '12/02/2010 10:00:00','12/02/2010 10:59:59' 
INSERT INTO @DateRanges (StartDate,EndDate) SELECT '12/02/2010 11:00:00','12/02/2010 11:59:59' 
INSERT INTO @DateRanges (StartDate,EndDate) SELECT '12/02/2010 12:00:00','12/02/2010 12:59:59'

DECLARE @DateValues TABLE(
        DateVal DATETIME
)

INSERT INTO @DateValues (DateVal) SELECT '12/02/2010 11:00:00'
INSERT INTO @DateValues (DateVal) SELECT '12/02/2010 11:01:00'
INSERT INTO @DateValues (DateVal) SELECT '12/02/2010 12:01:00'

SELECT  t.StartDate,
        t.EndDate,
        COUNT(tv.DateVal) CountVal
FROM    @DateRanges t LEFT JOIN
        @DateValues tv ON tv.DateVal BETWEEN t.StartDate AND t.EndDate
GROUP BY    t.StartDate,
            t.EndDate

выход

StartDate               EndDate                 CountVal
----------------------- ----------------------- -----------
2010-12-02 10:00:00.000 2010-12-02 10:59:59.000 0
2010-12-02 11:00:00.000 2010-12-02 11:59:59.000 2
2010-12-02 12:00:00.000 2010-12-02 12:59:59.000 1
0 голосов
/ 05 мая 2011

Ах, печально известный ГДЕ попался.Если у вас есть LEFT JOIN и предложение WHERE, которое проверяет условие в правом столбце, вам НЕОБХОДИМО включить

WHERE (<Condition based on rightHandTable.Column> OR rightHandTable.Column IS NULL)

Хорошей идеей будет также ставить конечные операторы OR в скобках, когда у вас есть составныеусловия:

WHERE a=1 AND b=1 OR b iS NULL

это оценивается как истина, когда a и b = 1 или когда b равно нулю

и отличается от

WHERE a=1 AND (b=1 OR b is NULL)

, это означает, что должно быть1 и b должны быть 1 или нулем

...