【问题标题】:SQL Delete subquery, removed duplicates recordsSQL删除子查询,删除重复记录
【发布时间】:2011-07-05 13:49:55
【问题描述】:

我正在尝试编写查询以从下表 (valid_columns) 中删除重复记录,并仅保留 [order] 编号可能最低的记录。

例如,在下表中,我想删除重复的行、区域 2,3 和作业 3,并以尽可能低的 [order] 保留记录。

例如输入表 valid_columns 如下所示:

name    col_order
-------------
job     1   
job     3   
status  2   
cust    2   
county  1   
state   1   
region  1
region  2
region  3
so      4

期望的输出:

name    col_order
-------------
job     1       
status  2   
cust    2   
county  1   
state   1   
region  1
so      4

我正在尝试修复一个错误,但我无法弄清楚 SQL。目前它使用删除语句和子查询。目前使用的查询如下所示:

-- 3) 删除重复的列

DELETE 
FROM valid_columns
WHERE   NOT ( col_order = ( SELECT  TOP 1 col_order 
            FROM    valid_columns   firstValid
            WHERE   name = firstValid.name
            AND col_order = firstValid.col_order
            ORDER BY col_order ASC ))

但是,这只会返回以下内容,这是不正确的:

name    col_order
-------------
job     1
county  1
state   1
region  1

非常感谢

