web-dev-qa-db-ja.com

月別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 

ただし、値を取得する必要がある場合は、nullを取得するだけです。何か不足していますか?

45
Echilon
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
98
Dave Downs

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]
19
Martyn Davis

私はDATEADDDATEDIFF関数を次のように組み合わせることを好みます:

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

一緒に、これらの2つの関数は、指定されたdatepartよりも小さい日付コンポーネントsmaller -)(つまり、この例ではMONTH)。

datepart ビットを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

もう1つ:Month列はDateTimeとして入力されます。これは、たとえばそのデータをさらに処理したり、.NETオブジェクトをマップしたりする必要がある場合にも便利です。

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

あるべき...

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

あなたが持っているものは、2010を4で割った後、1で割ってから日付に変換しています。 1900-01-01から57.5日目です。

SELECT @start初期化後、これが正しいかどうかを確認します。

3
MatBailie

これを頻繁に行う必要がある場合は、おそらく計算列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 
3
marc_s

結果に列を追加することを伴わない別のアプローチは、日付のdayコンポーネントを単純にゼロにすることです。したがって、2016-07-13および2016-07-16は両方とも2016-07-01-したがって、月ごとに等しくします。

datedatetimeではない)値がある場合、直接ゼロにすることができます:

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] ) )
1
Dai

これで、クエリは明示的に年= 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
0
DRapp