2012-07-21 49 views
1

我有一個這樣的表。在SQL查詢中查找下一行並僅在前一行匹配的情況下才刪除它

|-DT--------- |-ID------| 
|5/30 12:00pm |10  | 
|5/30 01:00pm |30  | 
|5/30 02:30pm |30  | 
|5/30 03:00pm |50  | 
|5/30 04:30pm |10  | 
|5/30 05:00pm |10  | 
|5/30 06:30pm |10  | 
|5/30 07:30pm |10  | 
|5/30 08:00pm |50  | 
|5/30 09:30pm |10  | 

我想刪除任何重複的行只上一行是否具有相同的ID爲下一行。我想保留將來最遠的日期時間的重複行。例如,上表看起來像這樣。

|-DT--------- |-ID------| 
|5/30 12:00pm |10  | 
|5/30 02:30pm |30  | 
|5/30 03:00pm |50  | 
|5/30 07:30pm |10  | 
|5/30 08:00pm |50  | 
|5/30 09:30pm |10  | 

我可以得到關於如何做到這一點的提示嗎?

回答

3
with C as 
(
    select ID, 
     row_number() over(order by DT) as rn 
    from YourTable 
) 
delete C1 
from C as C1 
    inner join C as C2 
    on C1.rn = C2.rn-1 and 
     C1.ID = C2.ID 

SE-Data

0

在這裏,只需將[Table]替換爲表格的名稱即可。

SELECT * 
FROM [dbo].[Table] 
WHERE [Ident] NOT IN 
(
    SELECT Extent.[Ident] 
    FROM 
    (
     SELECT TOP 100 PERCENT T1.[DT], 
       T1.[ID], 
       T1.[Ident], 
       (
        SELECT TOP 1 Previous.ID 
        FROM [dbo].[Table] AS Previous 
        WHERE Previous.[Ident] > T1.Ident -- this is where the identity seed is important 
        ORDER BY [Ident] ASC 
       ) AS 'PreviousId' 
     FROM [dbo].[Table] AS T1 
     ORDER BY T1.[Ident] DESC 
    ) AS Extent 
    WHERE [Id] = [PreviousId] 
) 

注意:您需要在表中的恆等式列 - 使用CTE,如果你不能改變表的結構。

0

你可以試試下面的查詢......

select * from 
(
    select *,RANK() OVER (ORDER BY dt,id) AS Rank from test 
) as a 
where 0 = (
select count(id) from (
select id, RANK() OVER (ORDER BY dt,id) AS Rank from test 
)as b where b.id = a.id and b.Rank = a.Rank + 1 

) order by dt 

感謝, 馬赫什

2

做這些3個步驟:http://www.sqlfiddle.com/#!3/b58b9/19

首先讓行順序:

with a as 
(
    select dt, id, row_number() over(order by dt) as rn 
    from tbl 
) 
select * from a; 

輸出:

|       DT | ID | RN | 
---------------------------------------- 
| May, 30 2012 12:00:00-0700 | 10 | 1 | 
| May, 30 2012 13:00:00-0700 | 30 | 2 | 
| May, 30 2012 14:30:00-0700 | 30 | 3 | 
| May, 30 2012 15:00:00-0700 | 50 | 4 | 
| May, 30 2012 16:30:00-0700 | 10 | 5 | 
| May, 30 2012 17:00:00-0700 | 10 | 6 | 
| May, 30 2012 18:30:00-0700 | 10 | 7 | 
| May, 30 2012 19:30:00-0700 | 10 | 8 | 
| May, 30 2012 20:00:00-0700 | 50 | 9 | 
| May, 30 2012 21:30:00-0700 | 10 | 10 | 

其次,使用序列號,我們可以發現哪些行是在底部(以及那些沒有在底部也如此):

with a as 
(
    select dt, id, row_number() over(order by dt) as rn 
    from tbl 
) 
select below.*, 
    case when above.id <> below.id or above.id is null then 
     1 
    else 
     0 
    end as is_at_bottom 
from a below 
left join a above on above.rn + 1 = below.rn; 

輸出:

|       DT | ID | RN | IS_AT_BOTTOM | 
------------------------------------------------------- 
| May, 30 2012 12:00:00-0700 | 10 | 1 |   1 | 
| May, 30 2012 13:00:00-0700 | 30 | 2 |   1 | 
| May, 30 2012 14:30:00-0700 | 30 | 3 |   0 | 
| May, 30 2012 15:00:00-0700 | 50 | 4 |   1 | 
| May, 30 2012 16:30:00-0700 | 10 | 5 |   1 | 
| May, 30 2012 17:00:00-0700 | 10 | 6 |   0 | 
| May, 30 2012 18:30:00-0700 | 10 | 7 |   0 | 
| May, 30 2012 19:30:00-0700 | 10 | 8 |   0 | 
| May, 30 2012 20:00:00-0700 | 50 | 9 |   1 | 
| May, 30 2012 21:30:00-0700 | 10 | 10 |   1 | 

三,刪除所有行不在底部:

with a as 
(
    select dt, id, row_number() over(order by dt) as rn 
    from tbl 
) 
,b as 
(
    select below.*, 
     case when above.id <> below.id or above.id is null then 
      1 
     else 
      0 
     end as is_at_bottom 
    from a below 
    left join a above on above.rn + 1 = below.rn 
) 
delete a 
from a 
inner join b on b.rn = a.rn 
where b.is_at_bottom = 0; 

驗證:

select * from tbl order by dt; 

輸出:

|       DT | ID | 
----------------------------------- 
| May, 30 2012 12:00:00-0700 | 10 | 
| May, 30 2012 13:00:00-0700 | 30 | 
| May, 30 2012 15:00:00-0700 | 50 | 
| May, 30 2012 16:30:00-0700 | 10 | 
| May, 30 2012 20:00:00-0700 | 50 | 
| May, 30 2012 21:30:00-0700 | 10 | 

您還可以簡化刪除此:http://www.sqlfiddle.com/#!3/b58b9/20

with a as 
(
    select dt, id, row_number() over(order by dt, id) as rn 
    from tbl 
) 
delete above 
from a below 
left join a above on above.rn + 1 = below.rn 
where case when above.id <> below.id or above.id is null then 1 else 0 end = 0; 

Mikael Eriksson的答案是最好的,但如果我再次簡化我的簡化查詢,它將看起來像他的回答ツ爲此,我爲他的答案+1了。儘管如此,我只會讓他的查詢更具可讀性;通過交換加入順序並給出好的別名。

with a as 
(
    select *, row_number() over(order by dt, id) as rn 
    from tbl 
) 
delete above 

from a below 
join a above on above.rn + 1 = below.rn and above.id = below.id; 

現場測試:http://www.sqlfiddle.com/#!3/b58b9/24

+0

感謝您的解釋! – Bravado 2012-07-21 23:52:20

相關問題