を作成せずに重複レコードを削除します。は、私は多くの重複レコードを持つテーブルが一時テーブル
shop
ID tax_id
1 10
1 10
1 11
2 10
2 12
2 10
2 10
私は一時テーブルを作成することなく、すべての重複レコードを削除したいです。 更新クエリの後、表は次のようになります。
shop
ID tax_id
1 10
1 11
2 10
2 12
を作成せずに重複レコードを削除します。は、私は多くの重複レコードを持つテーブルが一時テーブル
shop
ID tax_id
1 10
1 10
1 11
2 10
2 12
2 10
2 10
私は一時テーブルを作成することなく、すべての重複レコードを削除したいです。 更新クエリの後、表は次のようになります。
shop
ID tax_id
1 10
1 11
2 10
2 12
ここでインプレースソリューション(ただし、ワンライナー)です
最大のidを調べる:
select max(id) as maxid
from shop;
は、この値を覚えておいてください。それが1000に等しいとしよう。
で、一意の値を再度挿入オフセット:
insert into shop (id, tax_id)
select distinct id + 1000, tax_id
from shop;
ドロップ古い値:
update shop
set id = id - 1000;
利益:
delete from shop
where id <= 1000;
は、通常のIDを復元します!
これまでのところ、このソリューションはすべての基準に一致する唯一のソリューションです。代わりにそれをupvoteする必要があります。 :-) –
エントリを複製することは丁度良い練習や実用的ではないことは、記録 の小さな数以上とテーブルの上にこれを実装する想像INSERT文はtax_idの無差別であるためのみに応じて2つの(おそらく間違って保存しますテーブルがソートされているかどうかは関係ありません)。 – CBusBus
これは、500回/秒で実行する操作ではありません。これはデータ破損の修正です。数秒かかる場合でも、それは容認されるべきです(状況によっては)。私は、あなたが話している無差別を知りませんが、この解決策はOPが探している答えを正確に示しています。 –
まず第一に、あなたは今後の参考のために、これらの二つのフィールドに一意のインデックスを作成することでこれを防ぐことができます。
液として、MySQLでは同じ構造を持つ新しいテーブルshopnew
を作成するか、または単にレコードリストが生成されたテーブルからすべてのレコードを削除する(バックアップを持っていることを確認してください!):
//Get every record from mysql
$sSQL = "Select ID, tax_id from shop";
$oRes = mysql_query($sSQL);
$aRecordList = array();
while($aRow = mysql_fetch_assoc($oRes)){
//If record is a duplicate, it will be 'overwritten'
$aRecordList[$aRow['id'].".".$aRow['tax_id']] =1;
}
//You could delete every record from shop here, if you dont want an additional table
//recordList now only contains unique records
foreach($aRecordList as $sRecord=>$bSet){
$aExpRecord = explode(".",$sRecord);
mysql_query("INSERT INTO shopnew set id=".$aExpRecord[0].", tax_id = ".$aExpRecord[1]
}
この例では、IDもtax_idも一意ではありません。各ショップには複数のtax_idが関連付けられています。 – Grexis
はい、両方でユニークなインデックスを作成できます!それがあなたが探しているものです。したがって、2つのフィールドを組み合わせて表示することはできません。チェック:http://www.mysqlfaqs.net/mysql-faqs/Indexes/Unique-Key-or-Index/How-to-create-multi-column-unique-key-or-index-in-MySQL –
うん、そう?彼の解決策は、対(id、tax_id)の一意性を維持する(少なくとも、私が知る限り)。新しいテーブルを作成しないという条件に違反しますが。 –
解決策。
$res = mysql_query("SELECT id, tax_id, count(*) - 1 AS cnt
FROM shop
GROUP BY id
HAVING cnt > 1")
while($row = mysql_fetch_assoc($res)){
mysql_query("DELETE
FROM shop
WHERE id=".$row['id']."
AND tax_id=". $row['tax_id']."
LIMIT ".$row['cnt'] -1 . ");
}
編集、削除を行うために
//Sql query to find duplicates
SELECT id, tax_id, count(*) - 1 AS cnt
FROM shop
GROUP BY id
HAVING cnt > 1
--- res
+------+--------+-----+
| id | tax_id | cnt |
+------+--------+-----+
| 1 | 10 | 2 |
| 2 | 10 | 3 |
+------+--------+-----+
//Iterate through results with your language of choice
DELETE
FROM shop
WHERE id=<res id>
AND tax_id=<res tax_id>
LIMIT <cnt - 1>
---res (iterated)
+------+--------+
| id | tax_id |
+------+--------+
| 1 | 10 |
| 1 | 11 |
| 2 | 12 |
| 2 | 10 |
+------+--------+
2つのクエリは、PHPの小片が必要になります:それは価値がある何のために、この最近再考、ここでは一時的なカラムを用いた代替ソリューションですスクリプト言語の必要性を排除します。
ALTER TABLE shop ADD COLUMN place INT;
SET @i = 1
UPDATE shop SET place = @i:= @i + 1;
DELETE FROM shop WHERE place NOT IN (SELECT place FROM items GROUP BY id, tax_id);
ALTER TABLE shop DROP COLUMN place;
実際には、現在の制限事項は非常に難しい課題です。私は夕方の解決策について考えました(解決策が決して使用されないことを理解する)。私は野生の自然の中でこのソリューションを使用しませんでしたが、MySQLを使用することが可能かどうかを調べようとしました。
私の定式化の質問:重複する行を一意の制約なしに2列のテーブルから削除する一連のDELETE文を書くことは可能ですか?
問題:1が
ORDER BY
をサポートするDELETE
の形式はWHERE
句しか持つことができず、HAVING
をサポートしません。つまり、条件が満たされた後に注文が適用されます。たちは、テーブルがあるとします。
CREATE TABLE `tablename` (
`a_id` int(10) unsigned NOT NULL,
`b_id` int(10) unsigned NOT NULL,
KEY `Index_1` (`a_id`,`b_id`)
) ENGINE=InnoDB COLLATE utf8_bin;
私はより速く検索を行うために(UNIQUEまたはPRIMARYない)のキーを追加し、グループでそれを使用することを望んで。
あなたはいくつかの値を持つテーブルを養うことができ:
INSERT INTO tablename (a_id, b_id) VALUES (2, 3), (1, 1), (2, 2), (1,4);
INSERT INTO tablename (a_id, b_id) VALUES (2, 3), (1, 1), (2, 2), (1,4);
INSERT INTO tablename (a_id, b_id) VALUES (2, 3), (1, 1), (2, 2), (1,4);
を副作用として、キーは、カバレッジ指標となり、私たちはテーブルからのSELECTを行う際に表示される値はソートされているが、我々は削除を行うとき値は挿入された順に読み込まれます。
SELECT @c, @a_id as a, @b_id as b, a_id, b_id
FROM tablename, (SELECT @a_id:=0, @b_id:=0, @c:=0) as init
WHERE (@c:=IF(LEAST(@a_id=(@a_id:=a_id), @b_id=(@b_id:=b_id)), @c+1, 1)) >= 1
;
し、その結果を::
それでは、次のクエリを見てみましょう
@c, a, b, a_id, b_id
1, 1, 1, 1, 1
2, 1, 1, 1, 1
3, 1, 1, 1, 1
1, 1, 4, 1, 4
2, 1, 4, 1, 4
3, 1, 4, 1, 4
1, 2, 2, 2, 2
2, 2, 2, 2, 2
3, 2, 2, 2, 2
1, 2, 3, 2, 3
2, 2, 3, 2, 3
3, 2, 3, 2, 3
結果が自動的にIndex_1
を使用してソートされ、重複ペア(a_id, b_id)
は、列@c
に列挙されています。今私たちの仕事は、すべての行を削除することです。@c > 1
。私たちが持っている唯一の問題は、追加の条件を適用せずに、MySQLを使用することをやめさせることです(強制的に削除するにはIndex_1
です)。しかし、我々はa_id
上の平等のチェックや、複数の平等のチェックを使用してこれを行うことができます。
DELETE FROM t
USING tablename t FORCE INDEX (Index_1)
JOIN (SELECT @a_id:=0, @b_id:=0, @c:=0) as init
WHERE a_id IN (1)
AND (@c:=IF(LEAST(@a_id=(@a_id:=a_id), @b_id=(@b_id:=b_id)), @c+1, 1)) > 1;
DELETE FROM t
USING tablename t FORCE INDEX (Index_1)
JOIN (SELECT @a_id:=0, @b_id:=0, @c:=0) as init
WHERE a_id IN (2)
AND (@c:=IF(LEAST(@a_id=(@a_id:=a_id), @b_id=(@b_id:=b_id)), @c+1, 1)) > 1;
SELECT * FROM tablename t;
a_id, b_id
1, 1
1, 4
2, 2
2, 3
私はIN()
内のすべての可能なa_id
を置くことはできませんMySQLはインデックスが、この場合には役に立たないとクエリがないことを理解するため、すべての重複を削除します(隣接しているだけですが、10通りあります)a_id
2つのDELETE文で重複を削除できます。各INには5つの明示的なIDがあります。
希望、これは=誰かの役に立つかもしれません)
多分これは役立ちます。
$query="SELECT * FROM shop ORDER BY id";
$rez=$dbh->query($query);
$multi=$rez->fetchAll(PDO::FETCH_ASSOC);
foreach ($multi as $key=>$row){
$rest=array_slice($multi,$key+1);
foreach ($rest as $rest){
if(($row['id']==$rest['id']) && ($row['tax_id']==$rest['tax_id'])){
$dbh->query("DELETE FROM shop WHERE id={$rest['id']} and tax_id= {$rest['tax_id']}");
}
}
}
まずforeach
反復するすべての行、およびcomparationをやっ秒1。 私はPDOを使用していますが、もちろん、手続き的なやり方で行うことができます。
一時テーブルに問題がありますか? –
dublicateとは何ですか?ID/tax_idが同じ値を持っているか、あなたは、同じIDを持つ複数の行を持っている場合ならば - – Rufinus
@SergeiTulentsev(IDは一意である必要がありPK、あるべきか、あなたの「ID」をFKで):それはスペースをとります。 –