在SQL错误中按月分组

时间:2014-06-17 10:42:34

标签: sql group-by

我使用以下代码;

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

由于

2 个答案:

答案 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,如果我是你的话。