如何在2列中查找重复项而不是1


107

我有一个MySQL数据库表,其中有两列令我感兴趣。它们各自可以分别具有重复项,但是它们绝不能具有相同的值。

stone_id只要每个upsharge标题不同,就可以重复,反之亦然。但是例如说stone_id= 412和upcharge_title=“蓝宝石”,则该组合仅应发生一次。

还行吧:

stone_id = 412 upcharge_title = "sapphire"
stone_id = 412 upcharge_title = "ruby"

这不行:

stone_id = 412 upcharge_title = "sapphire"
stone_id = 412 upcharge_title = "sapphire"

是否有一个查询,将在两个字段中找到重复项?如果可能的话,是否有办法将我的数据库设置为不允许这样做?

我正在使用MySQL 4.1.22版

Answers:


192

您应该在两个字段之间设置一个复合键。每行需要一个唯一的stone_id和upcharge_title。

至于找到现有重复项,请尝试以下操作:

select   stone_id,
         upcharge_title,
         count(*)
from     your_table
group by stone_id,
         upcharge_title
having   count(*) > 1

谢谢,确实选择了它们。您能告诉我如何删除重复项(当然要保留1份),谢谢您!
JD Isaacks 09年

2
一种方法是获取所有不同的数据并重新创建表。
宫城编码器

1
@John Isaacks:如果没有其他可以区分它们的字段(即所有字段都是重复的),则必须删除两行并重新创建一个。一种方法是将重复项复制到表的副本中,将其从原始表中删除,然后在副本中重新插入不同的行。
P爸爸2009年

这在postgres 8.1上不起作用,有人可以帮我吗?
列侬2015年

非常感谢,您按顺序分组的顺序是否重要?
安德鲁(Andrew)

35

我发现使用“ ALTER IGNORE”添加unueue索引会有所帮助,该索引会删除重复项并强制执行唯一的记录,这听起来像是您想做的。因此语法为:

ALTER IGNORE TABLE `table` ADD UNIQUE INDEX(`id`, `another_id`, `one_more_id`);

这有效地增加了唯一性约束,这意味着您将永远不会有重复的记录,并且IGNORE会删除现有的重复项。

您可以在此处阅读有关eh ALTER IGNORE的更多信息:http : //mediakey.dk/~cc/mysql-remove-duplicate-entries/

更新:@Inquisitive通知我,这可能在MySql> 5.5版本中失败:

在MySQL> 5.5和InnoDB表上以及在Percona上,由于InnoDB快速索引创建功能[ http://bugs.mysql.com/bug.php?id=40344]而失败。在这种情况下,请先运行set session old_alter_table=1,然后执行上面的命令

更新- ALTER IGNORE在5.7中删除

来自文档

从MySQL 5.6.17开始,不推荐使用IGNORE子句,使用它会生成警告。IGNORE在MySQL 5.7中已删除。

MySQL开发人员之一提供了两种选择

  • 按唯一字段分组并删除,如上所示
  • 创建一个新表,添加唯一索引,使用INSERT IGNORE,例如:
CREATE TABLE duplicate_row_table LIKE regular_row_table;
ALTER TABLE duplicate_row_table ADD UNIQUE INDEX (id, another_id);
INSERT IGNORE INTO duplicate_row_table SELECT * FROM regular_row_table;
DROP TABLE regular_row_table;
RENAME TABLE duplicate_row_table TO regular_row_table;

但是根据您的桌子的大小,这可能不切实际


1
没错,但至少您下次知道。我遇到了同样的问题,并认为与其他人分享非常好
SeanDowney 2012年

我只是开玩笑说晚了三年。真的很高兴与您分享。因此,加1
JD Isaacks

我想这会任意删除重复项之一,因此请确保每行之间没有不同的数据,这些数据可能对了解或保留有用。
约书亚·品特

即使迟到了2年,答案还是+1。我不小心删除了一个组合键,这可以节省生命。谢谢
ivcode 2014年

我尝试了几种重复查找器技术,但没有一个如此简单快捷。感谢您分享此方法。
Kristjan O. 2014年

8

您可以找到类似的重复项。

Select
    stone_id, upcharge_title, count(*)
from 
    particulartable
group by 
    stone_id, upcharge_title
having 
    count(*) > 1

4

要查找重复项:

select stone_id, upcharge_title from tablename group by stone_id, upcharge_title having count(*)>1

为了限制将来避免这种情况,请在这两个字段上创建一个复合唯一键。


1
非常感谢,能否请您告诉我如何删除除重复项之外的所有重复项。以及如何在phpmyadmin中设置compisite密钥。谢谢!!!
JD Isaacks 09年

3

顺便说一句,表上的复合唯一约束将阻止这种情况的发生。

ALTER TABLE table
    ADD UNIQUE(stone_id, charge_title)

(这是有效的T-SQL。不确定MySQL。)


1
我认为可以,但是除非我先删除重复项,否则我不会这么做。谢谢。
JD Isaacks 09年

1

这篇SO帖子对我有所帮助,但我也想知道如何删除并保留其中的一行...这是一个PHP解决方案,用于删除重复的行并保留其中一列(在我的情况下,只有2列,并且在清除重复类别关联的功能)

$dupes = $db->query('select *, count(*) as NUM_DUPES from PRODUCT_CATEGORY_PRODUCT group by fkPRODUCT_CATEGORY_ID, fkPRODUCT_ID having count(*) > 1');
if (!is_array($dupes))
    return true;
foreach ($dupes as $dupe) {
    $db->query('delete from PRODUCT_CATEGORY_PRODUCT where fkPRODUCT_ID = ' . $dupe['fkPRODUCT_ID'] . ' and fkPRODUCT_CATEGORY_ID = ' . $dupe['fkPRODUCT_CATEGORY_ID'] . ' limit ' . ($dupe['NUM_DUPES'] - 1);
}

(限制NUM_DUPES-1)是保留单行的内容...

谢谢大家


3
ALTER IGNORE TABLE table ADD UNIQUE INDEX index_name(stone_id, charge_title)将删除重复的行,仅留下一对唯一的对。
dev-null-dweller 2010年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.