是否有更快的方法从另一列更新新列但从前一行更新?

时间:2015-08-14 22:14:52

标签: sql-server performance

我的存储过程花费的时间太长,只是用另一列的值更新一列,但是从前一行的值更新(按INT排序,其次是STR)

我使用的代码:

DECLARE @ITERg INT;
SET @ITERg = 1

WHILE @ITERg < 6131
BEGIN
    UPDATE Avg14RSI 
    SET Avg14GreenP = (SELECT TOP 1 Avg14Green 
                       FROM Avg14RSI a 
                       WHERE IDn = @ITERg AND a.IntDate < Avg14RSI.IntDate 
                       ORDER BY a.IDn, a.Ticker, a.IntDate DESC) 
    WHERE IDn = @ITERg

    SET @ITERg = @ITERg + 1
END;

如果有人可以帮助我,我将非常感激!谢谢!

2 个答案:

答案 0 :(得分:2)

原来lag函数非常有用:

UPDATE  UpdateTarget
SET Avg14GreenP = Displaced
FROM (SELECT a.Avg14GreenP, LAG(a.Avg14Green) OVER (PARTITION BY a.Ticker
ORDER BY a.[Date]) AS Displaced
FROM Avg14RSI a) AS UpdateTarget;

答案 1 :(得分:1)

首先,看起来你真的有SQL Server 2014.令人困惑的是,第一个SQL Server 2014版本是版本号12.0.2000.8(SP1是12.whatever),这就是你看到12 *的原因。 SSMS和分析服务的版本。如果您完全不确定,只需执行SELECT @@VERSION,您就可以获得有关SQL Server本身的完整信息。

即使你有SQL Server 2012也没关系,因为Martin Smith是正确的,{1}}和LAG是在SQL Server 2012中引入的。

LEAD可让您收集前一行的值(LAG从下一行获取值)。这是一个快速演示,其中列出了员工的工资,其中包括最接近他们的工资但更少的工资(例如,Masood获得72,000,而Jen,他们紧随其后,获得68,000):

LEAD

所以你可以看到Jen的行包括Manaa的薪水,Masood的行包括Jen的薪水等等。没有比Manaa更低的薪水,因此该行显示前一薪水为NULL。

回到您的数据,您应该能够通过此查询获取CREATE TABLE Employees ( Name VARCHAR(20), Salary NUMERIC(10,2)); GO INSERT INTO Employees VALUES ('Fred', 80000), ('Manaa', 65000), ('Ulrika', 90000), ('Masood', 72000), ('Jen', 68000); SELECT Name, Salary, LAG(Salary) OVER (ORDER BY Salary) AS PriorSalary FROM Employees ORDER BY Name; Name Salary PriorSalary ------ -------- ----------- Fred 80000.00 72000.00 Jen 68000.00 65000.00 Manaa 65000.00 NULL Masood 72000.00 68000.00 Ulrika 90000.00 80000.00 Avg14Green之前ID值的ID列表(我将尝试解释PARTITION在查询之后):

SELECT
  IDn,
  LAG(Avg14Green) OVER (
    PARTITION BY IDn
    ORDER BY Ticker, IntDate DESC) AS PriorAvg14Green
FROM Avg14RSI;

PARTITION表示在通过自动收报机和日期降序排序时获取先前的Avg14Green,但仅对具有相同IDn值的其他行执行此操作。

无论如何,请尝试查询,如果它具有您要查找的值,则可以将其用于一次性UPDATE,而不是一次处理一个IDn;它几乎可以保证更快:

UPDATE Avg14RSI
SET Avg14GreenP = pr.PriorAvg14Green
FROM Avg14RSI
JOIN (
  SELECT
    IDn,
    LAG(Avg14Green) OVER (
      PARTITION BY IDn
      ORDER BY Ticker, IntDate DESC) AS PriorAvg14Green
  FROM Avg14RSI
) pr ON Avg14RSI.IDn = pr.IDn;

请注意,Ticker, IntDate DESC之前的最早一行NULLPriorAvg14Green。我在这里有一点脑屁并且无法弄清楚你现有代码在这种情况下会做什么,所以如果你不想更新每个IDn的第一行,只需添加一个上述查询的WHERE子句省略了空pr.PriorAvg14Green值:

... the query above, plus
WHERE pr.Avg14Green IS NOT NULL;