如何从动态分组中获取结果

时间:2019-05-14 07:45:11

标签: sql-server tsql group-by sql-server-2012

基于两个输入-日期(日历中的任何日期)和日期期限(如年,月或周),结果应汇总数据:

基于输入,应将@calenderDate和@period结果中的数据进行汇总, 例如; 如果将@period指定为YEAR,则应仅基于年份汇总结果

当@period被指定为MONTH时,它应基于该年和给定年份的所有月份汇总结果,

当@period设为WEEK时,它应基于该年和特定月份以及该特定周中的所有天(给定周的第一天和最后一天之间)汇总结果。

我已经使用CASE语句进行了动态分组,并设法为@period = YEAR获得了期望的结果,但没有为其他两个输入(即@period = MONTH和WEEK)获得期望的结果

这里是示例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

这是我的代码:


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

当@calenderDate ='2019-04-12'和@ period ='YEAR'时,它应该显示,

period  volOfTxns   ValueOfTxns
2019    3   302.00

当@calenderDate ='2019-04-12'和@ period ='MONTH时,它应该显示,

period  volOfTxns   ValueOfTxns
4   2   161.00

同样,当@calenderDate =‘2019-03-12’和@period =‘MONTH时,应该显示

period  volOfTxns   ValueOfTxns
3   1   151.00

当@calenderDate ='2019-04-12'和@ period ='WEEK时,它应该显示,

period  volOfTxns   ValueOfTxns
11           1             10
12           1             151

2 个答案:

答案 0 :(得分:1)

将您的WHERE子句更改为以下

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)
    )

WEEK上,我不确定您是否想要WEEKWEEKDAY,因为您在查询中都引用了两者。而且不确定为什么WEEK

的预期结果中有两行

答案 1 :(得分:1)

在这种情况下,可能需要修改where子句,使其仅包含与您要查看的时间段匹配的行。您之前的代码只能正确过滤到您所看的年份。

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

上面是一个示例,有许多更短的方法可以做到这一点,但是我已经像上面那样做,以更好地说明逻辑。