2011-12-01 53 views
38

Tôi có một bảng trong đó có schema nàySQL Server Group By Tháng

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 

Tôi đang cố gắng để có được một công việc truy vấn trong đó cho thấy tổng số của mỗi tháng. Cho đến nay tôi đã thử DateDiff và các lựa chọn lồng nhau, nhưng không mang lại cho tôi những gì tôi muốn. Đây là điều gần nhất tôi nghĩ:

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 

Nhưng tôi chỉ nhận được null khi tôi nhận được giá trị. Tui bỏ lỡ điều gì vậy?

+0

Bạn đang cố gắng xoay vòng bảng để hiển thị các cột theo năm/tháng với tổng số tiền thanh toán bởi userid dưới nó? – William

+0

Tại sao UserID của bạn = 16178 trong mệnh đề where khác với UserID = 100 trong mệnh đề subquery của bạn ở đâu? Ngoài ra 3 truy vấn phụ cuối cùng cho tháng 1, tháng 2 và tháng 3, là sự khác biệt tháng của họ so với tháng 4 thực sự là 9, 10 và 11 tương ứng? –

+0

Có thể trùng lặp của [Cách nhóm theo tháng từ trường Ngày bằng cách sử dụng sql] (http://stackoverflow.com/questions/14565788/how-to-group-by-month-from-date-field-using-sql) – kurast

Trả lời

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

Bạn cũng có thể thử:

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 là thứ tôi cần. Cảm ơn. – Echilon

+0

Chỉ cần sử dụng dấu phẩy trong MySql như thế này 'nhóm theo năm (ngày), tháng (ngày)' – simo

+0

Ưu tiên đối với câu trả lời thứ hai cho khả năng đọc. –

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

Nên ...

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

Một bạn có được chia 2010 4, sau đó bằng 1, sau đó chuyển đổi đến một ngày. Đó là ngày thứ 57.5 từ ngày 1900-01-01.

Hãy thử SELECT @start sau khi khởi tạo để kiểm tra xem điều này có đúng không.

3

Nếu bạn cần phải làm điều này thường xuyên, tôi sẽ có thể thêm một cột tính PaymentMonth để bàn:

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

Nó vẫn kiên trì và lưu trữ trong bảng - vì vậy có thực sự không có chi phí thực hiện truy vấn nó. Đó là giá trị INT 4 byte - vì vậy chi phí không gian tối thiểu cũng vậy.

khi bạn đã có, bạn có thể đơn giản hóa truy vấn của bạn là một cái gì đó dọc theo dòng:

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

Có phí hoạt động không? Ngay cả trên một hộp spec thấp, SQL Server có thể làm vài triệu 'CONVERT (NVARCHAR (7), PaymentDate, 120)' mỗi giây. Tôi không chắc chắn bằng cách sử dụng một cột tính toán sẽ cung cấp bất kỳ lợi ích (trừ khi bạn đã lập chỉ mục nó có lẽ) – NickG

0

Bây giờ câu hỏi của bạn là rõ ràng nhìn vào chỉ thanh toán cho năm = 2010, tuy nhiên, tôi nghĩ rằng bạn có nghĩa là để có Jan/Feb/Mar của bạn thực sự đại diện 2009. Nếu vậy, bạn sẽ cần phải điều chỉnh này một chút cho trường hợp đó. Đừng giữ lại các giá trị tổng cho mỗi cột, chỉ là điều kiện của sự khác biệt ngày tháng. Đặt phần còn lại trong mệnh đề 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

Giới hạn kích thước của NVARCHAR đến 7, cung cấp cho CONVERT để chỉ hiển thị "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

cách tiếp cận khác, điều đó không liên quan đến việc bổ sung thêm các cột vào kết quả, là để chỉ đơn giản là không có thành phần day của ngày, do đó, 2016-07-132016-07-16 cả hai sẽ là 2016-07-01 - do đó làm cho chúng bằng nhau theo tháng.

Nếu bạn có một (không phải là một datetime) giá trị date, sau đó bạn có thể không trực tiếp:

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

Nếu bạn có datetime giá trị, bạn sẽ cần phải sử dụng CONVERT để loại bỏ thời gian-of- phần trong ngày:

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

tôi thích kết hợp DATEADDDATEDIFF chức năng như thế này:

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

Cùng với nhau, hai hàm này không có thành phần ngày nhỏ hơn so với ngày được chỉ định cụ thể (tức là MONTH trong ví dụ này).

Bạn có thể thay đổi datepart bit thành YEAR, WEEK, DAY, v.v ... rất tiện dụng.

Truy vấn SQL ban đầu của bạn sẽ trông giống như thế này (tôi không thể kiểm tra nó vì tôi không có tập dữ liệu của bạn, nhưng nó sẽ đưa bạn đi đúng hướng).

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 

Một điều nữa: cột Month được gõ như một DateTime đó cũng là một lợi thế tốt đẹp nếu bạn cần để tiếp tục quá trình đó dữ liệu hay bản đồ nó NET đối tượng ví dụ.