本文原文出处是C Sharp Corner ,为了更好地阅读,本人对 原文中不重要的语句有所删减.
当你在做数据库驱动的应用时, 你肯定知道怎么从数据库的表中移除重复数据.
→重复的记录不仅会占用大量空间, 而且会减慢数据库查询的执行过程.
含有重复数据的表
我有一张叫"学生"的数据表,其中含有需要删除的重复数据. 表格如下
它有四列, 分别是:
1.Id - 主要的列(类型是 "int" 和 Identity[1,1]
2.Name - varchar(50) 和 NOT NULL
3.Age - int 和 NOT NULL
4.Standard - int he NOT NULL
你可以通过以下脚本在SQL服务器数据库中创建表格.
1 SET ANSI_NULLS ON 2 GO 3 4 SET QUOTED_IDENTIFIER ON 5 GO 6 7 SET ANSI_PADDING ON 8 GO 9 10 CREATE TABLE [dbo].[Student]( 11 [Id] [int] IDENTITY(1,1) NOT NULL, 12 [Name] [varchar](50) NOT NULL, 13 [Age] [int] NOT NULL, 14 [Standard] [int] NOT NULL, 15 CONSTRAINT [PK_Student] PRIMARY KEY CLUSTERED 16 ( 17 [Id] ASC 18 )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] 19 ) ON [PRIMARY] 20 21 GO 22 23 SET ANSI_PADDING OFF 24 GO
我现在会通过运行以下的插入脚本来增加一些重复记录.
1 SET IDENTITY_INSERT [dbo].[Student] ON 2 3 GO 4 INSERT [dbo].[Student] ([Id], [Name], [Age], [Standard]) VALUES (1, N'John', 12, 5) 5 GO 6 INSERT [dbo].[Student] ([Id], [Name], [Age], [Standard]) VALUES (2, N'Ram', 11, 4) 7 GO 8 INSERT [dbo].[Student] ([Id], [Name], [Age], [Standard]) VALUES (3, N'Ram', 11, 4) 9 GO 10 INSERT [dbo].[Student] ([Id], [Name], [Age], [Standard]) VALUES (4, N'Anna', 8, 3) 11 GO 12 INSERT [dbo].[Student] ([Id], [Name], [Age], [Standard]) VALUES (5, N'Maya', 9, 4) 13 GO 14 INSERT [dbo].[Student] ([Id], [Name], [Age], [Standard]) VALUES (6, N'Mary', 10, 5) 15 GO 16 INSERT [dbo].[Student] ([Id], [Name], [Age], [Standard]) VALUES (7, N'Mary', 10, 5) 17 GO 18 INSERT [dbo].[Student] ([Id], [Name], [Age], [Standard]) VALUES (8, N'Mary', 10, 6) 19 GO 20 INSERT [dbo].[Student] ([Id], [Name], [Age], [Standard]) VALUES (9, N'Robin', 11, 5) 21 GO 22 INSERT [dbo].[Student] ([Id], [Name], [Age], [Standard]) VALUES (10, N'Donald', 12, 7) 23 GO 24 SET IDENTITY_INSERT [dbo].[Student] OFF 25 GO
现在打开表格就可以看到以下重复的数据了
重复的数据是叫以下名字的学生:
* Ram with id 2和3.
* Mary with id 6和7.
注意 Mary with id 8 并没有与其他id 6, 7 重复, 因为它的Standard与他们不同.
---------------------------------------------------------------------------------------------------------
方法一: 使用 Group By
SQL Group By语句按一栏或多栏对结果分组, 并且会搭配合计类的方法使用(COUNT, MAX, MIN, SUM, AVG).
我用Group By 和Min语句 建了一条SQL的查询.
1 SELECT MIN(Id) AS 'Id', Name, Age, Standard 2 FROM Student 3 GROUP BY Name, Age, Standard
可以看到在上图的查询结果中, 重复项id 3和7不见了.
现在, 我可以在查询中用Delete语句删除这些重复项.
1 DELETE FROM STUDENT WHERE 2 Id NOT IN(SELECT MIN(Id) AS 'Id' FROM Student GROUP BY Name, Age, Standard)
运行后, 表格如下:
方法二: 使用 Distinct 语句
要使用Distinct语句(可返回无重复项), 你必须要建一个与原表结构和组成相同的新表.
然后将原表的所有非重复项插入到新表.
我建了一个新表叫Student1, 然后将所有非重复项从Student表加入到新表中, 查询语句如下:
1 Select Distinct * into Student1 from Student;
现在我要删除掉旧表Student, 将新表Student1重命名为Student. 使用一下查询语句:
1 DROP Table Student 2 EXEC sp_rename 'Student1', 'Student'
方法三: 借助编程语言
你也可以借助一些编程语言如C#, JavaScript, PHP等,来删除重复数据
我将使用 Entity Framework Core(一种C#编写的的 OR/M框架→[Object-Relational Mapping对象关系映射]). Entity Framework Core 广泛应用于ASP.NET Core数据库编程.
在Entity Framework Core中, 删除重复记录的代码如下:
1 using (var context = new MyContext()) 2 { 3 var students = context.Student.GroupBy(s => new { s.Name, s.Age, s.Standard }).SelectMany(grp => grp.Skip(1)); ; 4 context.Student.RemoveRange(students); 5 context.SaveChanges(); 6 }
我使用了EF Core中的GroupBy()方法, 查找出了基于'Name, Age, Standard这三列的所有重复项.
然后我用RemoveRange()方法删除这些重复项.
方法四: 使用公用表表达式 CTE
CTE(Common table expression)是一个临时结果集, 是在单个SELECT、INSERT、UPDATE、DELETE 或CREATE VIEW 语句的执行范围内定义的.
我可以使用CTE和 "PARTITION BY"语句来删除重复项:
1 WITH myTemp 2 AS (SELECT ROW_NUMBER() OVER (PARTITION BY Name, Age, Standard ORDER BY Id) RN FROM Student) 3 DELETE FROM myTemp WHERE RN > 1;
注意: Row_Number()函数会根据在OVER子句中的选择的顺序, 生成连续的行号.
它将第一行设为1,并逐行递增.
我在Partition By 语句中放入了Student表的三列.
当你在Partition By 语句中指定单列或数列时, 它会将结果集分割成多个部分.然后分级函数会在每个部分单独运行. 分级对每部分会单独计算, 都是从1开始.
===================================================
公用表达式的定义,包含三部分:
- 公用表表达式的名字(在WITH之后)
- 所涉及的列名(可选)
- 一个SELECT语句(紧跟AS之后)
1 WITH expression_name [ ( column_name [,...n] ) ] 2 3 AS 4 5 ( CTE_query_definition )
====================================================
方法五: 使用自连接Self Join
自连接是将自身表的一个镜像当作另一个表来对待, 在同一张表中的内连接.(Inner Join,又叫等值连接,返回两个表中联结字段相等的行,是Join的默认形式)
自连接也可以用于删除重复项.
1> "on"条件句检查重复栏
2> "where"条件句中比较表之间的主键栏
以下查询语句会查出Student表中的重复项:
1 Select * From Student s Inner Join Student s1 2 On s.Name=s1.Name And s.Age=s1.Age And s.Standard=s1.Standard 3 Where s.Id>s1.Id
下一步要做的就是执行Delete语句:
1 Delete Student where Id in( 2 Select s.Id From Student s Inner Join Student s1 3 On s.Name=s1.Name And s.Age=s1.Age And s.Standard=s1.Standard 4 Where s.Id>s1.Id)
No man ever steps in the same river twice.
皆 誰かに必要とされたくて、でも うまくいかなくて 泣きたい気持ちを笑い飛ばして