带有存储过程的每日报告
Posted
技术标签:
【中文标题】带有存储过程的每日报告【英文标题】:Daily report with stored procedure 【发布时间】:2017-05-22 10:11:07 【问题描述】:我有这个 sp 来做一个需要每天做的报告。我怎样才能实现白天部分?就像我写的那样没关系,或者这是一些简单的方法?!
ALTER PROCEDURE [dbo].[pr_Report]
@YearOfRegistration INT
AS
SELECT
peCountryID,
peCountryName as coName,
ISNULL(SUM(CASE WHEN peIsSubmittedFL = 1 THEN 1 ELSE 0 END ),0) AS rdValue1,
ISNULL(SUM(CASE WHEN peIsSubmittedFL = 0 THEN 1 ELSE 0 END ),0) AS rdValue2,
COUNT(*) AS Total
FROM
vPerson
WHERE
@YearOfRegistration = 0
OR peYearOfRegistration = @YearOfRegistration
AND (DATEPART(dd, peSubmitDate) = DATEPART(dd, GETDATE())
AND DATEPART(MM, peSubmitDate) = DATEPART(MM, GETDATE())
AND DATEPART(yy, peSubmitDate) = DATEPART(YY, GETDATE()))
GROUP BY
peCountryofResidencyID, peCountryOfResidencyName
【问题讨论】:
【参考方案1】:逻辑是正确的,但这是一种非常糟糕的方法。您应该尽可能避免对数据调用函数,尤其是在 where 子句中,因为这意味着基础列上的任何索引都不能使用。
你的谓词最好写成:
WHERE peSubmitDate >= CAST(GETDATE() AS DATE)
AND peSubmitDate < DATEADD(DAY, 1, CAST(GETDATE() AS DATE));
这样可以使用索引,你的查询是sargable
碰巧,将DATETIME
转换为DATE
(反之亦然)实际上是不使用函数规则的一个例外,因此您可以将其缩短为:
WHERE CONVERT(DATE, peSubmitDate) = CONVERT(DATE, GETDATE())
另一点是,尽管使用OR
来适应您的两种选择(按年份过滤或返回所有记录)可能看起来更好,但您会发现使用两个单独的查询会执行得更好。所以你的最终 SP 可能是:
ALTER PROC [dbo].[pr_Report] @YearOfRegistration INT
AS
BEGIN
IF (@YearOfRegistration = 0)
BEGIN
SELECT peCountryID,
peCountryName as coName,
ISNULL(SUM(CASE WHEN peIsSubmittedFL = 1 THEN 1 ELSE 0 END ),0) AS rdValue1,
ISNULL(SUM(CASE WHEN peIsSubmittedFL = 0 THEN 1 ELSE 0 END ),0) AS rdValue2,
COUNT(*) AS Total
FROM vPerson
WHERE CONVERT(DATE, peSubmitDate) = CONVERT(DATE, GETDATE())
GROUP BY peCountryofResidencyID,peCountryOfResidencyName
END
ELSE
BEGIN
SELECT peCountryID,
peCountryName as coName,
ISNULL(SUM(CASE WHEN peIsSubmittedFL = 1 THEN 1 ELSE 0 END ),0) AS rdValue1,
ISNULL(SUM(CASE WHEN peIsSubmittedFL = 0 THEN 1 ELSE 0 END ),0) AS rdValue2,
COUNT(*) AS Total
FROM vPerson
WHERE CONVERT(DATE, peSubmitDate) = CONVERT(DATE, GETDATE())
AND peYearOfRegistration = @YearOfRegistration
GROUP BY peCountryofResidencyID,peCountryOfResidencyName;
END
END
【讨论】:
“尽可能避免调用函数,尤其是在 where 子句中,因为这意味着不能使用基础列上的任何索引”与您使用 @987654329 的建议直接矛盾@、DATEADD()
和 GETDATE()
在 WHERE
子句中。也许您可以为少数可能感到困惑的人澄清一下。
我已经说过 datetime 和 date 之间的强制转换和转换是这个规则的例外,GETDATE()
是一个运行时常量,所以它在运行时计算一次,而不是针对返回的每一行。因此,DATEADD(DAY, 1, Column) is evaluated once for every column, but
DATEADD(DAY, 1, GETDATE())` 每次查询都会评估一次,因此不会对性能产生不利影响。
我担心有些人只会听到“绝不在where
子句中使用函数”。应用于列 的函数可能会影响可搜索性。至于GetDate()
,每个 instance 都是一个单独的运行时常量,因此第一个示例中的两个调用可以返回不同的值。 (可以在here 找到有关该功能的一些讨论。)当两个电话返回不同的日期时,试图调试在午夜运行的报告的仆人可悲了。【参考方案2】:
getdate 返回一个日期时间,因此如果您只想比较日期而不是一天中的时间,您可以使用 cast。如果 peSubmitDate 的数据类型为 Date ,请使用此比较:
peSubmitDate = cast(GetDate() as date)
如果是数据时间,那么像这样使用它: cast(peSubmitDate as date) = cast(GetDate() as date)
后一种性能更差,所以只有在是日期时间时才使用它
【讨论】:
感谢你们,还有一个问题 - 我如何将这个 select 语句与 peSubmitDate 子句和另一个一般(没有 Date 子句)的语句合并到一个 sp 中?以上是关于带有存储过程的每日报告的主要内容,如果未能解决你的问题,请参考以下文章