Select 仅值发生变化的行
Select only the rows where a value changes
我正在使用 SQL Server 2008 R2,并且我正在努力编写一个查询,该查询 return 列更改的所有行。
在下面的 table 中,我想按日期顺序浏览所有记录,并且只有 select 金额与该客户的前一行不同的行。
CustomerId
InvoiceId
DateInvoice
Amount
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 *
我已将星号添加到我不想添加的行的金额列中 return。
如有任何建议,我们将不胜感激。
您可以在比您的 SQL 服务器版本更高的版本中使用 LAG() window 函数,但如果没有它,您可以在 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。
结果:
CustomerId
InvoiceId
DateInvoice
Amount
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
我刚刚找到了一种方法,但这对我来说很糟糕,必须有一种更易读的方法。
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
您可以使用带有ROW_NUMBER
和LEFT 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
会 更容易。
我正在使用 SQL Server 2008 R2,并且我正在努力编写一个查询,该查询 return 列更改的所有行。
在下面的 table 中,我想按日期顺序浏览所有记录,并且只有 select 金额与该客户的前一行不同的行。
CustomerId | InvoiceId | DateInvoice | Amount |
---|---|---|---|
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 * |
我已将星号添加到我不想添加的行的金额列中 return。
如有任何建议,我们将不胜感激。
您可以在比您的 SQL 服务器版本更高的版本中使用 LAG() window 函数,但如果没有它,您可以在 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。
结果:
CustomerId | InvoiceId | DateInvoice | Amount |
---|---|---|---|
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 |
我刚刚找到了一种方法,但这对我来说很糟糕,必须有一种更易读的方法。
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
您可以使用带有ROW_NUMBER
和LEFT 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
会 更容易。