计算年距离数据透视SQL

时间:2016-11-09 02:10:30

标签: sql sql-server sql-server-2008-r2

我有下表:

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

所以问题是,如何才能获得最新一年减去去年与最新一年减去最年份之间的距离......?

有没有人对此有所了解?
谢谢。

2 个答案:

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