重複するタプルの発生を特定するの(UserID,IPA)
は非常に簡単です。
SELECT s.UserID
, s.IPA
FROM mytable s
GROUP
BY s.UserID
, s.IPA
HAVING COUNT(1) > 1
最低スコアを取得するMIN(s.Score)
には、選択リストに追加できます。
重複を削除することは、一意性の保証がないように見えるという点で、もう少し困難です。除外したい行を別のテーブルにコピーしてから、名前を変更してテーブルを交換するか、元のテーブルを切り捨てて新しいテーブルから再ロードすることをお勧めする人もいます。(通常、これが最も効率的なアプローチであることが判明します。)
CREATE TABLE newtable LIKE mytable ;
INSERT INTO newtable (UserID,IPA,Score)
SELECT s.UserID
, s.IPA
, MIN(Score) AS Score
FROM mytable s
GROUP
BY s.UserID
, s.IPA ;
UserID だけで重複を識別したい場合は、同じアプローチが機能します。IPA 値がスコアが最も低い行から取得されることが重要でない場合は、少し簡単です。ユーザーのスコアが最も低い行を取得するクエリをまとめることができます。
各行に一意の識別子 (AUTO_INCREMENT id 列など) を追加せずに、既存のテーブルから行を削除することもできます。
これにより、最低スコアよりも高いスコアを持つ特定の (UserID,IPA) のすべての行が削除され、途中で取得されます。
DELETE t.*
FROM mytable t
JOIN ( SELECT s.UserID
, s.IPA
, MIN(s.Score)
FROM mytable s
GROUP
BY s.Userid
, s.IPA
) k
ON k.UserID = t.UserID
AND k.IPA = t.IPA
AND k.Score < t.Score
(UserID,IPA,Score)
しかし、それでも重複するタプルの重複が残ります。テーブルに行を一意にする他の列がないと、重複を削除するのが少し難しくなります。(ここでも、保持したい行を別のテーブルにコピーし、テーブルを交換するか、保存された行から元のテーブルをリロードするという手法が一般的です。
ファローアップ
ビューは一時的な MyISAM テーブル (MySQL はそれらを「派生テーブル」と呼びます) として実体化されるため、MySQL ではビュー (ストアド ビューとインライン ビューの両方) のパフォーマンスが高くなる可能性があることに注意してください。
しかし、相関サブクエリは、大規模なセットではさらに問題になる可能性があります。
だから、あなたの毒を選んでください。
テーブルにインデックスがある場合ON (userID, Score, IPA)
、結果セットを取得する方法は次のとおりです。
SELECT IF(@prev_user=t.UserID,@i:=@i+1,@i:=1) AS seq
, @prev_user := t.UserID AS UserID
, t.IPA
, t.Score
FROM mytable t
JOIN (SELECT @i := NULL, @prev_user := NULL) i
GROUP
BY t.UserID ASC
, t.Score ASC
, t.IPA ASC
HAVING seq = 1
これは、いくつかの MySQL 固有の機能を利用しています: user_variables と、GROUP BY がソートされた結果セットを返すという保証です。(EXPLAIN の出力には "Using index" と表示されます。これは、並べ替え操作を回避することを意味しますが、クエリは引き続き派生テーブルを作成します。user_variables を使用して、各 UserID の "最初の" 行を識別し、HAVING 句によってすべての行が削除されます。しかし、その最初の行。
テストケース:
create table mytable (UserID VARCHAR(6), IPA varchar(3), Score INT);
create index mytable_IX ON mytable (UserID, Score, IPA);
insert into mytable values ('User 1','IP1',13)
,('User 1','IP1',20)
,('User 1','IP2',30)
,('User 1','IP3',10)
,('User 2','IP4',20)
,('User 2','IP5',22)
,('User 2','IP5',15)
,('User 3','IP6',12)
,('User 3','IP6',20)
,('User 4','IP6',15)
,('User 5','IP6',11);
別のフォローアップ
結果セットから 'User 4' と 'User 5' を削除するには (なぜそれをしたいのか、またはそれを行う必要があるのか はまったく明らかではありません。それらのユーザーがテーブルに 1 行しかないためである場合は、JOIN を追加することができます次のように、複数の行がある UserID 値のリストを取得するサブクエリ (インライン ビュー):
SELECT IF(@prev_user=t.UserID,@i:=@i+1,@i:=1) AS seq
, @prev_user := t.UserID AS UserID
, t.IPA
, t.Score
FROM mytable t
JOIN ( SELECT d.UserID
FROM mytable d
GROUP
BY d.UserID
HAVING COUNT(1) > 1
) m
ON m.UserID = t.UserID
CROSS
JOIN (SELECT @i := NULL, @prev_user := NULL) i
GROUP
BY t.UserID ASC
, t.Score ASC
, t.IPA ASC
HAVING seq = 1