mssql接下来的12个月动态地连接年份

时间:2015-12-28 18:28:26

标签: sql-server date

我在下面有这个查询,我正在检索一些数据并按月显示。想要使这个动态,所以我没有任何硬编码的日期。在我的查询中声明和使用某些日期变量的最有效方法是什么?

SELECT Description, ComponentDescription,
SUM(CASE WHEN FMonth+CAST(YearOrder AS NVARCHAR(10)) = 'Dec2015' THEN    Forecast ELSE 0 END ) AS 'Dec2015',
SUM(CASE WHEN FMonth+CAST(YearOrder AS NVARCHAR(10)) = 'Jan2016' THEN Forecast ELSE 0 END ) AS 'Jan2016',
SUM(CASE WHEN FMonth+CAST(YearOrder AS NVARCHAR(10)) = 'Feb2016' THEN Forecast ELSE 0 END ) AS 'Feb2016',
SUM(CASE WHEN FMonth+CAST(YearOrder AS NVARCHAR(10)) = 'Mar2016' THEN Forecast ELSE 0 END ) AS 'Mar2016',
SUM(CASE WHEN FMonth+CAST(YearOrder AS NVARCHAR(10)) = 'Apr2016' THEN Forecast ELSE 0 END ) AS 'Apr2016',
SUM(CASE WHEN FMonth+CAST(YearOrder AS NVARCHAR(10)) = 'May2016' THEN Forecast ELSE 0 END ) AS 'May2016',
SUM(CASE WHEN FMonth+CAST(YearOrder AS NVARCHAR(10)) = 'Jun2016' THEN Forecast ELSE 0 END ) AS 'Jun2016',
SUM(CASE WHEN FMonth+CAST(YearOrder AS NVARCHAR(10)) = 'Jul2016' THEN Forecast ELSE 0 END ) AS 'Jul2016',
SUM(CASE WHEN FMonth+CAST(YearOrder AS NVARCHAR(10)) = 'Aug2016' THEN Forecast ELSE 0 END ) AS 'Aug2016',
SUM(CASE WHEN FMonth+CAST(YearOrder AS NVARCHAR(10)) = 'Sep2016' THEN Forecast ELSE 0 END ) AS 'Sep2016',
SUM(CASE WHEN FMonth+CAST(YearOrder AS NVARCHAR(10)) = 'Oct2016' THEN Forecast ELSE 0 END ) AS 'Oct2016',
SUM(CASE WHEN FMonth+CAST(YearOrder AS NVARCHAR(10)) = 'Nov2016' THEN Forecast ELSE 0 END ) AS 'Nov2016',
SUM(CASE WHEN FMonth+CAST(YearOrder AS NVARCHAR(10)) = 'Dec2016' THEN Forecast ELSE 0 END ) AS 'Dec2016'

FROM (SELECT Description, ComponentDescription, FMonth, Forecast, YearOrder FROM Table1 ) AS NormalizedData
GROUP BY Description, ComponentDescription
ORDER BY Description, ComponentDescription;

提前致谢。

1 个答案:

答案 0 :(得分:0)

编辑:跟进r.e.注释“添加另一列(总计)将水平求和。即对于项目x,我想显示所有月份的总和。我怎样才能实现这一点?”

让我们试试这个查询,请参阅下面的/ * new * / comment以获取AllMonths总列数。该子查询有一个where子句,它忽略了year&所以sum(totalForecast)应该为每个Description + ComponentDescription生成总计(分别为临时列d和cd)。

更改:修复了子查询where子句中的临时列名称(之前是y.c = x.c,更改为y.d = x.d,只是一个错字)。

修正了子查询(从select * from monthlyCommissions y“更改为”just“从monthlyCommissions中选择totalForecast); select *只是错误,需要一个值才能工作(这是我不测试代码时会发生的情况)。

修改后的查询:

     with monthlyCommissions ( d, cd, YearOrder, FMonth,  totalForecast ) as ( 
       -- Column order has to match in the both the with...as... & this nested select.
       -- I try keep names similar to simplify editing.
       select Description, ComponentDescription, YearOrder, FMonth,  sum(Forecast) as totalForecast
       from Table1
       -- I added the where clause to limit results to Dec2015 or anything in 2016.
       where (YearOrder = 2015 and FMonth = 'Dec')
          or (YearOrder = 2016)
       group by Description, ComponentDescription, YearOrder, FMonth
     )
     select Description
          , ComponentDescription
          , count(*) as entries
/* new */ , (select sum(totalForecast) from monthlyCommissions y where y.d = x.d and y.cd = x.cd ) as AllMonths
          , (select totalForecast from monthlyCommissions y where y.d = x.d and y.cd = x.cd and y.YearOrder = 2015 y.FMonth = 'Dec') as prev_Dec
          , (select totalForecast from monthlyCommissions y where y.d = x.d and y.cd = x.cd and y.YearOrder = 2016 y.FMonth = 'Jan') as Jan
          , (select totalForecast from monthlyCommissions y where y.d = x.d and y.cd = x.cd and y.YearOrder = 2016 y.FMonth = 'Feb') as Feb
          ...etc...
          , (select totalForecast from monthlyCommissions y where y.d = x.d and y.cd = x.cd and y.YearOrder = 2016 y.FMonth = 'Dec') as Dec
     from monthlyCommissions x
     group by d, cd
     order by d, cd

