1

我正在使用 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)我会 SUM(case) 测试 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]

这是 WHERE 解决方案的一些 SQL:

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]
4

3 回答 3

2

好吧,有点玩弄,我意识到我为自己做了一个小问题:

问题在于 WHERE 子句及其在 COUNT 子句中的位置。如果我在相同的结果集上使用 WHERE 并计数,那么对于日期之间的零行,我什么也得不到。但是,如果我计算所有内容并从同一结果集中省略 WHERE,并将 WHERE 子句放在 JOIN 中,即 [x] 左连接(从 [b] 中选择 [a],其中 [a] 在 @x 和 @y 之间)作为 [c]我返回所有行,然后计数。

我认为问题是 WHERE 子句之前省略了计数选择,因为没有采取任何行动(根据编译器)

于 2010-02-12T14:26:20.237 回答
1

如果我理解正确,您可以尝试类似

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
于 2010-02-12T13:41:48.450 回答
0

啊,臭名昭著的 WHERE 陷阱。当您有一个 LEFT JOIN 和一个 WHERE 子句来测试右侧列中的条件时,您必须包括

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

当您有复合 where 条件时,将尾随 OR 语句放在括号中也是一个好主意:

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

当 a 和 b = 1 或 b 为空时, this 评估为真

并且不同于

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

这意味着 a 必须为 1 且 b 必须为 1 或 null

于 2011-05-05T06:24:18.183 回答