原文:T-SQL技术收集——删除重复数据

在工作和面试中,经常出现如何查询或者删除重复数据的问题,如果有主键,那还好办一点,如果没有主键,那就有点麻烦。

当一个表上没有辅助键时,如果使用SSMS界面来删除,就会报错(注意,本人测试环境是2012,所以界面可能会有所不一样,但是对结果没有任何影响):

因为在创建表后插入数据是没有做判断。但是在删除时,为了保证数据库的一致性,RDBMS还是会做判断从而拒绝执行这类操作。

说明:

要解决这种问题,除了在设计的过程中做好之外,还可以在数据没有重复数据的情况下,使用ALTER TABLE ADD Constraint语句来增加约束。

但是要删除现有的重复值,使用SSMS界面是无法实现的,就算能实现,当数据量到达一定程度,也是不现实的。此时只能使用T-SQL语句,搭配SET ROWCOUNT 1让数据的处理方式一次一行或这使用DELETE  TOP (1)的方式删除,注意,括号是必须的。

SET ROWCOUNT { number | @number_var }:使 SQL Server 在返回指定的行数之后停止处理查询。如果需要取消限制,只需要使用SETROWCOUNT 0就可以。

下面是例子:

--使用set rowcount 3设定,查询所有数据

SET
ROWCOUNT  3

SELECT
* FROM
AdventureWorks.HumanResources.Department

结果如下:

--使用set rowcount 3,修改所有数据

UPDATE
AdventureWorks.HumanResources.Department

SET
name=name

(3 行受影响)

--回复原有设置

SET
ROWCOUNT  0

最后使用TOP (N)设定搭配INSERT/UPDATE /DELETE ,注意这部分只适合2005以后。

--使用TOP(3)设置,查询所有数据,注意是要有括号的

SELECT
TOP(3)
* FROM
AdventureWorks.HumanResources.Department

UPDATE
TOP(3)
AdventureWorks.HumanResources.Department
SET name
=name

(3 行受影响)

另外,SQLServer提供了一个系统函数@@ROWCOUNT来返回影响行数。以下是例子:

--使用@@rowcount系统函数返回影响行数

SELECT
EmployeeID,Title

FROM
AdventureWorks.HumanResources.Employee

WHERE
Title LIKE
'%Manager%'

GO

SELECT
@@ROWCOUNT 'Result'

解决方法:

首先创建一个测试表和插入测试数据:

USE tempdb

GO

CREATE TABLE
MyT

(

[SID]  
INT,

sname  
VARCHAR(10),

sdt    
DATETIME

)

GO

--插入测试数据

INSERT INTO
MyT VALUES (1,'Lu','2012/01/01');

INSERT INTO
MyT VALUES (1,'Lu','2012/07/08');

INSERT INTO
MyT VALUES (1,'Lu','2012/04/03');

INSERT INTO
MyT VALUES (2,'Tian','2012/03/01');

INSERT INTO
MyT VALUES (2,'Tian','2012/05/09');

INSERT INTO
MyT VALUES (2,'Tian','2012/01/01');

INSERT INTO
MyT VALUES (3,'AD','2012/01/08');

INSERT INTO
MyT VALUES (3,'AD','2012/03/01');

INSERT INTO
MyT VALUES (4,'Sun','2012/02/01');

INSERT INTO
MyT VALUES (1,'Lu','2012/01/01');

INSERT INTO
MyT VALUES (1,'Lu','2012/07/08');

INSERT INTO
MyT VALUES (1,'Lu','2012/04/03');

INSERT INTO
MyT VALUES (2,'Tian','2012/03/01');

INSERT INTO
MyT VALUES (2,'Tian','2012/05/09');

INSERT INTO
MyT VALUES (2,'Tian','2012/01/01');

INSERT INTO
MyT VALUES (3,'AD','2012/01/08');

INSERT INTO
MyT VALUES (3,'AD','2012/03/01');

INSERT INTO
MyT VALUES (4,'Sun','2012/02/01');

GO

第一种方法:

使用SET ROWCOUNT 1方法来删除重复数据:

需要搭配WHILE 1=1无限循环,搭配BREAK作为终止。针对找出来的重复数据,使用GROUP BY 和HAVING COUNT(1)>1作为筛选条件,可以避免所有数据被删除。

SET ROWCOUNT 1

WHILE 1=1

BEGIN

DELETE
FROM MyT

WHERE
[sid] IN

(

SELECT
[sid] FROM MyT

GROUP
BY [sid],sname

HAVING
COUNT(1)>1

)

IF
@@ROWCOUNT=0

BREAK

END

SET ROWCOUNT 0

--可以发现,重复的数据已经删除

SELECT *
FROM MyT

第二种方法:

使用DELETE TOP(N)方法,先把刚才插入测试数据的脚本再执行,可以多执行几次。DELETE TOP(1)可以用来替代SET ROWCOUNT 1:

WHILE 1=1

BEGIN

DELETE
TOP(1)
FROM MyT

WHERE
[sid] IN

(

SELECT
[sid] FROM MyT

GROUP
BY [sid],sname

HAVING
COUNT(1)>1

)

IF
@@ROWCOUNT=0

BREAK

END

结果和上面的一样。

扩充:保留最近的一行数据:

有时候不仅仅要去掉重复数据,也要保证剩下的是最新的数据(日期最大),此时可以借助索引,使用索引排序,然后把日期最小的那些删掉,只保留日期最大的那一笔。

--建立复合索引,利用索引将数据以编号和日期升序排序

CREATE INDEX
IDX_DT ON
MyT([sid],sdt
ASC)

GO

--修改删除语句,搭配with index查询提示

WHILE 1=1

BEGIN

DELETE
TOP(1)
FROM MyT

