我正在清理一个没有主键的数据库表(我知道,我知道,他们在想什么?)。我无法添加主键,因为列中存在将成为键的重复项。重复值来自在所有方面都相同的两行之一。我无法通过 GUI 删除该行(在本例中为 MySQL Workbench,但我正在寻找一种与数据库无关的方法),因为它拒绝在没有主键(或至少一个 UQ NN 列)的表上执行任务,并且我无法添加主键,因为列中存在将成为键的重复项。重复值来自一个...
如何删除其中一个双胞胎?
我正在清理一个没有主键的数据库表(我知道,我知道,他们在想什么?)。我无法添加主键,因为列中存在将成为键的重复项。重复值来自在所有方面都相同的两行之一。我无法通过 GUI 删除该行(在本例中为 MySQL Workbench,但我正在寻找一种与数据库无关的方法),因为它拒绝在没有主键(或至少一个 UQ NN 列)的表上执行任务,并且我无法添加主键,因为列中存在将成为键的重复项。重复值来自一个...
如何删除其中一个双胞胎?
SET ROWCOUNT 1
DELETE FROM [table] WHERE ....
SET ROWCOUNT 0
这只会删除两个相同的行之一
解决您的问题的一种选择是创建具有相同架构的新表,然后执行以下操作:
INSERT INTO new_table (SELECT DISTINCT * FROM old_table)
然后只是重命名表。
当然,您需要的空间量与您的表所需的磁盘空间量大致相同!
它效率不高,但非常简单。
请注意,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;
注意,没有一种简单的方法可以说“删除除一个之外的所有内容” - 只需继续检查您是否仍有行重复项。
delete top(1) 适用于 Microsoft SQL Server (T-SQL)。
这可以使用 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 很方便,但不是必需的,除非您对要删除的行有偏好。这也将处理所有重复记录的实例,而不是强制您一次删除一行。
对于 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 将是具有重复值的列集。
参考这里。
尝试过限制 1?这只会删除与您的DELETE
查询匹配的 1 行
DELETE FROM `table_name` WHERE `column_name`='value' LIMIT 1;
如果您可以添加一列,例如
ALTER TABLE yourtable ADD IDCOLUMN bigint NOT NULL IDENTITY (1, 1)
这样做。
然后按您的问题列计数行分组,其中 count >1 ,这将识别您的双胞胎(或三胞胎或其他)。
然后选择您的问题列,其中它的内容等于上面标识的内容,并检查 IDCOLUMN 中的 ID。
从 IDCOLUMN 等于其中一个 ID 的表中删除。
这适用于 PostgreSQL
DELETE FROM tablename WHERE id = 123 AND ctid IN (SELECT ctid FROM tablename WHERE id = 123 LIMIT 1)
在我的情况下,我可以让 GUI 给我一串相关行的值(或者,我可以手动完成)。在一位同事的建议下,我仍然欠他的债,我用它来创建一个 INSERT 语句:
INSERT
'ID1219243408800307444663', '2004-01-20 10:20:55', 'INFORMATION', 'admin' (...)
INTO some_table;
我测试了插入语句,所以我现在有了三元组。最后,我运行了一个简单的 DELETE 来删除所有这些...
DELETE FROM some_table WHERE logid = 'ID1219243408800307444663';
然后再插入一次,给我留下一行,以及主键的明亮可能性。
您可以使用最大值,这与我的情况相关。
DELETE FROM [table] where id in
(select max(id) from [table] group by id, col2, col3 having count(id) > 1)
一定要先测试你的结果,并在你的“有”分句中有一个限制条件。对于如此庞大的删除查询,您可能需要先更新数据库。
我在表中添加了一个 Guid 列,并将其设置为为每一行生成一个新的 id。然后我可以使用 GUI 删除行。
假设我们要删除重复记录,只保留 Employee 表中的 1 个唯一记录 - Employee(id,name,age)
delete from Employee
where id not in (select MAX(id)
from Employee
group by (id,name,age)
);
如果像我一样,您不想列出数据库的所有列,则可以将每一行转换为 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
))
在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;
在实际进行清理之前做一个是明智的。
如果要删除多个重复行并且所有字段都相同,没有不同的 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
delete top(1) tableNAme
where --your conditions for filtering identical rows
您可以使用限制 1
这对我来说非常适合 MySQL
delete from `your_table` [where condition] limit 1;