在 SQL Server 中删除重复行

如何编写 SQL Server 中删除或移除重复行的查询,这是你可能会遇到的常见面试问题之一。

对于这个删除重复行或记录的例子,我们将使用下面显示的数据(Adventure Works DW 中用于移除的 Fact Internet Sales 的几列)。

USE [AdventureWorksDW2014]
GO
SELECT [ProductKey]
      ,[OrderQuantity]
      ,[UnitPrice]
      ,[ExtendedAmount]
      ,[DiscountAmount]
      ,[ProductStandardCost]
      ,[TotalProductCost]
      ,[SalesAmount]
      ,[TaxAmt]
FROM [FactInternetSales]
ORDER BY [ProductKey]

为了尽可能使这个例子简单,我们创建了一个新表,然后将上述数据插入到新表中。

CREATE TABLE [dbo].[DupFactInternetSales](
	[FactID] [int] IDENTITY(1,1) NOT NULL,
	[ProductKey] [int] NOT NULL,
	[OrderQuantity] [smallint] NOT NULL,
	[UnitPrice] [money] NOT NULL,
	[ExtendedAmount] [money] NOT NULL,
	[DiscountAmount] [float] NOT NULL,
	[ProductStandardCost] [money] NOT NULL,
	[TotalProductCost] [money] NOT NULL,
	[SalesAmount] [money] NOT NULL,
	[TaxAmt] [money] NOT NULL
) ON [PRIMARY]

GO

下面的屏幕截图将向你展示我们插入到数据库的 DupFactInternetSales 表中的数据。

Insert records 1

让我向你展示 SQL Server 表中存在的唯一记录。正如你所见,我们使用了 SELECT DISTINCT 关键字。

Select Statement to View Records 2

使用 ROW_NUMER 和 CTE 删除 SQL Server 中的重复行

在本例中,我们将向你展示如何使用 ROW_NUMBER 函数和公共表表达式(CTE)来删除重复行。

WITH RemoveDuplicate
AS (
     SELECT ROW_NUMBER() 
      OVER (
	    PARTITION BY [ProductKey]
			,[OrderQuantity]
			,[UnitPrice]
			,[ExtendedAmount]
			,[DiscountAmount]
			,[ProductStandardCost]
			,[TotalProductCost]
			,[SalesAmount]
			,[TaxAmt]
	   ORDER BY [ProductKey]
          ) UniqueRowNumber
    FROM [DupFactInternetSales])

DELETE FROM RemoveDuplicate
WHERE  UniqueRowNumber > 1;

在 CTE 中,我们使用了名为 ROW_NUMBER 的排序函数。它将分配一个从 1 到 n 的唯一排序编号。接下来,我们删除所有排序编号大于 1 的记录。

输出:让我向你展示该语句的输出。

Messages
--------
(60240 row(s) affected)

让我们看看在删除操作后,DupFactInternetsales 中存在的数据。

remove or Delete Duplicate Rows 4

使用自连接删除 SQL Server 中的重复行

在这个常见问题解答中,我们将展示如何使用 SELF JOIN 来移除重复行。

DELETE InternetSales
FROM   [DupFactInternetSales] InternetSales,
       [DupFactInternetSales] FactInternetSales
WHERE   InternetSales.[ProductKey] = FactInternetSales.[ProductKey] AND
	InternetSales.[OrderQuantity] = FactInternetSales.[OrderQuantity] AND
	InternetSales.[UnitPrice] = FactInternetSales.[UnitPrice] AND
	InternetSales.[ExtendedAmount] = FactInternetSales.[ExtendedAmount] AND 
	InternetSales.[DiscountAmount] = FactInternetSales.[DiscountAmount] AND 
	InternetSales.[ProductStandardCost]= FactInternetSales.[ProductStandardCost] AND 
	InternetSales.[SalesAmount] = FactInternetSales.[SalesAmount] AND 
	InternetSales.[TaxAmt] = FactInternetSales.[TaxAmt] AND 
	InternetSales.FactID > FactInternetSales.FactID

让我向你展示该语句的输出。

Messages
--------
(60240 row(s) affected)

输出

Delete Duplicate Rows Example 6

使用 Group By Having 子句删除重复行

此示例展示了如何使用 LEFT JOIN、MIN 函数、GROUP BY 和 HAVING 来删除重复行。

DELETE DupFactInternetSales
 FROM DupFactInternetSales
      LEFT JOIN (
               SELECT MIN([FactID]) AS [FactID] 
                    ,[ProductKey]
		    ,[OrderQuantity]
                    ,[UnitPrice]
                    ,[ExtendedAmount]
                    ,[DiscountAmount]
                    ,[ProductStandardCost]
                    ,[TotalProductCost]
                    ,[SalesAmount]
                    ,[TaxAmt]
               FROM [DupFactInternetSales]
               GROUP BY [ProductKey],
		        [OrderQuantity]
                       ,[UnitPrice]
                       ,[ExtendedAmount]
                       ,[DiscountAmount]
                       ,[ProductStandardCost]
                       ,[TotalProductCost]
                       ,[SalesAmount]
                       ,[TaxAmt]
        ) AS InternetSales ON
        [DupFactInternetSales].[FactID] = InternetSales.[FactID]
        WHERE InternetSales.[FactID] IS NULL

让我向你展示该语句的输出。

Messages
--------
(60240 row(s) affected)