2

我正在搜索删除表上的重复条目,我看到了如下示例:

CREATE TABLE Suppliers
(
  Id int identity (1,1),
  CompanyTitle nvarchar(1000),
  ContactName nvarchar(100),
  LastContactDate datetime
)

INSERT Suppliers VALUES (N'Melody Music Instruments',N'James Manning', '20090623 10:15')
INSERT Suppliers VALUES (N'Blue Jazz',N'Mike Clark', '20090720 15:40')
INSERT Suppliers VALUES (N'Top Music',N'Katy Swan', '20090827 18:00')
INSERT Suppliers VALUES (N'Blue Jazz',N'Mike Clark', '20090806 10:00')
INSERT Suppliers VALUES (N'Melody Music Instruments',N'James Brown', '20080121 11:20')
INSERT Suppliers VALUES (N'Top Music',N'Katy Perry', '20090825 14:00')
INSERT Suppliers VALUES (N'Top Music',N'Katy Perry', '20090825 14:00')


WITH Duplicate AS 
(
SELECT
  RN = ROW_NUMBER() OVER (PARTITION BY CompanyTitle ORDER BY LastContactDate DESC)
FROM Suppliers
)
delete from Duplicate where RN > 1

CTE 返回类似的东西,然后如果值大于 1 则删除。

RN
--
1
2
1
2
1
2
3

我不明白的是它如何理解哪个条目将被删除。它只是通过这个例子返回重复的条目计数。

现场示例:http ://www.sqlfiddle.com/#!3/d84b6/20

4

3 回答 3

4

您的示例表是一个堆(意味着它没有聚集索引)。

如果您查看示例的执行计划,您将看到它Bmk1000位于叶级表扫描的输出列列表中,并且该列在计划中的所有操作符之间传递,直到DELETE操作符为止。

Bmk1000是一个书签,用于唯一标识行的位置(堆的行标识符包含行的 File:Page:Slot 的位置),因此DELETE操作员可以使用它来定位所需的行。

如果您的表有一个聚集索引,您可能会看到聚集索引键列是以这种方式而不是书签传递的。

于 2013-02-19T23:15:11.390 回答
1

你的问题是什么?它正在删除行号大于 1 的任何内容。. . 代码非常明确RN > 1

它将行号分配给行,从每个 CompanyTitle 开始。具有最近联系日期的行的值为 1。

因此,此代码将删除比每个 CompanyTitle 的最近联系人更旧的所有内容。

于 2013-02-19T21:32:25.227 回答
1

PARTITION BY 和 ORDER BY 子句控制将删除哪些行。如果稍微扩展 CTE,它的工作原理会更加明显。(PostgreSQL 语法)

WITH Duplicate AS 
(
  SELECT
    ROW_NUMBER() OVER (PARTITION BY CompanyTitle ORDER BY LastContactDate DESC),
    CompanyTitle, 
    LastContactDate 
  FROM Suppliers
)
select * 
from Duplicate

(为了便于阅读,下面添加了空行。)

1  Blue Jazz                    2009-08-06 10:00:00
2  Blue Jazz                    2009-07-20 15:40:00

1  Melody Music Instruments     2009-06-23 10:15:00
2  Melody Music Instruments     2008-01-21 11:20:00

1  Top Music                    2009-08-27 18:00:00
2  Top Music                    2009-08-25 14:00:00
3  Top Music                    2009-08-25 14:00:00

PARTITION 子句将相同的 CompanyTitle 值保持在一起。ORDER BY 子句按 LastContactDate 对具有相同CompanyTitle 值的行进行排序。由于它按降序排序,因此每个 CompanyTitle 的最新行将始终编号为 1。

因此,要删除除每个 CompanyTitle 的最新行之外的所有行,您需要删除行号大于 1 的所有行。

于 2013-02-19T22:46:45.107 回答