web-dev-qa-db-ja.com

1ではなく2列で重複を見つける方法

興味のある2つの列を持つMySQLデータベーステーブルがあります。個別にそれぞれが重複する可能性がありますが、同じ値を持つ両方が重複することはありません。

stone_idは、各upshargeタイトルが異なる限り、重複する可能性があります。しかし、たとえばstone_id = 412およびupcharge_title = "sapphire"その組み合わせは1回だけ発生します。

これで結構です:

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を使用しています

91
JD Isaacks

2つのフィールド間に複合キーを設定する必要があります。これには、各行に一意のstone_idとupcharge_titleが必要です。

既存の重複を見つける限り、これを試してください:

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

「ALTER IGNORE」を使用して一意のインデックスを追加すると、重複を削除し、やりたいように聞こえる一意のレコードを適用するのに役立つことがわかりました。したがって、構文は次のようになります。

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

これにより、一意の制約が効果的に追加されます。つまり、重複レコードは決して存在せず、IGNOREは既存の重複を削除します。

ALTER IGNOREの詳細については、こちらをご覧ください: http://mediakey.dk/~cc/mysql-remove-duplicate-entries/

更新:MySql> 5.5のバージョンではこれが失敗する可能性があることを@Inquisitiveから通知されました。

MySQL> 5.5およびInnoDBテーブル、およびInnoDB高速インデックス作成機能[ http://bugs.mysql.com/bug.php?id=40344] が原因でPerconaで失敗します。この場合、最初にset session old_alter_table=1を実行すると、上記のコマンドは正常に動作します

アップデート-ALTER IGNORE 5.7で削除

docs から

MySQL 5.6.17の時点で、IGNORE句は廃止され、その使用は警告を生成します。 IGNOREはMySQL 5.7で削除されました。

MySQL開発者が提供するものの1つ 2つの選択肢

  • 一意のフィールドでグループ化し、上記のように削除します
  • 新しいテーブルを作成し、一意のインデックスを追加し、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;

しかし、テーブルのサイズによっては、これは実用的ではない場合があります

33
SeanDowney

このような重複を見つけることができます。

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

重複を見つけるには:

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

今後これを避けるように制約するには、これらの2つのフィールドに複合一意キーを作成します。

4
Ian Nelson

ちなみに、テーブルに複合一意制約があると、そもそもこれが発生しなくなります。

ALTER TABLE table
    ADD UNIQUE(stone_id, charge_title)

(これは有効なT-SQLです。MySQLについてはわかりません。)

3
P Daddy

このSO投稿は助けてくれましたが、私も行の1つを削除して保持する方法を知りたいと思いました...重複行を削除して1つを保持する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)は、単一の行を保持するものです...

皆さんありがとう

0
groovenectar