SQL中的循环滚动平均

SQL中的循环滚动平均,sql,sql-server,tsql,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

我试图通过循环滚动平均值,在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

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

整个查询如下:

--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;
最终结果是


您使用的是什么数据库管理系统?请编辑标签。样本数据和期望的结果将非常有帮助。@stickybit我。。。不确定。我认为我们使用Transact-SQL,但数据库管理并不是我的专长。@GordonLinoff示例数据包含在代码中。我已经添加了一个期望的输出。这也是我的想法,尽管我不确定如何最好地实现它。如果平均值的宽度是任意的,这个方法可以推广吗?我猜行:和I.TimeID(c.max\u-TimeID,c.min\u-TimeID)必须变成:和c.max\u-TimeID-@radius和c.max\u-TimeID之间的I.TimeID,或者是c.min\u-TimeID和c.min\u-TimeID+radius之间的I.TimeID。同样,这个方法假设TimeID是连续的。如果可能的话,我宁愿只要求他们sequential@Sinnombre,不太理解你的评论。但有一件事我要纠正你,对于解决方案,没有假设TimeID应该是连续的。你是对的,我在看c2 select语句中硬编码的“1”和“-1”,但当然,考虑到它们适用于max和min,它们不会关心连续性。我的另一个问题是关于更改平均值的宽度,例如,平均值超过5点,或7点,或其他直到运行时才知道的任意数字。该方法是否可以推广到不使用for循环的情况下进行解释?是的,该解决方案可以推广到2N+1点(其中N是1,2,3,…)。如果您修改您的问题(当然是使用示例数据),我可以修改我的解决方案,使其通用化。:-)
--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;