5

重要な2列のテーブルがある場合、

CREATE TABLE foo (id INT, a INT, b INT, KEY a, KEY b);

a両方を持ち、両方の行で同じであるすべての行を見つけるにはどうすればよいbですか? たとえば、このデータセットでは

id | a | b
----------
1  | 1 | 2
2  | 5 | 42
3  | 1 | 42
4  | 1 | 2 
5  | 1 | 2
6  | 1 | 42

id=2で一意であるため、 を除くすべての行を取得したい(a,b)。基本的に、私はすべての問題のある行を見つけて、

ALTER TABLE foo ADD UNIQUE (a, b);

私のテーブルには10M行があるので、n^2 forループよりも優れたものがいいでしょう。

ボーナス ポイント: 1 行を除くすべての行を削除するにはどうすればよいですか (1 行が残っている限り、どの行でもかまいません)。

4

8 に答える 8

1

最終的に何をする必要があるかを明確にしていただけますか?最善の解決策は、それによって異なる場合があります (たとえば、単にすべての重複キー行を削除しますか?)。

1 つの方法は、このテーブルを処理することです (mySQL がサポートしているかどうかは不明です。これは SYBASE からのものです)。

SELECT MIN(id), A, B FROM FOO GROUP BY A, B HAVING COUNT(*)>1

あなたの正確な質問 (ただし、id=2 以外のすべての行が必要な理由については少し迷っています) は次のとおりです。

SELECT F1.*  
FROM FOO F1 , 
     (SELECT A, B FROM FOO GROUP BY A, B HAVING COUNT(*)>1) F2
WHERE F1.A=F2.A and F1.B=F2.B

すべての重複を削除するには、たとえば次のようにします

DELETE FOO WHERE NOT EXISTS
(SELECT 1 from
    (SELECT MIN(id) 'min_id' FROM FOO GROUP BY A, B HAVING COUNT(*)>1) UINIQUE_IDS 
 WHERE id = min_id)

別の方法として、次のことができます

  SELECT MIN(id) 'id', A, B INTO TEMPDB..NEW_TABLE 
  FROM FOO GROUP BY A, B HAVING COUNT(*)>1

  TRUNCATE TABLE FOO
  // Drop indices on FOO
  INSERT FOO SELECT * FROM NEW_TABLE
  // Recreate indices on FOO
于 2009-09-17T05:13:44.300 に答える
1
select * from foo where a = b

または、何か不足していますか?

===

明確にするために更新します。

select * from 
foo as a
inner join foo as b
on a.a = b.a AND b.a = b.b
and a.id != b.id

++++++++++ 3回目の明確化編集後:

select f1.id
FROM foo as f1
INNER JOIN foo as f2
ON f1.a = f2.a AND f1.b=f2.b AND f1.id != f2.id

しかし、私は撃たれたので、自分で確認してください。

于 2009-09-17T04:55:55.443 に答える
1

これはうまくいくべきではありませんか?

SELECT * FROM foo WHERE a = b

=== 編集 ===

どうですか

SELECT a, b FROM foo GROUP BY a, b HAVING COUNT(*) > 1

=== この質問をあきらめる前に最後の再編集 ===

SELECT foo.* FROM foo, (
   SELECT a, b FROM foo GROUP BY a, b HAVING COUNT(*) > 1
) foo2
WHERE foo.a = foo2.a AND foo.b = foo2.b
于 2009-09-17T04:56:57.867 に答える
1
SELECT * 
FROM foo first
JOIN foo second
  ON ( first.a = second.a
       AND first.b = second.b ) 
  AND (first.id <> second.id )

複数の行が a と b の同じ組み合わせを持つすべての行を考え出す必要があります。

列 a と b にインデックスがあることを願っています。

于 2009-09-17T05:02:35.347 に答える
1

これを試して:

    With s as (Select a,b from foo group by a,b having Count(1)>1)
Select foo.* from foo,s where foo.a=s.a and foo.b=s.b

このクエリは、テーブル foo に重複する行を表示する必要があります。

于 2009-09-17T05:29:05.283 に答える
0

ここに別のアプローチがあります

select * from foo f1 where exists(
  select * from foo f2 where
    f1.id != f2.id および
    f1.a = f2.a および
    f1.b = f2.b )

とにかく、もう少し読みやすいと思いますが、そのような巨大なテーブルがある場合は、実行計画を確認する必要があります。サブクエリはパフォーマンスに関する評判が悪いです...

また、クエリを高速化するためにインデックスを作成することも検討する必要があります(明らかにunique句なしで)...巨大な操作の場合、インデックスの作成に時間を費やし、更新を実行してからインデックスを削除する方が良い場合があります...この場合、(a, b) のインデックスは確かに大いに役立つはずです...

于 2009-09-17T05:15:57.573 に答える
0

あなたが述べた目標は、の重複した組み合わせをすべて削除することです(a,b)。そのために、複数テーブルの DELETE を使用できます。

DELETE t1
  FROM foo t1
  JOIN foo t2 USING (a, b)
 WHERE t2.id > t1.id

実行する前に、次の方法でどの行が削除されるかを確認できます。

SELECT DISTINCT t1.id
  FROM foo t1
  JOIN foo t2 USING (a, b)
 WHERE t2.id > t1.id

WHERE 句をt2.id > t1.id使用すると、 の値が最も高いものを除くすべてが削除されidます。あなたの場合、2、5、idまたは6に等しい行のみが残ります。

于 2009-09-17T12:40:14.320 に答える
0

最終製品で id 値がまったく問題にならない場合、つまり、それらすべてに番号を付け直すことができれば問題ありません。また、id がシリアル列である場合は、2 つの列を「個別に選択」して古いテーブルからすべてのデータを削除してから、一時的な値をコピーして戻します。

于 2009-09-17T12:47:07.117 に答える