获取T-SQL中列的运行平均值

时间:2015-04-15 17:43:37

标签: sql sql-server sql-server-2008 tsql

好的,我有一张桌子,在一列中我有一些数据,第二列是数据的平均值。实施例

id|Data|avg
1 |20  |20
2 |4   |12
3 |18  |14

如何使用T-SQL在插入时使用数据列的运行平均值填充avg列?

编辑:对不起,伙计,这实际上是我犯的一个愚蠢的错误。我以为我有SQL 2014,但在尝试了Stephan的代码并得到一些错误后,我回去确认并意识到我使用的是SQL 2008.对于错误的信息我很抱歉。我还更新了标签

4 个答案:

答案 0 :(得分:6)

在插入时,假设id是一个身份,而您只是放入data

insert into table t(id, data, avg)
    select @data, @data * (1.0 / n) + avg * (n - 1.0)/n
    from (select count(*) as cnt, avg(data) as avg
          from t
         ) t;

在SQL Server 2012+中,只需将其输出即可:

select t.*, avg(data) over (order by id) as cume_avg
from table t

在SQL Server 2012之前,您可以使用相关子查询或apply执行此操作:

select t.*,
       (select avg(data)
        from table t2
        where t2.id <= t.id
       ) as cume_avg 
from table t;

如果表格很大,表现可能会受到影响。但是,id, data上的索引会有所帮助。

答案 1 :(得分:5)

戈登·林诺夫(Gordon Linoff)插入了它。如果你想用触发器

触发方法

IF OBJECT_ID('myTable') IS NOT NULL
    DROP TABLE myTable;

CREATE TABLE myTable(ID INT, Data INT,[avg] INT);
GO

CREATE TRIGGER trg_running_avg ON myTable
INSTEAD OF INSERT
AS
BEGIN
    INSERT INTO myTable
        SELECT ID,Data,AVG(Data) OVER (ORDER BY ID ROWS UNBOUNDED PRECEDING)
        FROM inserted
END

INSERT INTO myTable(ID,Data)
VALUES  (1,20),(2,4),(3,18)

SELECT *
FROM myTable

查看方法

CREATE VIEW vw_average
AS
SELECT ID,Data,AVG(Data) OVER (ORDER BY ID ROWS UNBOUNDED PRECEDING)
        FROM inserted

使用自联接更新预先插入的值

UPDATE myTable
SET avg = running_avg
FROM myTable A
INNER JOIN (SELECT ID,AVG(Data) OVER (ORDER BY ID ROWS UNBOUNDED PRECEDING) running_avg FROM myTable) B
ON A.ID = B.ID

使用CTE更新预先插入的值

WITH CTE_Update
AS 
(
    SELECT  ID,
            [avg] OldAvg,
            AVG(Data) OVER (ORDER BY ID) AS NewAvg
    FROM myTable
) 
UPDATE CTE_Update SET OldAvg = NewAvg

答案 2 :(得分:3)

SQL Server&lt; = 2008没有聚合函数的OVER(ORDER BY ...)子句。

CREATE TRIGGER trg_running_avg ON myTable
AFTER INSERT, UPDATE, DELETE
AS
BEGIN
  UPDATE old
    SET avg = new_avg
  FROM myTable old
  CROSS APPLY (
    SELECT AVG(Data) AS new_avg FROM myTable WHERE ID <= old.ID
  ) new
  --Skip the full table update. Start from the lowest ID that was changed.
  WHERE id >= (SELECT MIN(id) FROM (SELECT ID FROM inserted UNION ALL SELECT ID FROM deleted) t)
END
GO

如果可以,请使用视图。对于一行中的更改来说,将其他行中存储的数据无效是一种糟糕的设计。行应代表独立的事实。

答案 3 :(得分:0)

我觉得这应该通过自我加入来实现:

3

join将给出:

select t1.id, t1.data, sum(t2.data)/t1.id as avg
from table t1, table t2
where t1.id>=t2.id group by t1.id