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

标签 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;

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

最佳答案

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

即使您拥有 SQL Server 2012 也可以,因为 Martin Smith 认为 SQL Server 2012 中引入了 LAGLEAD 是正确的。

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

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

因此您可以看到 Jen 的行包括 Manaa 的薪水,Masood 的行包括 Jen 的薪水等。没有低于 Manaa 的薪水,因此该行显示之前的薪水为 NULL。

回到您的数据,您应该能够使用此查询在 ID 中获得具有先前 Avg14Green 值的 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 的最早行对于 PriorAvg14Green 将具有 NULL。我有点脑子放屁,不知道在这种情况下你现有的代码会做什么,所以如果你不想更新每个 IDn 的第一行只需在上述查询中添加 WHERE 子句以省略空 pr.PriorAvg14Green 值:

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

关于sql-server - 是否有更快的方法从另一列更新新列,但从前一行更新?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32019384/

相关文章:

sql - 如何使用 SELECT 语句 sql 在结果中显示 `0` 而不是 NULL?

SQL Server 用户名函数

mysql - Codeigniter数据库调用效率

python - 如何提高拆分列表的速度?

.net - 拔掉网线时 SQL 连接不会很快超时

SQL:如何查看列表中有多少项出现在表中?

sql-server - T-SQL 错误 : Adding a value to a 'smalldatetime' column caused overflow. SQL 服务器错误?

java - 参数与字段

java - 不推荐使用 HttpMethod getResponseBodyAsString 但为什么

python - 来自文件的 Numpy 数组 - 预分配?