我有下表:
InspectYear
pos#
数据将始终每两年添加一次
我想计算每个declare @inspectyear as nvarchar(max), @calc as nvarchar(max), @query as nvarchar(max);
set @inspectyear = STUFF((select distinct ',' + quotename(InspectYear) from ##t2 c
for XML path(''), type).value('.','NVARCHAR(MAX)'),1,1,'')
select @calc = ', ' + quotename(Max(InspectYear)) + ' - ' + quotename(Max(InspectYear)-2)
+ ' as Calc1, ' + quotename(Max(InspectYear)) + ' - ' + quotename(min(InspectYear))
+ ' as Calc2' from #t2;
set @query =
';with data as
(
select inspectyear,
partno, Pos, number
from #t2
unpivot
(
number
for Pos in ([Pos1], [Pos2], [Pos3], [Pos4])
) unpvt
)
select * ' + @calc + ' into ##temp
from data
pivot
(
sum(number)
for inspectyear in (' + @inspectyear + ')
) pvt
order by partno';
exec sp_executesqk @query = @query;
select * from ##temp;
drop table ##temp;
列与上一年(Calc1)的最新值。也是具有最旧值(Calc2)的最新值。
然后,我有以下代码:
---------------------------------------------------------------------
Part Pos 2009 2011 2013 2015 Calc1 Calc2
---------------------------------------------------------------------
001 Pos1 8 9 8 10 2 2
001 Pos2 8 9 9 8 -1 0
001 Pos3 9 8 7 7 0 -2
001 Pos4 7 7 9 4 -5 -3
结果应该是:
Calc1 = (newest value on each pos# column - value on the previous year on each pos#) / distance from latest year until the previous year.
Calc2 = (newest value on each pos# column - value on the first year on each pos#) / distance from latest year until the first year.
我想修改Calc1和Calc2的计算,即:
---------------------------------------------------------------------
Part Pos 2009 2011 2013 2015 Calc1 Calc2
---------------------------------------------------------------------
001 Pos1 8 9 8 10 1 0.333
例如:
Calc1 2015 - 2013 = 2
上表中的年份距离为Calc2 2015 - 2009 = 6
{{1}}
所以问题是,如何才能获得最新一年减去去年与最新一年减去最年份之间的距离......?
有没有人对此有所了解?
谢谢。
答案 0 :(得分:1)
正如评论中所提到的,这里的简单解决方法是将@calc
变量更改为如下所示:
select @calc = ', (' + quotename(Max(InspectYear)) + ' - ' + quotename(Max(InspectYear)-2)
+ ') / 2.0 as Calc1, 1.0 * (' + quotename(Max(InspectYear)) + ' - ' + quotename(min(InspectYear))
+ ') / (' + cast(max(inspectyear) as char(4)) + '-' + cast(min(inspectyear) as char(4)) + ') as Calc2'
from #t2;
这将为您提供类似于此的输出:, ([2015] - [2013]) / 2.0 as Calc1, 1.0 * ([2015] - [2009]) / (2015-2009) as Calc2
答案 1 :(得分:0)
我把这个版本放在一起,但它绝对可以优化。
为了让您知道发生了什么,请将其运行到(并包括)评论部分。然后轮流评论部分以获得结果。
CREATE TABLE #t2
( InspectYear int
,Part [nchar](5)
,Pos1 int
,Pos2 int
,Pos3 int
,Pos4 int
)
Insert Into #t2
Values
('2009','001','8','8','9','7'),
('2009','002','9','7','8','6'),
('2011','001','9','9','8','7'),
('2011','002','7','8','6','8'),
('2013','001','8','9','7','9'),
('2013','002','7','7','8','8'),
('2015','001','10','8','7','4'),
('2015','002','7','6','9','8');
DECLARE @cols AS NVARCHAR(MAX),
@count AS NVARCHAR(MAX),
@max AS NVARCHAR(MAX),
@query AS NVARCHAR(MAX);
SET @cols = STUFF((SELECT distinct ',' + QUOTENAME(c.InspectYear)
FROM #t2 c
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'');
SET @count = (Select COUNT(distinct InspectYear)-1 FROM #t2);
SET @max = (Select MAX(InspectYear) FROM #t2);
/* --TESTING & to see how this works
Select
inspectyear,
part,
Pos,
number,
Last_Value(Calc1)Over(Partition by Part,Pos Order by inspectyear ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) as Calc1,
Last_Value(Calc2)Over(Partition by Part,Pos Order by inspectyear ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) as Calc2
from (
select
inspectyear,
part,
Pos,
number,
CASE WHEN inspectyear=@max THEN
(number-LAG(number,1,0)Over(Partition by Part,Pos Order by inspectyear))
/(inspectyear-LAG(inspectyear,1,0)Over(Partition by Part,Pos Order by inspectyear)) END as Calc1,
CASE WHEN inspectyear=@max THEN
CAST((number-LAG(number,@count,0)Over(Partition by Part,Pos Order by inspectyear))as decimal(8,7))
/(inspectyear-LAG(inspectyear,@count,0)Over(Partition by Part,Pos Order by inspectyear)) END as Calc2
from #t2
unpivot
(
number
for Pos in ([Pos1], [Pos2], [Pos3], [Pos4])
) unpvt )t3
Order by Pos,Part,inspectyear
*/
set @query = 'SELECT Part,Pos, ' + @cols + ' , Calc1, Calc2 from
(
Select
inspectyear,
part,
Pos,
number,
Last_Value(Calc1)Over(Partition by Part,Pos Order by inspectyear ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) as Calc1,
Last_Value(Calc2)Over(Partition by Part,Pos Order by inspectyear ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) as Calc2
from (
select
inspectyear,
part,
Pos,
number,
CASE WHEN inspectyear=' + @max + ' THEN
(number-LAG(number,1,0)Over(Partition by Part,Pos Order by inspectyear))
/(inspectyear-LAG(inspectyear,1,0)Over(Partition by Part,Pos Order by inspectyear)) END as Calc1,
CASE WHEN inspectyear=' + @max + ' THEN
CAST((number-LAG(number,' + @count + ',0)Over(Partition by Part,Pos Order by inspectyear))as decimal(8,7))
/(inspectyear-LAG(inspectyear,' + @count + ',0)Over(Partition by Part,Pos Order by inspectyear)) END as Calc2
from #t2
unpivot
(
number
for Pos in ([Pos1], [Pos2], [Pos3], [Pos4])
) unpvt )t3
) x
pivot
(
SUM(number)
for inspectyear in (' + @cols + ')
) p
Order by Part,Pos'
execute(@query)