原始答案:

如果你这样开始怎么办? 警告:未经测试的代码。我附近没有一个sqlserver实例来测试它,但它应该指向一个有用的(如果不是最佳的)方向。

无论如何,这将摆脱许多硬编码值:

请注意,我假设原始表将FMonth作为char-like,将YearOrder作为某种整数。

with monthlyCommissions ( Description, ComponentDescription, YearOrder, FMonth,  totalForecast ) as ( 
  -- Column order has to match in the both the with...as... & this nested select.
  -- I try keep names the same to simplify editing.
  select Description, ComponentDescription, YearOrder, FMonth,  sum(Forecast) as totalForecast
  from Table1
  -- I added the where clause to limit results to Dec2015 or anything in 2016.
  where (YearOrder = 2015 and FMonth = 'Dec')
     or (YearOrder = 2016)
  group by Description, ComponentDescription, FMonth, YearOrder
)
select * from monthlyCommissions
order by Description, ComponentDescription, FMonth, YearOrder

我使用with..as ..语法的目的是在'monthlyCommissions'中设置一个临时结果集,您可以使用它来生成当前查询所做的结果集类型。 (如果您之前没有使用过“with ... as ..”样式,请先从itslef执行内部选择,看看它的作用。)

假设上面的代码有效,让我们通过将每个Description + ComponentDescription组合合并到单行中来制作看起来更像原始查询的内容:

with monthlyCommissions ( Description, ComponentDescription, YearOrder, FMonth,  totalForecast ) as ( 
  -- Column order has to match in the both the with...as... & this nested select.
  -- I try keep names the same to simplify editing.
  select Description as Description, ComponentDescription, YearOrder, FMonth,  sum(Forecast) as totalForecast
  from Table1
  -- I added the where clause to limit results to Dec2015 or anything in 2016.
  where (YearOrder = 2015 and FMonth = 'Dec')
     or (YearOrder = 2016)
  group by Description, ComponentDescription, FMonth, YearOrder
)
select Description
     , ComponentDescription
     , count(*) as entries
     , (select * from monthlyCommissions y where y.c = x.c and y.cd = x.cd and y.YearOrder = 2015 y.FMonth = 'Dec') as prev_Dec
     , (select * from monthlyCommissions y where y.c = x.c and y.cd = x.cd and y.YearOrder = 2016 y.FMonth = 'Jan') as Jan
     , (select * from monthlyCommissions y where y.c = x.c and y.cd = x.cd and y.YearOrder = 2016 y.FMonth = 'Feb') as Feb
     ...etc...
     , (select * from monthlyCommissions y where y.c = x.c and y.cd = x.cd and y.YearOrder = 2016 y.FMonth = 'Dec') as Dec
from monthlyCommissions x
group by Description, ComponentDescription
order by Description, ComponentDescription

您可以通过多种方式参数化目标年份。

最简单的可能是使用T-SQL变量表示法......

declare @targetYear int = 2016
with monthlyCommissions ( Description, ComponentDescription, YearOrder, FMonth,  totalForecast ) as ( 
  -- Column order has to match in the both the with...as... & this nested select.
  -- I try keep names the same to simplify editing.
  select Description, ComponentDescription as cd, YearOrder, FMonth,  sum(Forecast) as totalForecast
  from Table1
  -- Adjusted where clause to pay attention to @targetYear
  where (YearOrder + 1 = @targetYear and FMonth = 'Dec')
     or (YearOrder = @targetYear )
  group by Description, ComponentDescription, FMonth, YearOrder
)
select Description
     , ComponentDescription
     , count(*) as entries
     , (select * from monthlyCommissions y where y.c = x.c and y.cd = x.cd and y.YearOrder + 1 = @targetYear y.FMonth = 'Dec') as prev_Dec
     , (select * from monthlyCommissions y where y.c = x.c and y.cd = x.cd and y.YearOrder = @targetYear y.FMonth = 'Jan') as Jan
     , (select * from monthlyCommissions y where y.c = x.c and y.cd = x.cd and y.YearOrder = @targetYear y.FMonth = 'Feb') as Feb
     ...etc...
     , (select * from monthlyCommissions y where y.c = x.c and y.cd = x.cd and y.YearOrder = @targetYear y.FMonth = 'Dec') as Dec
from monthlyCommissions x
group by Description, ComponentDescription
order by Description, ComponentDescription

请注意,我在Where子句中做了一些奇怪的事情。 具体来说,我正在做这样的事情:

where YearOrder + 1 = @targetYear

我记得如果你尝试在表达式中修改@targetYear,sqlserver会抱怨:例如我希望这种(直观的方式)能够引发问题:

where YearOrder = @targetYear - 1

您还可以设置两个变量...(如果我有任何错误,我必须测试语法并更新它):

declare @targetYear int = 2016
declare @priorYear int = @targetYear - 1

我确信还有其他更简洁的方法可以做到这一点,但我希望这有点帮助。