【问题讨论】:

    标签: .net sql-server sql-server-2005 tsql


    【解决方案1】:
    DELETE FROM t1
    FROM valid_columns t1
    WHERE col_order > 
        (SELECT MIN(col_order) from valid_columns t2 WHERE t1.name = t2.name)
    

    编辑: 可以简化为:

       DELETE FROM valid_columns 
       WHERE col_order > 
            (SELECT MIN(col_order) from valid_columns t2 WHERE valid_columns.name = t2.name)
    

    DELETE 语句可以有一个 FROM 子句来根据第二个表中相关记录的值删除记录。在这种情况下,实际上并不需要 FROM(我有时会使用 FROM 为表名命名,因为我不喜欢额外的输入。)

    DELETE FROM TableA
    FROM TableA 
    JOIN TableB On TableA.CriteriaA = TableB.CriteriaA
    

    你也可以试试这个例子(如果你经常这样做可能会更快):

    DELETE FROM valid_columns 
    WHERE EXISTS
        (SELECT * FROM valid_columns t1 
         WHERE t1.name = valid_columns.name AND valid_columns.col_order > t1.col_order);
    

    【讨论】:

    • 在 where 子句中使用相关子查询时我有点困惑,您能否简要扩展您的答案。看起来它会起作用。
    【解决方案2】:
    -- Test table
    declare @T table(Name varchar(10), col_order int)
    
    -- Sample data
    insert into @T
    select 'job',     1 union all
    select 'job',     3 union all
    select 'status',  2 union all
    select 'cust',    2 union all
    select 'county',  1 union all
    select 'state',   1 union all
    select 'region',  1 union all
    select 'region',  2 union all
    select 'region',  3 union all
    select 'so',      4
    
    -- Delete using CTE and row_number()
    ;with cte as
    (
      select row_number() over(partition by Name order by col_order) as rn
      from @T
    )
    delete from cte
    where rn > 1
    
    -- Result
    select *
    from @T
    

    或者用子查询代替 CTE

    delete vc
    from (select row_number() over(partition by Name order by col_order) as rn
          from valid_columns) as vc
    where vc.rn > 1      
    

    【讨论】:

      【解决方案3】:

      试试这个(您可以用选择替换删除,以确保在删除之前获得正确的结果)。

      DELETE FROM [valid_columns] t1
      WHERE col_order > (SELECT MIN(col_order) from [valid_columns] t2 
              WHERE t1.name = t2.name)
      

      【讨论】:

        【解决方案4】:

        这应该可以满足您的需要:

        DELETE FROM valid_columns a
        WHERE (SELECT MAX(col_order)
            FROM valid_columns b
            WHERE a.name = b.name) > a.col_order;
        

        不过,我建议您在测试之前备份数据。

        【讨论】:

          【解决方案5】:

          使用二进制校验和删除记录(适用于任何 sql server 版本)

          创建表#t1(ID INT NULL,VALUE VARCHAR(2)) 插入#t1(ID,VALUE)值(1,'aa') 插入#t1(ID,VALUE)值(2,'bb') 插入#t1(ID,VALUE)值(1,'aa') 插入#t1(ID,VALUE)值(1,'aa') 插入#t1(ID,VALUE)值(3,'cc') 插入#t1(ID,VALUE)值(3,'cc') 去 -- BINARY_CHECKSUM(): 是我们想要比较重复的列 -- 如果你想比较整行然后改变 BINARY_CHECKSUM() -> BINARY_CHECKSUM(*) -- 对于 SQL Server 2000+ 一个循环 -- 保存重复的校验和和行数 SELECT BINARY_CHECKSUM(ID, VALUE) AS ChkSum, COUNT(*) AS Cnt 进入#t2 从#t1 GROUP BY BINARY_CHECKSUM(ID, VALUE) HAVING COUNT(*)>1 声明@ChkSum BIGINT,@rc INT -- 获取第一个校验和并将 rowcount 设置为 count - 1 -- 因为我们想留下一个重复 SELECT TOP 1 @ChkSum = ChkSum, @rc = Cnt-1 FROM #t2 存在时(从 #t2 中选择 *) 开始 -- 行数比重复行数少一 设置行数@rc 从#t1 中删除 BINARY_CHECKSUM(ID, VALUE) = @ChkSum -- 从校验和表中删除处理过的重复项 删除 #t2 其中 ChkSum = @ChkSum -- 选择下一个要删除的重复行 SELECT TOP 1 @ChkSum = ChkSum, @rc = Cnt-1 FROM #t2 结尾 设置行数 0 去 选择 * 从 #t1 -- 对于 SQL Server 2005+ 一个很酷的 CTE ;带编号 作为 ( SELECT ROW_NUMBER() OVER (PARTITION BY ChkSum ORDER BY ChkSum) AS RN, * 从 ( 选择 BINARY_CHECKSUM(ID, VALUE) 作为校验和 从#t1 ) 吨 ) 从编号中删除,其中 RN > 1; 去 选择 * 从 #t1 删除表#t1; 删除表#t2;

          【讨论】:

            【解决方案6】:

            或者您可以使用游标遍历表并插入临时表中某个项目遇到的第一个值(确保临时表具有为 name 列指定的唯一约束)。

            编辑:为了方便起见,我已经包含了一个代码 sn-p...

            declare @Ti table(name varchar(10), col_order int);
            declare @Tf table(name varchar(10) unique not null, col_order int not null);
            
            declare @name varchar(10);
            declare @col_order int;
            
            -- Sample data
            insert into @Ti
            select 'job',     1 union all
            select 'job',     3 union all
            select 'status',  2 union all
            select 'cust',    2 union all
            select 'county',  1 union all
            select 'state',   1 union all
            select 'region',  1 union all
            select 'region',  2 union all
            select 'region',  3 union all
            select 'so',      4
            
            select * from @Ti
            
            declare i cursor for
                select * from @Ti;
            
            open i;
            fetch next from i into @name, @col_order;
            
            while @@FETCH_STATUS = 0
            begin
                if not exists( select * from @Tf where name = @name )
                begin
                    insert into @Tf(name, col_order)
                        select @name, @col_order;
                end
            
                fetch next from i into @name, @col_order;
            end
            
            close i;
            deallocate i;
            
            select * from @Tf;
            

            【讨论】:

              猜你喜欢
              • 2016-01-07
              • 2015-08-12
              • 2010-10-24
              • 1970-01-01
              • 2015-04-04
              • 2020-02-17
              • 2016-11-30
              • 2020-07-16
              • 2021-02-13
              相关资源
              最近更新 更多