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

时间:2018-01-12 17:07:08

标签: sql sql-server sql-server-2008 recursive-query

我有这个查询创建了同一个表的两个副本(原始表没有唯一的ID)所以我使用row_number来排序表:

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

我想检查“导入”中的值是否与我在按政策排序的表格中的实际行之前的“导入”中的值相同。

我使用行号对我的两个表进行了比较以检查实际值之前的值,如果它们都等于它,则将“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,因为它可能有重复的值)。

所以,如果我有按政策排序的值(使用rowcount),我正在使用rowNumber按照我想要的顺序比较'政策':

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

3 个答案:

答案 0 :(得分:3)

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

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

SQL Server 2008和之前将使用类似于您的方法的逻辑,但是在表级而不是行级执行。这是一种方式:

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

答案 1 :(得分:2)

  

我想检查“导入”中的值是否为&#39;它与&#39;导入&#39;中的值相同从我按照政策订购的表中的实际行之前的行。

我不知道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)上的索引会有所帮助。

答案 2 :(得分:0)

首先,不需要使用row_number创建两个版本。您可以加入同一张桌子。

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

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

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

如果您确实想要更新原始表,那么您还有一个问题,因为表中没有唯一标识符。那你加入什么?此外,我可以看到您的数据存在一些问题,因为您已经订购了策略但是有多个策略记录。假设您有这些数据:

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记录的顺序。整个问题是一个经典案例,说明为什么不应该创建没有主键的表。