有没有办法优化递归查询?

Is there a way to optimize recursive query?

我有这个查询,它创建了相同 table 的两个副本(原始 table 没有唯一 ID)所以我使用 row_number 来订购 tables:

SELECT ROW_NUMBER() OVER(ORDER BY Policy ASC) AS RowNumber, * 
INTO Example1 
FROM Payments

SELECT ROW_NUMBER() OVER(ORDER BY Policy ASC) AS RowNumber, * 
INTO Example2
FROM Payments

我想检查 'Import' 中的值是否与 'Import' 中的值相同,该值来自我的 table 中按政策排序的实际值之前的行。

我与我的两个 table 进行了比较,使用行号检查实际值之前的值,如果它们都相等,则将列 'Review' 设置为选中,这意味着导入它与从实际值之前的行导入相同。

这是我所做的,但是执行起来需要很长时间...所以我想知道我是否可以优化此查询或以不同的方式做我想做的事?

DECLARE @intCount INT
SELECT @intCount = COUNT(DISTINCT(RowNumber)) FROM Example1   

DECLARE @i int  
SET @i = 1  

WHILE @i <= @intCount  
BEGIN  
    DECLARE @Import decimal(15,2)  

    SELECT @Import = Import 
    FROM Example1 
    WHERE RowNumber = @i

    DECLARE @RowNumberBefore bigint

    SELECT @RowNumberBefore = RowNumber 
    FROM Example1 
    WHERE RowNumber = @i - 1 

    UPDATE TOP (1) Example1  
    SET Review = 'Checked'
    FROM Example1 a 
    JOIN Example2 b ON a.Policy = b.Policy  
    WHERE a.Import = @Import 
      AND a.RowNumber = @RowNumberBefore

    SET @i = @i + 1  
END  

期望结果示例:

如果我有这个:

RowNumber     Policy    Import   Review
---------     ------    ------   ------
1             0001      586.45
2             0002      586.45
3             0003       65.50
4             0004      249.30
5             0005       65.50
6             0005      153.35
7             0006       32.50
8             0006       32.50
9             0007       32.50
10            0009      250.00

我想用 'checked' 更新评论,如果它的导入与实际导入之前的导入相同(我不能将策略用作 id,因为它可以有重复的值)。

因此,如果我有按策略排序的值(使用行数),我将使用 rowNumber 按照我想要的顺序比较 'Policy':

RowNumber     Policy    Import   Review
---------     ------    ------   ------
1             0001      586.45   Checked
2             0002      586.45   Checked
3             0003       65.50
4             0004      249.30
5             0005       65.50
6             0005      153.35
7             0006       32.50   Checked
8             0006       32.50   Checked
9             0007       32.50   Checked
10            0009      250.00

And I want to check if the value in 'Import' it's the same as the value in 'Import' from the row before the actual one from my table ordered by policy.

我不明白 row_number()update 与这个问题有什么关系。如果要识别 import 更改的行,那么如何:

select p.*
from (select p.*,
             lag(p.import) over (order by p.policy) as prev_import
      from payments p
     ) p
where prev_import <> import;

编辑:

在 SQL Server 2008 中,您只需使用 outer apply 即可:

select p.*
from (select p.*, p2.import as prev_import
      from payments p outer apply
           (select top 1 p2.*
            from payments p2
            where p2.policy < p.policy
            order by p2.policy desc
           ) p2
     ) p
where prev_import <> import;

性能仍然很差,但 payments(policy, import) 上的索引会有所帮助。

您可以使用 LAG() 在一个查询中执行此操作以获取前一行的值,如下所示:

SELECT *, CASE WHEN Import = LAG(Import) over (ORDER BY Policy)
               THEN 'Checked'
               ELSE 'Whatever'
          END Review
INTO Example1
FROM Payments

SQL Server 2008 及之前的版本将使用与您的方法类似的逻辑,但在 table 级别而不是行中执行。这是一种方法:

SELECT p.*, CASE WHEN p.Import = p2.Import
                 THEN 'Checked'
                 ELSE 'Whatever'
            END as Review
INTO Example1
FROM (SELECT *, ROW_NUMBER() over (ORDER BY policy) RN
      FROM Payment) p
LEFT JOIN (SELECT Import, ROW_NUMBER() over (ORDER BY policy) RN
           FROM Payment) p2 on p.RN = p2.RN - 1

首先不需要用row_number创建两个版本。您可以加入相同的 table.

SELECT Payment.Policy, Payment.Import, ROW_NUMBER() over (ORDER BY policy) RN
    INTO #temp
FROM Payment

如果您的 table 很大,您现在可以为其添加索引。注意我只使用了我需要的列。那么查询就是

SELECT t.Import,t.policy,  CASE WHEN t.Import = t2.Import
                 THEN 'Checked'
                 ELSE 'Whatever'
            END as Review
FROM #Temp t
LEFT JOIN #Temp t2 on t.RN = t2.RN - 1

如果您真的想更新原始 table,那么您还有一个问题,因为您在 table 中没有唯一标识符。那你加入什么?此外,我可以看到您的数据存在一些问题,因为您已根据政策订购但有多个政策记录。假设您有以下数据:

RowNumber     Policy    Import   Review
---------     ------    ------   ------
1             0001      586.45
2             0002      586.45
3             0003       65.50
4             0004      249.30
5             0005       65.50
6             0005      249.30
7             0006       32.50
8             0006       32.50
9             0007       32.50
10            0009      250.00

现在政策 0004 和 0005 中的审核值可能取决于它选择处理两条 0005 记录的方式。一个匹配,但另一个不匹配,您无法保证这些 005 记录的顺序。整个问题是一个经典案例,说明为什么你不应该在没有主键的情况下创建 table。