我在下面有这个查询,我正在检索一些数据并按月显示。想要使这个动态,所以我没有任何硬编码的日期。在我的查询中声明和使用某些日期变量的最有效方法是什么?
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;
提前致谢。
答案 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
我确信还有其他更简洁的方法可以做到这一点,但我希望这有点帮助。