2011-12-01 209 views
38

我有一個具有此架構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和嵌套選擇,但都沒有給我我想要的。這是我最接近的我的想法:

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 

但我只是得到空值,當我應該得到的價值。我錯過了什麼嗎?

+0

您是否試圖將錶轉換爲按年份/月顯示列,並在其下使用userid進行付款? – William

+0

爲什麼您的UserID = 16178中的where子句與子查詢where子句中的UserID = 100不同?另外,1月,2月和3月的最後3個子查詢分別是從4月份的9月份,10月份和11月份的月份差異? –

+0

可能的重複[如何從日期字段使用sql按月分組](http://stackoverflow.com/questions/14565788/how-to-group-by-mon-month-from-date-field-using-sql) – kurast

回答

84
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 
+5

DatePart是我需要的。謝謝。 – Echilon

+0

只需在MySql中使用逗號,就像這個'按年份(日期),月份(日期)組'一樣' – simo

+0

爲了可讀性而選擇第二個答案。 –

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

應該是...

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

你擁有的是一個2010除以4,然後按1,然後轉換到一個約會。這是1900-01-01第57.5天。

嘗試SELECT @start初始化後檢查這是否正確。

3

如果你需要頻繁地做到這一點,我可能會一個計算列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 
+0

是否有性能開銷?即使在低規格框中,SQL Server也可以每秒執行數百萬次'CONVERT(NVARCHAR(7),PaymentDate,120)'。我不確定使用計算列將會帶來什麼好處(除非您可能會將其編入索引) – NickG

0

現在查詢被明確地望着只支付了一年= 2010,但是,我想你的意思是你的1月/ 2月/ 3月實際上代表了2009年。如果是這樣,你需要對此稍微調整一下。不要重新查詢每列的總和值,只需要以月份爲單位的日期差異條件。將剩下的部分放在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 
11

限制NVARCHAR的尺寸至7,供給到轉換成只顯示「YYYY-MM」

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

的另一種方法,不涉及添加列到的結果,是隻需簡單地將日期的day組成部分清零,那麼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刪除時間OF-天部分:

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

我喜歡結合DATEADDDATEDIFF功能是這樣的:

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

總之,這兩個函數爲零時的日期分量比指定的日期部分較小(即MONTH在這個例子中)。

您可以將datepart位更改爲YEARWEEK,DAY等......這是非常方便的。你原來的SQL查詢會看起來像這樣(我不能測試它,因爲我沒有你的數據集,但它應該把你放在正確的軌道上)。

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 

一兩件事:在Month列的類型是DateTime這也是一個很好的優勢,如果你需要進一步處理的數據或將其映射.NET對象爲例。