2011-12-01 14 views
38

ben her ay için toplamlarını gösteren bir sorgu çalışma almak için çalışıyorumSQL Server Grubu tarafından Ay

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 

Bu şemayı olan bir tablo var. Şimdiye kadar DateDiff'i ve iç içe geçmiş seçimleri denedim, ama ne istediğimi bana vermiyor. Bu sanırım var en yakın olan:

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 

Ama değerler alma gerekirken ben sadece boş değerlere olsun. Bir şey mi eksik?

+0

Tabloyu, sütunları yıl/ay bazında göstermek için altından kullanıcı tarafından yapılan ödemeler toplamı ile dönmeye mi çalışıyorsunuz? – William

+0

Neden UserID = 16178, where yan tümcesinde alt maddede UserID = 100'den farklıdır? Ayrıca Jan, Feb ve Mar için son 3 alt sorgu, sırasıyla 9, 10 ve 11 no'lu Nisan aylarındaki aylık farkları mı? –

+0

Olası çoğaltılabilir [sql kullanarak Tarih alanından ay nasıl gruplanır] (http://stackoverflow.com/questions/14565788/how-to-group-by-month-from-date-field-using-sql) – kurast

cevap

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

Şunu da deneyebilirsiniz:

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'ın ihtiyacım olan şey. Teşekkürler. – Echilon

+0

Sadece MySql'deki virgülleri kullan bu gibi grup yıl (tarih), ay (tarih) ' – simo

+0

Okunabilirlik için ikinci cevabı tercih et. –

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

olmalı ...

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

sahip bir sonra, 1 ile ardından 4'e 2010 bölünmesi dönüştürmektedir bir tarihe. 1900-01-01 arası 57.5.

Bunun doğru olup olmadığını kontrol etmek için sıfırlamadan sonra SELECT @start deneyin. Sık sık bunu yapmak gerekiyorsa

3

, muhtemelen Tabloya bir bilgisayarlı sütun PaymentMonth eklersiniz:

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

Bu kalıcı ve tabloda depolanan - bu yüzden sorgulama herhangi bir performans havai gerçekten var. Bu bir 4 bayt INT değeridir - bu yüzden alan yükü de minimumdur. sen, sen çizgisinde bir şey olması Sorgunuzla basitleştirmek verebilecek sahip olduktan

: Ancak

Şimdi
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

Bir performans yükü var mı? Düşük bir spec kutusunda bile, SQL Server saniyede birkaç milyon 'CONVERT (NVARCHAR (7), PaymentDate, 120) yapabilir. Hesaplanmış bir sütun kullanmanın herhangi bir fayda sağlayacağından emin değilim (belki de bunu dizine eklemediyseniz) – NickG

0

sorgu açıkça yıl = 2010 sadece ödemeler bakıyor, sana gerekiyordu düşünüyorum Jan/Feb/Mar'ın 2009'u gerçekten temsil etmesini sağlayın. Eğer öyleyse, bu durum için biraz ayarlamalısınız. Her sütunun toplam değerlerini tutmaya devam etmeyin, sadece aylardaki tarih farkının durumu. Gerisini WHERE maddesine koyun.

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

etmek, sonuca sütunlar ekleyerek içermeyen sadece "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

başka bir yaklaşım göstermeye CONVERT verilen, 7 NVARCHAR boyutunu sınırla sadece day bileşeninin tarihini sıfırlamak için 2016-07-13 ve 2016-07-16 her ikisi de 2016-07-01 olacaktır;Bir date (bir datetime) değeri varsa

, o zaman doğrudan sıfır yapabilirsiniz: datetime değerleri varsa

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

, zaman-of kaldırmak için CONVERT kullanmanız gerekir gün kısmı:

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

böyle DATEADD ve DATEDIFF fonksiyonlarını birleştiren tercih:

Birlikte

GROUP BY DATEADD(MONTH, DATEDIFF(MONTH, 0, Created),0) 
, bu iki işlev sıfır üzerinden tarih bileşeni belirtilen DATEPART daha daha küçük (yani, Bu örnekte MONTH.

datepart biti, YEAR, WEEK, DAY, vb.

Özgün SQL sorgunuz böyle bir şeye benziyordu (veri kümene sahip olmadığım için bunu test edemiyorum, ancak sizi doğru yola koymalıyım).

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 

Bir şey daha: Month sütunu verileri sürecini ilerletmek ya da örneğin nesne .NET harita gerektiğinde de güzel bir avantajdır bir DateTime olarak yazılır.