SQL

时间:2018-05-18 22:57:26

标签: sql sql-server tsql

我试图通过在SQL中循环滚动平均来创建平滑函数。我目前的非循环方法代码如下:

CREATE TABLE #Input ( 
         PartitionID  int
       , TimeID     int
       , Quantity float );

INSERT INTO #Input
  VALUES
   ( 1, 1, 2 ),
   ( 1, 2, 4 ),
   ( 1, 3, 6 ),
   ( 1, 4, 16 ),
   ( 2, 4, 6 ),
   ( 2, 5, 1 ),
   ( 2, 6, 9 ),
   ( 2, 7, 2 );

SELECT *
  FROM #Input;

-- Actual code
UPDATE i
  SET i.Quantity = i2.c
  FROM #Input i
       JOIN ( SELECT PartitionID AS a
                   , TimeID AS b
                   , AVG(Quantity) OVER(Partition BY PartitionID ORDER BY TimeID ASC ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING) AS c
                FROM #Input
            ) i2
               ON i2.a = i.PartitionID
                  AND i2.b = i.TimeID;
-- /Actual code

SELECT *
  FROM #Input;

我想创建这个循环,以便每个分区的第一行引用最后一行和反之。有什么想法吗?

编辑: 所需的输出是:

1    1    7.33
1    2    4
1    3    8.66
1    4    8
2    4    3
2    5    5.33
2    6    4
2    7    5.66

1 个答案:

答案 0 :(得分:1)

这确实是一个非常有趣的问题。我所做的是尝试通过为每个PartitionID组添加两行来扩展原始表,一行具有max(TimeID)+1,另一行具有min(TimeID)-1,而[Quantity]值恰好相反。 例如,对于PartitionID = 1,我将添加两行,将原来的四行分为六行,如下所示(添加第一行和后两行)

( 1, 0, 16 )  
( 1, 1, 2 ),
( 1, 2, 4 ),
( 1, 3, 6 ),
( 1, 4, 16 ),
( 1, 5, 2 )

整个查询如下:

--drop table #input;
CREATE TABLE #Input ( 
         PartitionID  int
       , TimeID     int
       , Quantity float );

INSERT INTO #Input
  VALUES[![enter image description here][1]][1]
   ( 1, 1, 2 ),
   ( 1, 2, 4 ),
   ( 1, 3, 6 ),
   ( 1, 4, 16 ),
   ( 2, 4, 6 ),
   ( 2, 5, 1 ),
   ( 2, 6, 9 ),
   ( 2, 7, 2 );

select * from #Input;

   ; with c as (
                select partitionid, min_timeid = min(timeid), max_timeid = max(timeid)
                from #Input
                group by partitionid
               )
, c2 as (
            select c.PartitionID, TimeID= c.max_timeid+c.min_timeid-i.TimeID + case i.TimeID when c.max_timeid then -1 else 1 end , i.Quantity
            from c
            inner join #input i
            on c.partitionid = i.PartitionID
            and i.TimeID in (c.max_timeid, c.min_timeid)
            union
            select * from #Input
)
update i 
set i.Quantity = i2.c
from #Input i
inner join ( SELECT PartitionID AS a
                   , TimeID AS b
                   , AVG(Quantity) OVER(Partition BY PartitionID ORDER BY TimeID ASC ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING) AS c
                FROM c2
            ) i2
               ON i2.a = i.PartitionID
                  AND i2.b = i.TimeID;

SELECT * from #input;

最终结果是

enter image description here