51

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

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

4

18 回答 18

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

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

于 2013-10-25T13:40:02.857 回答
35

解决您的问题的一种选择是创建具有相同架构的新表,然后执行以下操作:

INSERT INTO new_table (SELECT DISTINCT * FROM old_table)

然后只是重命名表。

当然,您需要的空间量与您的表所​​需的磁盘空间量大致相同!

它效率不高,但非常简单。

于 2013-05-08T13:30:05.557 回答
24

请注意,MySQL 有自己的扩展名DELETE,即DELETE ... LIMIT,它以您期望的通常方式工作:http LIMIT: //dev.mysql.com/doc/refman/5.0/en/delete.html

用于 DELETE 的 MySQL 特定的 LIMIT row_count 选项告诉服务器在将控制权返回给客户端之前要删除的最大行数。这可用于确保给定的 DELETE 语句不会花费太多时间。您可以简单地重复 DELETE 语句,直到受影响的行数小于 LIMIT 值。

因此,您可以使用DELETE FROM some_table WHERE x="y" AND foo="bar" LIMIT 1;注意,没有一种简单的方法可以说“删除除一个之外的所有内容” - 只需继续检查您是否仍有行重复项。

于 2013-05-08T11:54:09.117 回答
19

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

于 2015-12-01T08:35:41.423 回答
11

这可以使用 CTE 和ROW_NUMBER()函数来完成,如下所示:

/* Sample Data */
    CREATE TABLE #dupes (ID INT, DWCreated DATETIME2(3))

    INSERT INTO #dupes (ID, DWCreated) SELECT 1, '2015-08-03 01:02:03.456'
    INSERT INTO #dupes (ID, DWCreated) SELECT 2, '2014-08-03 01:02:03.456'
    INSERT INTO #dupes (ID, DWCreated) SELECT 1, '2013-08-03 01:02:03.456'

/* Check sample data - returns three rows, with two rows for ID#1 */
    SELECT * FROM #dupes 

/* CTE to give each row that shares an ID a unique number */
    ;WITH toDelete AS
      (
        SELECT ID, ROW_NUMBER() OVER (PARTITION BY ID ORDER BY DWCreated) AS RN
        FROM #dupes 
      )

  /* Delete any row that is not the first instance of an ID */
    DELETE FROM toDelete WHERE RN > 1

/* Check the results: ID is now unique */
    SELECT * FROM #dupes

/* Clean up */
    DROP TABLE #dupes

有一列 ORDER BY 很方便,但不是必需的,除非您对要删除的行有偏好。这也将处理所有重复记录的实例,而不是强制您一次删除一行。

于 2016-02-05T16:41:20.203 回答
9

对于 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 将是具有重复值的列集。

参考这里

于 2016-11-07T13:52:48.550 回答
6

尝试过限制 1?这只会删除与您的DELETE查询匹配的 1 行

DELETE FROM `table_name` WHERE `column_name`='value' LIMIT 1;
于 2016-12-31T01:20:08.290 回答
4

如果您可以添加一列,例如

  ALTER TABLE yourtable ADD IDCOLUMN bigint NOT NULL IDENTITY (1, 1)

这样做。

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

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

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

于 2013-05-08T11:59:44.137 回答
4

这适用于 PostgreSQL

DELETE FROM tablename WHERE id = 123 AND ctid IN (SELECT ctid FROM tablename WHERE id = 123 LIMIT 1)
于 2018-01-16T21:09:52.117 回答
3

在我的情况下,我可以让 GUI 给我一串相关行的值(或者,我可以手动完成)。在一位同事的建议下,我仍然欠他的债,我用它来创建一个 INSERT 语句:

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

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

DELETE FROM some_table WHERE logid = 'ID1219243408800307444663';

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

于 2013-05-08T10:29:20.070 回答
3

您可以使用最大值,这与我的情况相关。

DELETE FROM [table] where id in 
(select max(id) from [table] group by id, col2, col3 having count(id) > 1)

一定要先测试你的结果,并在你的“有”分句中有一个限制条件。对于如此庞大的删除查询,您可能需要先更新数据库。

于 2017-09-18T10:09:12.160 回答
0

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

于 2014-01-16T12:31:33.460 回答
0

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

delete from Employee
where id not in (select MAX(id)
                  from Employee
                  group by (id,name,age)
                );
于 2021-06-13T01:37:57.643 回答
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
))
于 2019-09-17T03:10:18.067 回答
0

PostgreSQL中有一个名为ctid. 见维基。因此,您可以自由使用以下内容:

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;在实际进行清理之前做一个是明智的。

于 2017-04-11T11:06:03.483 回答
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 
于 2019-04-15T20:35:21.683 回答
0
delete top(1) tableNAme 
where --your conditions for filtering identical rows
于 2022-03-05T12:58:14.457 回答
0

您可以使用限制 1

这对我来说非常适合 MySQL

delete from `your_table` [where condition] limit 1;
于 2021-10-07T08:38:28.263 回答