我使用以下代码;
SELECT
SUM(PlanTotal) as PlanTotal, PlanStartDate
FROM
TEST.dbo.Plans
WHERE
DATEDIFF(MONTH, cast(cast(PlanStartDate AS varchar(8)) AS datetime), GETDATE()) <= 6
GROUP BY
PlanStartDate
ORDER BY
PlanStartDate
这让我回到过去六个月PlanStartDate
每天的计划总数,但是我想找到每个月的计划总计。我想如果我做了这样的事情就行了;
SELECT
SUM(PlanTotal) as PlanTotal, MONTH(PlanStartDate)
FROM
TEST.dbo.Plans
WHERE
DATEDIFF(MONTH, CAST(CAST(PlanStartDate AS varchar(8)) AS datetime), GETDATE()) <= 6
GROUP BY
MONTH(PlanStartDate)
但是我得到一个错误:
将表达式转换为数据类型datetime的算术溢出错误
我不明白我做错了什么。我需要包含强制转换函数,PlanStartDate
在数字函数中不是datetime
。
由于
答案 0 :(得分:0)
您遇到的问题是由于从字符串转换为日期。如果PlanStartDate
是字符串,则只会在您的查询中出现。
因为您的原始查询有效,我怀疑这也可行:
SELECT SUM(PlanTotal) as PlanTotal, MONTH(cast(cast(PlanStartDate as varchar(8)) as datetime))
FROM TEST.dbo.Plans
WHERE DATEDIFF(MONTH, cast(cast(PlanStartDate as varchar(8)) as datetime), GETDATE()) <= 6
GROUP BY MONTH(cast(cast(PlanStartDate as varchar(8)) as datetime));
为避免此类问题,您应将日期存储为日期,而不是字符串或数字。
答案 1 :(得分:0)
您可以通过以下方式简单地复制您的问题:
SELECT MONTH(20140624) -- TODAY'S DATE AS AN INT
为了解决这个问题,我会以有效的格式存储日期,但如果没有这个,您可以使用以下内容提取月份:
SELECT FLOOR(20140617 % 1000 / 100)
您的谓词也不是sargable,您将PlanStartDate上的任何索引都转换为两次后无效,然后将其放在DATEDIFF中。您可以按如下方式重写谓词以允许使用索引:
WHERE PlanStartDate >= CONVERT(INT, CONVERT(VARCHAR(6), DATEADD(MONTH, -6, GETDATE()), 112) + '01')
AND PlanStartdate <= GETDATE();
关键部分是您获得的第一个日期会使DATEDIFF
小于或等于6,并选择所有日期较晚的记录(小于今天)。由于GETDATE()
仅在查询开始时评估一次,因此以下部分将被评估一次,并且不需要为每一行重新评估:
CONVERT(INT, CONVERT(VARCHAR(6), DATEADD(MONTH, -6, GETDATE()), 112) + '01')
最后查询:
SELECT SUM(PlanTotal) as PlanTotal, FLOOR(20140617 % 1000 / 100) AS Month
FROM TEST.dbo.Plans
WHERE PlanStartDate >= CONVERT(INT, CONVERT(VARCHAR(6), DATEADD(MONTH, -6, GETDATE()), 112) + '01')
AND PlanStartdate <= GETDATE()
GROUP BY FLOOR(20140617 % 1000 / 100);
这已删除了有关您数据的所有转化,因此会更好地进行优化。我仍然倾向于咬住子弹然后将PlanStartDate转换为DATE,如果我是你的话。