如何删除两个完全相同的行中的一个?

时间:2013-05-08 10:28:42

标签: sql duplicate-removal

我正在清理没有主键的数据库表(我知道,我知道,他们在想什么?)。我无法添加主键,因为列中的副本将成为键。重复值来自两行中的一行,这两行在所有方面都相同。我无法通过GUI删除该行(在本例中是MySQL Workbench,但我正在寻找一种与数据库无关的方法),因为它拒绝在没有主键(或至少是UQ NN列)的表上执行任务,并且我无法添加主键,因为列中的副本将成为键。重复值来自一个......

如何删除其中一对双胞胎?

16 个答案:

答案 0 :(得分:52)

SET ROWCOUNT 1
DELETE FROM [table] WHERE ....
SET ROWCOUNT 0

这只会删除两个相同行中的一行

答案 1 :(得分:21)

解决问题的一个方法是创建一个具有相同模式的新表,然后执行:

INSERT INTO new_table (SELECT DISTINCT * FROM old_table)

然后只需重命名表格。

您当然需要大约相同的空间,因为您的磁盘需要备用磁盘才能执行此操作!

效率不高,但非常简单。

答案 2 :(得分:19)

请注意,MySQL有自己的DELETE扩展名DELETE ... LIMIT,它的工作方式与LIMIT DELETE FROM some_table WHERE x="y" AND foo="bar" LIMIT 1; {{1}}的通常方式相同:http://dev.mysql.com/doc/refman/5.0/en/delete.html

  

DELETE的特定于MySQL的LIMIT row_count选项告诉服务器   返回控件之前要删除的最大行数   客户端。这可以用于确保给定的DELETE语句   不花太多时间。您只需重复删除即可   声明直到受影响的行数小于LIMIT   值。

因此,您可以使用{{1}}请注意,没有一种简单的方法可以说“删除除一个以外的所有内容” - 只需继续检查是否仍有行重复。

答案 3 :(得分:10)

对于PostgreSQL,你可以这样做:

DELETE FROM tablename
WHERE id IN (SELECT id
          FROM (SELECT id, ROW_NUMBER() 
               OVER (partition BY column1, column2, column3 ORDER BY id) AS rnum
               FROM tablename) t
          WHERE t.rnum > 1);

column1,column2,column3将设置具有重复值的列。

参考here

答案 4 :(得分:6)

delete top(1)适用于Microsoft SQL Server(T-SQL)。

答案 5 :(得分:5)

这可以使用CTE和//Init float maxs[10+1]; for(int i=0; i<10+1; i++){ maxs[i] = -inf; } for(int i=0; i<size; i++){ //Is it higher than the element 0? if(data[i] > maxs[0]){ maxs[0] = data[i]; for(int j=0; j<10; j++){ if(maxs[j] > maxs[j+1]) swap(maxs[j], maxs[j+1]); else break; } } } 函数完成,如下所示:

ROW_NUMBER()

将列添加到ORDER BY非常方便,但除非您优先选择要删除的行,否则不需要。这也将处理重复记录的所有实例,而不是强制您一次删除一行。

答案 6 :(得分:4)

尝试过LIMIT 1?这只会删除与您的DELETE查询相符的1行

DELETE FROM `table_name` WHERE `column_name`='value' LIMIT 1;

答案 7 :(得分:2)

你可以使用max,这与我的情况相关。

file-path

请务必首先测试您的搜索结果,并在您的&#34; clausule。有了这么大的删除查询,您可能需要先更新数据库。

答案 8 :(得分:1)

在我的情况下,我可以获取GUI以给我一行相关行的值(或者,我可以手动完成)。根据一位同事的建议,我保留了他的债务,我用它来创建一个INSERT声明:

INSERT
'ID1219243408800307444663', '2004-01-20 10:20:55', 'INFORMATION', 'admin' (...)
INTO some_table;

我测试了insert语句,所以我现在有了三元组。最后,我运行了一个简单的DELETE来删除所有这些......

