仅选择值发生变化的行

时间:2021-01-19 16:29:22

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

我正在使用 SQL Server 2008 R2,我正在努力编写一个查询,该查询返回列更改的所有行。

在下表中,我想按日期顺序浏览所有记录,只选择金额与该客户的前一项不同的行。

<头>
客户 ID 发票编号 日期发票 金额
209 9725772 2020-12-10 9.50
209 9725773 2021-01-15 1.50
209 9725774 2021-01-17 2.50
209 9725775 2021-01-19 3.50
209 9725776 2021-01-21 3.50 *
209 9725777 2021-01-23 9.50
209 9725778 2021-01-25 9.50 *
209 9725779 2021-01-25 3.50
210 9726132 2021-02-02 3.50
210 9726133 2021-03-02 9.50
210 9726134 2021-04-02 9.50 *

对于不想返回的行,我已在“金额”列中添加了一个星号。

如有任何建议,我们将不胜感激。

3 个答案:

答案 0 :(得分:2)

您可以在比您的 SQL Server 版本更高的版本中使用 LAG() 窗口函数,但如果没有它,您可以在 WHERE 子句中使用相关子查询:

SELECT t1.*
FROM tablename t1
WHERE t1.Amount <> COALESCE(
  (
    SELECT TOP 1 t2.Amount
    FROM tablename t2
    WHERE t2.CustomerId = t1.CustomerId AND t2.DateInvoice < t1.DateInvoice
    ORDER BY t2.DateInvoice DESC
  ), -1)

参见demo
结果:

<头>
客户 ID InvoiceId 日期发票 数量
209 9725772 2020-12-10 9.50
209 9725773 2021-01-15 1.50
209 9725774 2021-01-17 2.50
209 9725775 2021-01-19 3.50
209 9725777 2021-01-23 9.50
209 9725779 2021-01-25 3.50
210 9726132 2021-02-02 3.50
210 9726133 2021-03-02 9.50

答案 1 :(得分:2)

可以使用带有 ROW_NUMBERLEFT JOIN 的 CTE 到前一行:

WITH CTE AS(
    SELECT CustomerId,
           InvoiceId,
           DateInvoice,
           Amount,
           ROW_NUMBER () OVER (PARTITION BY CustomerID ORDER BY DateInvoice ASC) AS RN
    FROM dbo.YourTable)
SELECT C1.CustomerId,
       C1.InvoiceId,
       C1.DateInvoice,
       C1.Amount
FROM CTE C1
     LEFT JOIN CTE C2 ON C1.CustomerId = C2.CustomerId
                     AND C1.Amount = C2.Amount
                     AND C1.RN = C2.RN + 1
WHERE C2.CustomerId IS NULL;

使用 forpas 的样本数据:db<>fiddle

但是 LAG/LEAD方式更容易。

答案 2 :(得分:0)

我刚刚找到了一种方法,但这对我来说看起来很糟糕,必须有一种更易读的方法来做到这一点。

SELECT t.CustomerId,
t.InvoiceId,
t.DateInvoice,
t.Amount,
(SELECT TOP 1 Amount 
 FROM #test t1 
 WHERE t1.CustomerId=t.CustomerId AND t1.DateInvoice<t.DateInvoice 
 ORDER BY DateInvoice DESC) AS PrevAmount
 FROM #test AS t
 WHERE ((SELECT TOP 1 Amount 
    FROM #test t1
    WHERE t1.CustomerId=t.CustomerId AND t1.DateInvoice<t.DateInvoice 
    ORDER BY DateInvoice DESC)) <> Amount 
 Or ((SELECT TOP 1 Amount 
 FROM #test t1 
 WHERE t1.CustomerId=t.CustomerId AND t1.DateInvoice<t.DateInvoice 
 ORDER BY DateInvoice DESC)) Is Null
相关问题