Mar1009
Mar1009

Reputation: 811

How to get result from dynamic grouping

Based on two inputs - date (any date from calendar) and period of date (like Year,month or week) result should aggregate data:

Based on the inputs the data in @calenderDate and @period result should be aggregated, for example; when @period is given as YEAR then it should aggregate results based on the year alone,

when @period is given as MONTH then it should aggregate results based on that year and all the month in given year,

when @period is given as WEEK then it should aggregate results based on that year and the specific month and all the days (between first day and last day of the given week) in that specific week

I have used dynamic grouping using CASE statement and managed to get desired result for the @period = YEAR, but not for other two inputs i.e. @period = MONTH and WEEK

Here is the sample DDL;

CREATE TABLE [dbo].[transferTable](
    [ID] [bigint] IDENTITY(1000,1) NOT NULL,
    [transferDateTime] [datetime] NOT NULL,
    [transferAmount] [money] NOT NULL
) ON [PRIMARY]

GO
SET IDENTITY_INSERT [dbo].[transferTable] ON 

GO
INSERT [dbo].[transferTable] ([ID], [transferDateTime], [transferAmount]) VALUES (1000, CAST(0x0000AA2C0110897B AS DateTime), 10.0000)
GO
INSERT [dbo].[transferTable] ([ID], [transferDateTime], [transferAmount]) VALUES (1001, CAST(0x0000AA2D00F0AA50 AS DateTime), 151.0000)
GO
INSERT [dbo].[transferTable] ([ID], [transferDateTime], [transferAmount]) VALUES (1002, CAST(0x0000A8850110897B AS DateTime), 10.0000)
GO
INSERT [dbo].[transferTable] ([ID], [transferDateTime], [transferAmount]) VALUES (1003, CAST(0x0000AA0E0121043B AS DateTime), 151.0000)
GO
SET IDENTITY_INSERT [dbo].[transferTable] OFF
GO

here is my code :


DECLARE @calenderDate DATETIME2(0) = '2019-04-12'
DECLARE @period varchar(20) = 'MONTH'

DECLARE @year varchar(10) =  DATEPART(YEAR,@calenderDate) 
DECLARE @month varchar(10) =  DATEPART(MONTH,@calenderDate)
DECLARE @week varchar(10) =  DATEPART(WEEK,@calenderDate) 

select case when @period = 'YEAR' then DATEPART(YEAR,transferDateTime)
            when @period = 'MONTH' then DATEPART(MONTH,transferDateTime)
            when @period = 'WEEK' then DATEPART(WEEKDAY,transferDateTime)
 end as period, 
     COUNT (t.transferAmount) as volOfTxns,
     SUM (t.transferAmount) as ValueOfTxns
from transferTable t
where 
     ( 
      (DATEPART(YEAR,t.transferDateTime) = @year) OR 
      (DATEPART(YEAR,t.transferDateTime) = @year AND DATEPART(MONTH,t.transferDateTime) = @month)
      )

group by case when @period = 'YEAR' then DATEPART(YEAR,transferDateTime)
              when @period = 'MONTH' then DATEPART(MONTH,transferDateTime)
              when @period = 'WEEK' then DATEPART(WEEKDAY,transferDateTime)
          end

When @calenderDate = ‘2019-04-12’ and @period = ‘YEAR’ then it should show,

period  volOfTxns   ValueOfTxns
2019    3   302.00

When @calenderDate = ‘2019-04-12’ and @period = ‘MONTH then it should show,

period  volOfTxns   ValueOfTxns
4   2   161.00

Likewise when @calenderDate = ‘2019-03-12’ and @period = ‘MONTH then it should show,

period  volOfTxns   ValueOfTxns
3   1   151.00

When @calenderDate = ‘2019-04-12’ and @period = ‘WEEK then it should show,

period  volOfTxns   ValueOfTxns
11           1             10
12           1             151

Upvotes: 0

Views: 40

Answers (2)

Matt
Matt

Reputation: 2869

It would be a case of modifying your where clause to only include the rows that match the period in which you are looking at. Your previous code was only filtering correctly to the year in which you were looking at.

DECLARE @calenderDate DATETIME2(0) = '2019-04-12'
DECLARE @period varchar(20) = 'MONTH'

DECLARE @year varchar(10) =  DATEPART(YEAR,@calenderDate) 
DECLARE @month varchar(10) =  DATEPART(MONTH,@calenderDate)
DECLARE @week varchar(10) =  DATEPART(WEEK,@calenderDate) 

select case when @period = 'YEAR' then DATEPART(YEAR,transferDateTime)
            when @period = 'MONTH' then DATEPART(MONTH,transferDateTime)
            when @period = 'WEEK' then DATEPART(WEEKDAY,transferDateTime)
 end as period, 
     COUNT (t.transferAmount) as volOfTxns,
     SUM (t.transferAmount) as ValueOfTxns
from transferTable t
where 

      CASE 
            WHEN @period = 'WEEK' THEN 
                CASE 
                    WHEN DATEPART(YEAR, t.transferDateTime) = @year 
                        AND DATEPART(MONTH, t.TransferDateTime) = @month
                        AND DATEPART(WEEK, t.transferDateTime) = @week
                    THEN 1
                    ELSE 0 
                END
            WHEN @period = 'MONTH' THEN
                CASE 
                    WHEN DATEPART(YEAR, t.transferDateTime) = @year 
                        AND DATEPART(MONTH, t.TransferDateTime) = @month
                    THEN 1
                    ELSE 0 
                END
            WHEN @period = 'YEAR' THEN
                CASE 
                    WHEN DATEPART(YEAR, t.transferDateTime) = @year 
                    THEN 1
                    ELSE 0 
                END
            ELSE 0
        END = 1

group by case when @period = 'YEAR' then DATEPART(YEAR,transferDateTime)
              when @period = 'MONTH' then DATEPART(MONTH,transferDateTime)
              when @period = 'WEEK' then DATEPART(WEEKDAY,transferDateTime)
          end

The above is an example and there are many shorter ways of doing this, however I've done it like the above to show the logic a bit better.

Upvotes: 1

Squirrel
Squirrel

Reputation: 24792

change your WHERE clause to below

where   (
        (@period = 'YEAR'   AND DATEPART(YEAR,t.transferDateTime) = @year)
    OR  (@period = 'MONTH'  AND DATEPART(MONTH,t.transferDateTime) = @month)
    OR  (@period = 'WEEK'   AND DATEPART(WEEK,t.transferDateTime) = @week)
    )

On the WEEK, I am not sure you wanted WEEK or WEEKDAY, as you reference both in your query. And not sure why there are 2 rows in your expected result for WEEK

Upvotes: 1

Related Questions