2011-12-01 18 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 

しかし、値を取得する必要がありますが、私はちょうどnullsを取得します。何か不足していますか?

+0

あなたはそれの下でユーザーIDでの支払いの合計で年/月で列を表示するテーブルを旋回するようにしようとしていますか? – William

+0

はなぜ句あなたのサブクエリでユーザーID = 100とは別のwhere句でユーザーID = 16178のでしょうか?また月、2月と月の最後の3つのサブクエリは、それぞれ本当に4月9日、10、および11からその月の違いがありますか? –

+0

[月をSQLで日付フィールドからグループ化する方法](http://stackoverflow.com/questions/14565788/how-to-group-by-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で 'year(date)、month(date) 'のようにコンマを使用するだけです。 – simo

+0

可読性のために2番目の答えに優先します。 –

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

はする必要があります...

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

あなたが変換した後、その後1により、4で2010を分割されている1日付に。 1900年1月1日から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

にあり、結果に列を追加する伴わない唯一の「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

別のアプローチを示すように変換するために、供給、7にNVARCHARの大きさを制限日付の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を使用する必要があります日部分:

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) 

これらの2つの機能を合わせて、日付コンポーネントを小さくします。より指定した日付部分(つまり、この例ではMONTH)。

ビットをYEARWEEKDAYなどに変更できます。これは便利です。

あなたのオリジナルの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列はあなたがそのデータをプロセスを進めるか、それが例えばオブジェクト.NETマッピングする必要がある場合にも素敵な利点であるDateTimeとして入力されます。