SQL Server Group By Month

前端 未结 7 1251
攒了一身酷
攒了一身酷 2020-12-13 01:53

I have a table which has this schema

ItemID    UserID    Year    IsPaid    PaymentDate  Amount
1         1         2009    0         2009-11-01  300
2                


        
相关标签:
7条回答
  • 2020-12-13 02:07

    Restrict the dimension of the NVARCHAR to 7, supplied to CONVERT to show only "YYYY-MM"

    SELECT CONVERT(NVARCHAR(7),PaymentDate,120) [Month], SUM(Amount) [TotalAmount]
    FROM Payments
    GROUP BY CONVERT(NVARCHAR(7),PaymentDate,120)
    ORDER BY [Month]
    
    0 讨论(0)
  • 2020-12-13 02:13

    Now your query is explicitly looking at only payments for year = 2010, however, I think you meant to have your Jan/Feb/Mar actually represent 2009. If so, you'll need to adjust this a bit for that case. Don't keep requerying the sum values for every column, just the condition of the date difference in months. Put the rest in the WHERE clause.

    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 讨论(0)
  • 2020-12-13 02:18
    DECLARE @start [datetime] = 2010/4/1;
    

    Should be...

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

    The one you have is dividing 2010 by 4, then by 1, then converting to a date. Which is the 57.5th day from 1900-01-01.

    Try SELECT @start after your initialisation to check if this is correct.

    0 讨论(0)
  • 2020-12-13 02:23
    SELECT CONVERT(NVARCHAR(10), PaymentDate, 120) [Month], SUM(Amount) [TotalAmount]
    FROM Payments
    GROUP BY CONVERT(NVARCHAR(10), PaymentDate, 120)
    ORDER BY [Month]
    

    You could also try:

    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
    
    0 讨论(0)
  • 2020-12-13 02:27

    I prefer combining DATEADD and DATEDIFF functions like this:

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

    Together, these two functions zero-out the date component smaller than the specified datepart (i.e. MONTH in this example).

    You can change the datepart bit to YEAR, WEEK, DAY, etc... which is super handy.

    Your original SQL query would then look something like this (I can't test it as I don't have your data set, but it should put you on the right track).

    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
    

    One more thing: the Month column is typed as a DateTime which is also a nice advantage if you need to further process that data or map it .NET object for example.

    0 讨论(0)
  • 2020-12-13 02:30

    If you need to do this frequently, I would probably add a computed column PaymentMonth to the table:

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

    It's persisted and stored in the table - so there's really no performance overhead querying it. It's a 4 byte INT value - so the space overhead is minimal, too.

    Once you have that, you could simplify your query to be something along the lines of:

    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 讨论(0)
提交回复
热议问题