SQL Server组按月份

我有一个有这个模式的表

ItemID UserID Year IsPaid PaymentDate Amount 1 1 2009 0 2009-11-01 300 2 1 2009 0 2009-12-01 342 3 1 2010 0 2010-01-01 243 4 1 2010 0 2010-02-01 2543 5 1 2010 0 2010-03-01 475 

我试图得到一个查询工作,显示每个月的总计。 到目前为止,我已经尝试了DateDiff和嵌套select,但都不给我我想要的。 我认为这是最接近的:

 DECLARE @start [datetime] = 2010/4/1; SELECT ItemID, IsPaid, (SELECT SUM(Amount) FROM Payments WHERE Year = 2010 And DateDiff(m, PaymentDate, @start) = 0 AND UserID = 100) AS "Apr", (SELECT SUM(Amount) FROM Payments WHERE Year = 2010 AND DateDiff(m, PaymentDate, @start) =1 AND UserID = 100) AS "May", (SELECT SUM(Amount) FROM Payments WHERE Year = 2010 AND DateDiff(m, PaymentDate, @start) =2 AND UserID = 100) AS "Jun", (SELECT SUM(Amount) FROM Payments WHERE Year = 2010 AND DateDiff(m, PaymentDate, @start) =3 AND UserID = 100) AS "Jul", (SELECT SUM(Amount) FROM Payments WHERE Year = 2010 AND DateDiff(m, PaymentDate, @start) =4 AND UserID = 100) AS "Aug", (SELECT SUM(Amount) FROM Payments WHERE Year = 2010 AND DateDiff(m, PaymentDate, @start) =5 AND UserID = 100) AS "Sep", (SELECT SUM(Amount) FROM Payments WHERE Year = 2010 AND DateDiff(m, PaymentDate, @start) =6 AND UserID = 100) AS "Oct", (SELECT SUM(Amount) FROM Payments WHERE Year = 2010 AND DateDiff(m, PaymentDate, @start) =7 AND UserID = 100) AS "Nov", (SELECT SUM(Amount) FROM Payments WHERE Year = 2010 AND DateDiff(m, PaymentDate, @start) =8 AND UserID = 100) AS "Dec", (SELECT SUM(Amount) FROM Payments WHERE Year = 2010 AND DateDiff(m, PaymentDate, @start) =9 AND UserID = 100) AS "Jan", (SELECT SUM(Amount) FROM Payments WHERE Year = 2010 AND DateDiff(m, PaymentDate, @start) =10 AND UserID = 100) AS "Feb", (SELECT SUM(Amount) FROM Payments WHERE Year = 2010 AND DateDiff(m, PaymentDate, @start) =11 AND UserID = 100) AS "Mar" FROM LIVE L INNER JOIN Payments I ON I.LiveID = L.RECORD_KEY WHERE UserID = 16178 

但是当我应该得到价值的时候,我只会得到空值。 我错过了什么吗?

 SELECT CONVERT(NVARCHAR(10), PaymentDate, 120) [Month], SUM(Amount) [TotalAmount] FROM Payments GROUP BY CONVERT(NVARCHAR(10), PaymentDate, 120) ORDER BY [Month] 

你也可以尝试:

 SELECT DATEPART(Year, PaymentDate) Year, DATEPART(Month, PaymentDate) Month, SUM(Amount) [TotalAmount] FROM Payments GROUP BY DATEPART(Year, PaymentDate), DATEPART(Month, PaymentDate) ORDER BY Year, Month 

将NVARCHAR的维度限制为7,提供给CONVERT以仅显示“YYYY-MM”

 SELECT CONVERT(NVARCHAR(7),PaymentDate,120) [Month], SUM(Amount) [TotalAmount] FROM Payments GROUP BY CONVERT(NVARCHAR(7),PaymentDate,120) ORDER BY [Month] 

我更喜欢结合DATEADDDATEDIFFfunction:

 GROUP BY DATEADD(MONTH, DATEDIFF(MONTH, 0, Created),0) 

这两个函数一起使date分量小于指定的date分量(即本例中的MONTH )。

你可以将datepart位更改为YEARWEEKDAY等等,这是非常方便的。