DELETE FROM some_table WHERE logid = 'ID1219243408800307444663';

然后再插入INSERT,留下一行,以及主键的明亮可能性。

答案 9 :(得分:1)

如果你可以添加像

这样的列
  ALTER TABLE yourtable ADD IDCOLUMN bigint NOT NULL IDENTITY (1, 1)

这样做。

然后计算按问题列分组的行数,其中count> 1,这将识别您的双胞胎(或三胞胎或其他)。

然后选择您的问题列,其内容等于上面标识的内容,并检查IDCOLUMN中的ID。

从您的表中删除IDCOLUMN等于其中一个ID。

答案 10 :(得分:1)

这适用于PostgreSQL

DELETE FROM tablename WHERE id = 123 AND ctid IN (SELECT ctid FROM tablename WHERE id = 123 LIMIT 1)

答案 11 :(得分:0)

我在表中添加了一个Guid列,并将其设置为每行生成一个新的id。然后我可以使用GUI删除行。

答案 12 :(得分:0)

PostgreSQL 中,有一个名为ctid的隐式列。请参阅wiki。所以你可以自由使用以下内容:

WITH cte1 as(
    SELECT unique_column, max( ctid ) as max_ctid
    FROM table_1
    GROUP BY unique_column
    HAVING count(*) > 1
), cte2 as(
    SELECT t.ctid as target_ctid
    FROM table_1 t
    JOIN cte1 USING( unique_column )
    WHERE t.ctid != max_ctid
)
DELETE FROM table_1
WHERE ctid IN( SELECT target_ctid FROM cte2 )

我不确定在有可能进行并发更新时使用它是多么安全。因此,人们可能会发现在实际进行清理之前制作LOCK TABLE table_1 IN ACCESS EXCLUSIVE MODE;是明智的。

答案 13 :(得分:0)

如果要删除多个重复的行,并且所有字段都相同,没有不同的id,表没有主键,一种选择是将具有不同的重复行保存在新表中,删除所有重复行并插入排回来。如果表很大而重复的行数很小,这将很有帮助。

---  col1 , col2 ... coln are the table columns that are relevant. 
--- if not sure add all columns of the table in the select bellow and the where clause later. 

--- make a copy of the table T to be sure you can rollback anytime , if possible
--- check the @@rowcount to be sure it's what you want
--- use transactions and rollback in case there is an error 

--- first find all with duplicate rows that are identical , this statement could be joined 
--- with the first one if you choose all columns 

select col1,col2, --- other columns as needed
  count(*) c into temp_duplicate group by col1,col2 having count(*) > 1 

--- save all the rows that are identical only once ( DISTINCT ) 

insert distinct * into temp_insert from T , temp_duplicate D where
T.col1 = D.col1 and
T.col2 = D.col2 --- and other columns if needed

--- delete all the rows that are duplicate

delete T from T , temp_duplicate D where 
T.col1 = D.col1 and
T.col2 = D.col2 ---- and other columns if needed

--- add the duplicate rows , now only once
insert into T select * from temp_insert 

--- drop the temp tables after you check all is ok 

答案 14 :(得分:0)

如果像我一样,您不想列出数据库的所有列,则可以将每一行转换为JSONB并以此进行比较。

(注意:这效率极低-请注意!)

select to_jsonb(a.*), to_jsonb(b.*)
FROM
    table a
        left join table b
on
    a.entry_date < b.entry_date
where (SELECT NOT exists(
    SELECT
    FROM jsonb_each_text(to_jsonb(a.*) - 'unwanted_column') t1
         FULL OUTER JOIN jsonb_each_text(to_jsonb(b.*) - 'unwanted_column') t2 USING (key)
    WHERE t1.value<>t2.value OR t1.key IS NULL OR t2.key IS NULL
))

答案 15 :(得分:0)

假设我们要删除重复的记录,只保留 Employee 表中的 1 个唯一记录 - Employee(id,name,age)

delete from Employee
where id not in (select MAX(id)
                  from Employee
                  group by (id,name,age)
                );