【问题标题】:MSSQL: procedure to remove duplicatesMSSQL:删除重复项的过程
【发布时间】:2016-04-15 12:07:25
【问题描述】:

考虑没有任何主键或外键的表。 我想编写一个程序来删除给定表名的所有重复行。

如果所有字段都相同,则该行应被视为与其他行重复。

如果可能的话,你能建议我吗?我尝试过的一件事是按每个领域进行分组,但这种方法并不通用。

【问题讨论】:

标签: sql sql-server tsql stored-procedures distinct


【解决方案1】:

您可以使用 Dynamic-SQL 实现它

快速支持的解决方案(很大的改进空间):

CREATE TABLE tab1(a INT, b INT);
INSERT INTO tab1(a,b) VALUES (1,1),(1,1),(1,1),(2,3);
GO

程序:

CREATE PROCEDURE dbo.remove_duplicates
    @tab_name SYSNAME
    ,@debug BIT = 0
AS
BEGIN
    SET NOCOUNT ON;
    -- TODO: validation if table does not exist, raise error
    -- TODO: Add @schema parameter
    -- TODO: Wrap with BEGIN TRY, omit calculated columns, CAST `TEXT/IMAGE/BINARY`....

    DECLARE @sql NVARCHAR(MAX) = 
       'WITH cte AS
        (
            SELECT *, rn = ROW_NUMBER() OVER(PARTITION BY <cols> ORDER BY (SELECT 1))
            FROM <tab_placeholder>
        )
        DELETE FROM cte
        WHERE rn <> 1;';

    DECLARE @cols NVARCHAR(MAX) = STUFF((SELECT ',' +  column_name
                                         FROM INFORMATION_SCHEMA.COLUMNS
                                         WHERE TABLE_NAME = @tab_name
                                           AND TABLE_SCHEMA = 'dbo'
                                         FOR XML PATH('')), 1, 1, '');    

    SET @sql = REPLACE(@sql, '<tab_placeholder>', QUOTENAME(@tab_name));
    SET @sql = REPLACE(@sql, '<cols>', @cols);

    IF @debug = 1 SELECT @sql;

    EXEC dbo.sp_executesql @sql;    

END
GO

执行:

EXEC [dbo].[remove_duplicates] @tab_name = 'tab1', @debug = 1;
SELECT * FROM tab1;

LiveDemo

【讨论】:

  • 谢谢,实际上我正在寻找不依赖表格列的通用方法。但最终,即使在这里,你也得到了它们,然后分开。但这解决了我被接受的问题。
  • 你必须依赖表列的情况(一种或另一种方式):) 没有 SELECT * FROM tab GROUP BY * 这样的东西 :)
【解决方案2】:

这将从表中删除重复项。您的分区依据必须包含您希望分组的字段以确定重复项是什么。在你的情况下,所有这些。

IF OBJECT_ID('tempdb..#TABLE') IS NOT NULL DROP TABLE #TABLE

CREATE TABLE #TABLE ( SOMEINT INT,SOMEVALUE VARCHAR(255) )
INSERT INTO #TABLE ( SOMEINT, SOMEVALUE )
VALUES (1,'VALUE1')
,(1,'VALUE2')
,(1,'VALUE2')
,(1,'VALUE3')
,(1,'VALUE4')
,(1,'VALUE4')
,(1,'VALUE4')
,(1,'VALUE4')
,(1,'VALUE5')
,(1,'VALUE6')
,(1,'VALUE6')
,(1,'VALUE6')
,(1,'VALUE7')
,(1,'VALUE8')
,(1,'VALUE8')
,(1,'VALUE9')
,(1,'VALUE10')

;WITH dedup
AS
( 
SELECT *, ROW_NUMBER() OVER (PARTITION BY SOMEINT,SOMEVALUE ORDER BY SOMEINT ASC) AS SEQUENCE
FROM #TABLE
)
DELETE
FROM dedup
WHERE SEQUENCE > 1
GO

SELECT * FROM #TABLE

【讨论】:

    【解决方案3】:

    有很多方法

    首先,

    创建一个临时表,并将不同的数据复制到该临时表。从您的实际表中删除或截断数据。并将临时表复制到您的实际表中。删除临时表

    SELECT DISTINCT * INTO #table1 from TABLE1
    DELETE FROM TABLE1
    INSERT INTO TABLE1
    SELECT * FROM #table1
    DROP TABLE #table1
    

    第二,

    向表中添加一列,使用 ROW_NUMBER PARTITION 更新该列,然后删除 COLUMN 1 的行。删除新创建的列。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-09-13
      • 2018-10-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-04-07
      • 2011-03-24
      相关资源
      最近更新 更多