SQL:テーブル内の列の組み合わせで重複データのある行を見つける

仕事上で必要なロジックがあったので、考えてみました。

インターネットで検索すると「重複行のデータを抽出する」と書いてあっても、どの行とどの行が重複しているのかを取り出せるようなものが見つかりませんでした。

どういった時に必要になるかというと、例えば「ある人の血液型とその母親の血液型の組み合わせで、他の人と重複しているのはどれだけいるのだろう?」といった場合に、重複している人たちのみを抜き出したい場合に利用できます。

もちろん、本人の血液型だけを比較して重複を抜き出すようなことにも使えます。

血液型テーブルを参考に抽出してみる

例えば以下のようなデータを持つテーブルがあるとしましょう。

bloodテーブル

名前 本人の血液型 母親の血液型
山下 O A
田中 O A
佐々木 AB B
高橋 B B
鈴木 A AB
黒木 AB B

今回はこのテーブルのハイライトされている行を抽出するということを行います。 条件を論理的に列挙すると以下のとおりです。

  • 1つの行を全ての行と比較して重複をチェックする。
  • 全ての行をチェックする際に同一行は省く。
  • 重複条件:本人の血液型と母親の血液型の組み合わせが重複している行。

INNER JOIN で全行比較しながら重複をWHERE で絞り込み

こういった重複チェックは同一テーブルを2つ比べることになり、また1つの行を全行と比較することになるので、別名テーブルINNER JOINを使います。

今回は比較テーブルが同一なので「LEFT JOIN」でも構いませんが、比較対象が別テーブルかつ、データの内容が異なる場合は「LEFT JOIN」を利用しましょう。

SELECT tbl1.* FROM `blood` tbl1
INNER JOIN `blood` tbl2 ON (
tbl1.名前 = tbl2.名前
) WHERE
tbl1.本人の血液型 <=> tbl2.本人の血液型 AND
tbl1.母親の血液型 <=> tbl2.母親の血液型;

1つ見慣れない演算子(<=>)がありますが、これは「安全等価演算子」といって、フィールドにNULLが含まれる場合(今回でいうと「血液型が分からない場合はNULLを設定する場合)でも正しく比較を行いたい時に使います。

結果はこのようになります。

名前 本人の血液型 母親の血液型
山下 O A
田中 O A
佐々木 AB B
黒木 AB B

これで重複が存在するすべての行を取り出すことができます。 さらに絞り込みたい場合はWHERE句の後に条件を追加しましょう。

例えば重複のチェックを山下さんと田中さんに絞ってチェックする場合は以下のようにします。

SELECT tbl1.* FROM `blood` tbl1
INNER JOIN `blood` tbl2 ON (
tbl1.名前 = tbl2.名前 AND
    tbl2.名前 IN ('山下','田中') AND 
) WHERE
tbl1.名前 IN ('山下','田中') AND 
tbl1.本人の血液型 <=> tbl2.本人の血液型 AND
tbl1.母親の血液型 <=> tbl2.母親の血液型;

当然ですが、欠点もある

このSQL文の欠点としては、やはりINNER JOIN を使っていて全行検索を行なってしまうというのがあります。
ですから、n行のデータがあればn×nの照合を行なってしまうため、行数が増えれば増えるほど、負荷がかかってきます。

お役に立ちましたでしょうか?

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

2013-01-16