开发者

Counting Rows between dates

开发者 https://www.devze.com 2022-12-19 20:00 出处:网络
I\'m using a CTE to generate a range of dates. 12/02/2010 10:00:00 12/02/2010 10:59:59 12/02/2010 11:00:00 12/02/2010 11:59:59

I'm using a CTE to generate a range of dates.

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

I then left join this to a indexed view containing huge amounts of date.

I have 2 options for counting between the date ranges

1) i would SUM(case) test the log_date to test if it is between the start and end dates, + 1 for true, 0 for false - so if no results i would always get '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) i can count(*) using a WHERE clause per date range.

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

As you would expect 1) is effective but has a massive overhead on performance 2) is possibly 8000% more efficent BUT fails to return the range should a filter be applied which returns null results between the specified date range.

Is there a way to use the efficent WHERE clause but retain the date range row detailing '0'?

here is some SQL for the case solution:

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
                      d开发者_运维知识库bo.vCallLog WITH (noexpand) as [LOG] on 0 > -1
GROUP BY [Start Date], [End Date], [Display Start Date], [Display End Date], [LABEL]

here is some SQL for the WHERE solution:

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]


Ok, a little pokery and i realised i made a slight issue for my self:

The issue is the WHERE clause and its position to the COUNT clause. If i'm using WHERE & count on the same result set then i get nothing for zero rows between dates. IF, however, i count everything and omit the WHERE from the same result set and place the WHERE clause in the JOIN i.e [x] left join (select [a] from [b] where [a] between @x & @y) as [c] i return all the rows, count then litrally counts.

I think the issue was the WHERE clause previous ommited the count select because there was no action to take (according to the compiler)


If I understand you correctly you could try something like

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

Output

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


Ah, infamous WHERE gotchas. When you have a LEFT JOIN and a WHERE clause that tests a condition in the righthand column, you DO have to include

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

It's also a good idea to put trailing OR statements in parens when you have compound where conditions:

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

this evaluates as true when a and b = 1 or when b is null

and is different from

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

this means a must be 1 and b must be 1 or null

0

精彩评论

暂无评论...
验证码 换一张
取 消