删除重复的SQL记录以允许唯一键

时间:2010-05-18 22:28:15

标签: sql mysql join

我在MYSQL数据库中有一个表('sales'),它应该有一个强制执行的唯一约束来防止重复。首先删除欺骗并设置约束证明有点棘手。

表结构(简化):

  • 'id(unique,autoinc)'
  • PRODUCT_ID

目标是强制执行product_id的唯一性。我想要应用的重复数据删除策略是删除除最近创建的所有重复记录,例如:最高ID。

或者换句话说,我想只删除重复记录,不包括与以下查询匹配的ID,同时还保留现有的非duped记录:

select id 
  from sales s  
inner join (select product_id, 
                   max(id) as maxId 
              from sales 
          group by product_id 
            having count(product_id)  > 1) groupedByProdId on s.product_id 
                                                          and s.id = groupedByProdId.maxId

我在两个方面都在努力解决这个问题 - 编写查询以选择要删除的正确记录,然后编写MYSQL中的约束,其中DELETE的子选择FROM子句不能引用从中删除数据的同一个表。

我检查了this的答案,它似乎处理了这个主题,但似乎特定于sql-server,但我不会将这个问题排除在复制另一个问题之外。

4 个答案:

答案 0 :(得分:11)

在回复您的评论时,这是一个适用于MySQL的查询:

delete YourTable
from YourTable
inner join YourTable yt2
on YourTable.product_id = yt2.product_id
and YourTable.id < yt2.id

这只会删除重复的行。即使同一产品没有其他行,inner join也会过滤掉每个产品的最新行。

P.S。如果您尝试在FROM之后对表进行别名,则MySQL要求您指定数据库的名称,如:

delete <DatabaseName>.yt
from YourTable yt
inner join YourTable yt2
on yt.product_id = yt2.product_id
and yt.id < yt2.id;

答案 1 :(得分:7)

也许使用ALTER IGNORE TABLE ... ADD UNIQUE KEY。 例如:

describe sales;
+------------+---------+------+-----+---------+----------------+
| Field      | Type    | Null | Key | Default | Extra          |
+------------+---------+------+-----+---------+----------------+
| id         | int(11) | NO   | PRI | NULL    | auto_increment | 
| product_id | int(11) | NO   |     | NULL    |                | 
+------------+---------+------+-----+---------+----------------+

select * from sales;
+----+------------+
| id | product_id |
+----+------------+
|  1 |          1 | 
|  2 |          1 | 
|  3 |          2 | 
|  4 |          3 | 
|  5 |          3 | 
|  6 |          2 | 
+----+------------+

ALTER IGNORE TABLE sales ADD UNIQUE KEY idx1(product_id), ORDER BY id DESC; 
Query OK, 6 rows affected (0.03 sec)
Records: 6  Duplicates: 3  Warnings: 0


select * from sales;
+----+------------+
| id | product_id |
+----+------------+
|  6 |          2 | 
|  5 |          3 | 
|  2 |          1 | 
+----+------------+

有关详细信息,请参阅此pythian post

请注意,id以相反的顺序结束。我认为这不重要,因为id的顺序在数据库中无关紧要(据我所知!)。但是,如果这让您感到不满,那么上面链接的帖子也会显示解决此问题的方法。但是,它涉及创建一个临时表,它需要比我上面发布的就地方法更多的硬盘空间。

答案 2 :(得分:1)

我可能会在sql-server中执行以下操作来消除重复项:

DELETE FROM Sales
FROM Sales
    INNER JOIN Sales b ON Sales.product_id = b.product_id AND Sales.id < b.id

看起来mysql的类似delete语句可能是:

DELETE FROM Sales 
USING Sales
    INNER JOIN Sales b ON Sales.product_id = b.product_id AND Sales.id < b.id

答案 3 :(得分:0)

使用CTE和排名函数可以更容易地解决这类问题,但是,您应该可以执行以下操作来解决问题:

Delete Sales
Where Exists(
            Select 1
            From Sales As S2
            Where S2.product_id = Sales.product_id
                And S2.id > Sales.Id
            Having Count(*) > 0
            )
相关问题