你原来的SQL查询会看起来像这样(我无法testing,因为我没有你的数据集,但它应该把你放在正确的轨道上)。

 DECLARE @start [datetime] = '2010-04-01'; SELECT ItemID, UserID, DATEADD(MONTH, DATEDIFF(MONTH, 0, Created),0) [Month], IsPaid, SUM(Amount) FROM LIVE L INNER JOIN Payments I ON I.LiveID = L.RECORD_KEY WHERE UserID = 16178 AND PaymentDate > @start 

还有一件事:如果您需要进一步处理该数据或将其映射到.NET对象,则“ Month列将被键入为DateTime ,这也是一个很好的优势。

 DECLARE @start [datetime] = 2010/4/1; 

应该…

 DECLARE @start [datetime] = '2010-04-01'; 

你所拥有的是2010年除以4,然后除以1,然后转换成date。 这是从1900-01-01第57.5天。

初始化后尝试SELECT @start来检查这是否正确。

如果你需要经常这样做,我可能会添加一个计算列PaymentMonth到表中:

 ALTER TABLE dbo.Payments ADD PaymentMonth AS MONTH(PaymentDate) PERSISTED 

它被保存并存储在表中 – 所以没有任何性能开销来查询它。 这是一个4字节的INT值 – 所以空间开销也很小。

一旦你有了这些,你可以简化你的查询是沿线的东西:

 SELECT ItemID, IsPaid, (SELECT SUM(Amount) FROM Payments WHERE Year = 2010 And PaymentMonth = 1 AND UserID = 100) AS 'Jan', (SELECT SUM(Amount) FROM Payments WHERE Year = 2010 And PaymentMonth = 2 AND UserID = 100) AS 'Feb', .... and so on ..... FROM LIVE L INNER JOIN Payments I ON I.LiveID = L.RECORD_KEY WHERE UserID = 16178 

另一种不涉及到结果列的方法是简单地将date的date部分归零,因此2016-07-132016-07-16都是2016-07-01 – 这样做他们按月平均。

如果你有一个date (不是datetime )的值,那么你可以直接将它清零:

 SELECT DATEADD( day, 1 - DATEPART( day, [Date] ), [Date] ), COUNT(*) FROM [Table] GROUP BY DATEADD( day, 1 - DATEPART( day, [Date] ), [Date] ) 

如果您有datetime值,则需要使用CONVERT删除时间部分:

 SELECT DATEADD( day, 1 - DATEPART( day, [Date] ), CONVERT( date, [Date] ) ), COUNT(*) FROM [Table] GROUP BY DATEADD( day, 1 - DATEPART( day, [Date] ), CONVERT( date, [Date] ) ) 

现在,您的查询仅显式查看年= 2010年的付款,但是,我认为您的1月/ 2月/ 3月实际上代表了2009年。如果是,则需要针对该情况进行调整。 不要重新查询每列的总和值,只需要以月份为单位的date差异条件。 把其余的放在WHERE子句中。

 SELECT SUM( case when DateDiff(m, PaymentDate, @start) = 0 then Amount else 0 end ) AS "Apr", SUM( case when DateDiff(m, PaymentDate, @start) = 1 then Amount else 0 end ) AS "May", SUM( case when DateDiff(m, PaymentDate, @start) = 2 then Amount else 0 end ) AS "June", SUM( case when DateDiff(m, PaymentDate, @start) = 3 then Amount else 0 end ) AS "July", SUM( case when DateDiff(m, PaymentDate, @start) = 4 then Amount else 0 end ) AS "Aug", SUM( case when DateDiff(m, PaymentDate, @start) = 5 then Amount else 0 end ) AS "Sep", SUM( case when DateDiff(m, PaymentDate, @start) = 6 then Amount else 0 end ) AS "Oct", SUM( case when DateDiff(m, PaymentDate, @start) = 7 then Amount else 0 end ) AS "Nov", SUM( case when DateDiff(m, PaymentDate, @start) = 8 then Amount else 0 end ) AS "Dec", SUM( case when DateDiff(m, PaymentDate, @start) = 9 then Amount else 0 end ) AS "Jan", SUM( case when DateDiff(m, PaymentDate, @start) = 10 then Amount else 0 end ) AS "Feb", SUM( case when DateDiff(m, PaymentDate, @start) = 11 then Amount else 0 end ) AS "Mar" FROM Payments I JOIN Live L on I.LiveID = L.Record_Key WHERE Year = 2010 AND UserID = 100