WHERE
[sid] IN

(

SELECT
[sid] FROM MyT
WITH (INDEX(idx_dt))

GROUP
BY [sid],sname

HAVING
COUNT(1)
>1

)

IF
@@ROWCOUNT=0

BREAK

END

查询结果:

SELECT *
FROM MyT

注意:

为了向后兼容,括号在 SELECT 语句中是可选的。

我们建议您始终对 SELECT 语句中的 TOP 使用括号,这样,就可以与在 INSERT、UPDATE、MERGE 和 DELETE 语句中需要使用括号保持一致(在这种情况下括号是必需的)。

(出自SQL SERVER 2012联机丛书)

T-SQL技术收集——删除重复数据的更多相关文章

  1. 面试题中经常遇到的SQL题:删除重复数据,保留其中一条

    如题,解决思路如下: 1.首先我们需要找出拥有重复数据的记录 ---以name字段分组 select Name,COUNT(Name) as [count] from Permission group ...

  2. 你真的会玩SQL吗?删除重复数据且只保留一条

    在网上看过一些解决方法 我在此给出的方法适用于无唯一ID的情形 表:TB_MACVideoAndPicture 字段只有2个:mac,content mac作为ID,正常情况下mac数据是唯一的,由于 ...

  3. SQL Server中删除重复数据

    delete from A ) )

  4. SQL表之间复制数据、选出随机几条数据、删除重复数据、取得自增长列等操作

    --表之间数据复制 SELECT* INTO yozhu FROM yo --复制一份表 SELECT* INTO yozhu1 FROM yo where 1<>1 --只复制表结构,无 ...

  5. SQL server 存储过程 C#调用Windows CMD命令并返回输出结果 Mysql删除重复数据保留最小的id C# 取字符串中间文本 取字符串左边 取字符串右边 C# JSON格式数据高级用法

    create proc insertLog@Title nvarchar(50),@Contents nvarchar(max),@UserId int,@CreateTime datetimeasi ...

  6. sql查询删除重复数据

    数据库UserInfo 删除重复数据 即删除重复的用户名手机号 同一个用户名手机号只保留一个用户 01.根据多个字段查询重复数据 with data1 as( select MobilePhone,N ...

  7. sql 删除重复数据且保留其中一条 用sql 关键字:with ROW_NUMBER

    --1.建立表:Coursecreate table Course( ID int identity(1,1),--ID Student varchar(20) ,--学生 Sub varchar(2 ...

  8. SQL语句删除重复数据

    1.如表中没有主键,先添加自动增长主键 alter table 表名 add 列名 int identity (1,1) primary key 2.删除重复数据 delete from 表名 whe ...

  9. SQL:一句话删除重复的数据

    --构造原始数据 )) --插入数据 INSERT INTO #T (N)VALUES ('A') --方式一:一句话删除重复数据(无主键) --方式二:采用CTQ,with的写法删除 ;

随机推荐

  1. 屏蔽电信流氓广告造成的诡异的问题--Android WebView 长时间不能载入页面

    发如今家里的时候用Android App里的WebView打开站点非常慢,会有十几秒甚至更长时间的卡住. 可是在电脑上打开相同的网页却非常快. 查找这个问题的过程比較曲折,记录下来. 抓取Androi ...

  2. 辛星与您使用CSS导航条

    第一步.我们创建了一个新的my.html档.在内容填入如下面.这个html文件不动,直到最后.正是这些内容: <!DOCTYPE html PUBLIC "-//W3C//DTD XH ...

  3. String,StringBuffer以及StringBuilder的差别

    1.定义: String:String 类代表字符串. Java 程序中的全部字符串字面值(如"abc" )都作为此类的实例实现. 字符串是常量:它们的值在创建之后不能更改. 字符 ...

  4. 【Spark亚太研究院系列丛书】Spark实战高手之路-第一章 构建Spark集群(第五步)(2)

    把下载下来的"hadoop-2.2.0.tar.gz"复制到"/usr/local/hadoop/"文件夹下并解压: 改动系统配置文件,改动~/.bashrc文 ...

  5. Windows Phone开发(18):变形金刚第九季——变换

    原文:Windows Phone开发(18):变形金刚第九季--变换 变换不是一个好理解的概念,不是吓你,它涉及很多有关代数,几何,以及线性代数的知识.怎么?被我的话吓怕了?不用怕,尽管我们未必能够理 ...

  6. centos6.5安装nodejs

    Preface(前言) 一次偶然的机会知道有nodejs这个东西,确实对它还是非常感兴趣的.刚開始仅仅知道它能让javascript写后台,然后前后台都由javascript来写,确实认为真的挺爽,毕 ...

  7. php &#160;性能优化

    基础优化 1 不要随便复制变量. 有时候为了使 PHP 代码更加整洁,一些 PHP 新手(包含我)会把提前定义好的变量拷贝到一个名字更简短的变量中,事实上这样做的结果是添加了一倍的内存消耗,仅仅会使程 ...

  8. Android中一个类实现的接口数不能超过七个

    近期一段时间,在开发Android应用程序的过程中,发现Android中一个类实现的接口数超过七个的时候,常常会出现超过第7个之后的接口不能正常使用.

  9. HBuilder之初体验

    听闻HTML5定稿了,所以特意去了解了下.文章有提到HTML5的一款IDE(HBuilder,貌似出来好久了,孤陋寡闻....),于是来到官网http://dcloud.io/ ,被演示图震惊了!果然 ...

  10. 同一路由器不同vlan之间的通信(一)

    还是废话不多说,第一步,看拓扑图. 先把pc上的ip都配好.開始设置 switch0: >en >conf t >vlan 2 >exit >int fa 0/1 > ...