MySQL
 Computer >> コンピューター >  >> プログラミング >> MySQL

MySQLでMINUSクエリをシミュレートする方法【LEFT JOINを使った差分抽出】

MySQLでは、OracleなどのRDBMSで利用できる集合演算子MINUS(差集合)をサポートしていません。しかし、JOIN(特にLEFT JOIN)を工夫して使うことで、MINUSクエリと同等の結果を簡単にシミュレートできます。

この記事では、実際のテーブルデータを使いながら、その具体的な手順をわかりやすく解説します。

例:2つのテーブルの差分を抽出する

ここでは、Student_detailStudent_info という2つのテーブルを例にします。それぞれ以下のようなデータが格納されています。

mysql> Select * from Student_detail;
+-----------+---------+------------+------------+
| studentid | Name    | Address    | Subject    |
+-----------+---------+------------+------------+
|       101 | YashPal | Amritsar   | History    |
|       105 | Gaurav  | Chandigarh | Literature |
|       130 | Ram     | Jhansi     | Computers  |
|       132 | Shyam   | Chandigarh | Economics  |
|       133 | Mohan   | Delhi      | Computers  |
|       150 | Rajesh  | Jaipur     | Yoga       |
|       160 | Pradeep | Kochi      | Hindi      |
+-----------+---------+------------+------------+
7 rows in set (0.00 sec)

mysql> Select * from Student_info;
+-----------+-----------+------------+-------------+
| studentid | Name      | Address    | Subject     |
+-----------+-----------+------------+-------------+
|       101 | YashPal   | Amritsar   | History     |
|       105 | Gaurav    | Chandigarh | Literature  |
|       130 | Ram       | Jhansi     | Computers   |
|       132 | Shyam     | Chandigarh | Economics   |
|       133 | Mohan     | Delhi      | Computers   |
|       165 | Abhimanyu | Calcutta   | Electronics |
+-----------+-----------+------------+-------------+
6 rows in set (0.00 sec)

student_info にのみ存在するレコードを取得する

まず、「student_info テーブルには存在するが、Student_detail テーブルには存在しない studentid」を抽出してみましょう。次のように LEFT JOIN を使います。

mysql> SELECT studentid from student_info LEFT JOIN Student_detail USING(studentid) WHERE student_detail.studentid IS NULL;
+-----------+
| studentid |
+-----------+
|       165 |
+-----------+
1 row in set (0.07 sec)

実行結果を見ると、studentid「165」だけが抽出されました。つまり、Abhimanyu のレコードが student_info にのみ存在していることが確認できます。

逆に、Student_detail にのみ存在するレコードを取得する

今度は逆パターンです。「Student_detail テーブルには存在するが、student_info テーブルには存在しない studentid」を取得するには、JOINする順序を入れ替えるだけです。

mysql> SELECT studentid from student_detail LEFT JOIN Student_info USING(studentid) WHERE student_info.studentid IS NULL;
+-----------+
| studentid |
+-----------+
|       150 |
|       160 |
+-----------+
2 rows in set (0.00 sec)

この場合は、studentid「150」と「160」が返されました。これらのレコードは Student_detail にしか登録されていないことがわかります。

仕組みのポイント

この手法の鍵となるのは、次の2点です。

  • LEFT JOIN を使うことで、左側テーブルの全行を保持したまま右側テーブルと結合できる
  • 結合相手が存在しない行は、右側テーブルのカラムが NULL になるため、WHERE ~ IS NULL で差分だけを絞り込める

この「LEFT JOIN + NULL判定」の組み合わせは、MINUSだけでなくNOT INサブクエリよりもパフォーマンスが良いケースも多く、実務でも広く使われる定番テクニックです。

補足:MySQL 8.0.31 以降では EXCEPT が使える

なお、MySQL 8.0.31 以降では標準SQLの EXCEPT 演算子がサポートされています。新しいバージョンのMySQLをお使いの場合は、SELECT ... EXCEPT SELECT ... の形式でMINUSと同じ差集合演算を直接記述できます。それ以前のバージョンでは、本記事で紹介したLEFT JOIN方式が最も有効な代替手段となります。

  1. MySQLで日付ごとの合計値を集計する方法【GROUP BY活用術】

    MySQLでは、datetime型の日付データを日ごとにグループ化し、数値の合計を求めることができます。本記事では、サンプルテーブルを作成し、DATE()関数とGROUP BY句、SUM()関数を組み合わせて日付ごとの合計を集計する手順を解説します。1. サンプルテーブルの作成まず、datetime型のカラムと、日数(カウント)を格納するint型のカラムを持つテーブルを作成します。mysql> create table DemoTable ( ShippingDate datetime, CountOfDate int ); Query OK, 0 rows affect

  2. MySQLでSELECTクエリの結果を並べ替える方法|ORDER BY句の基本と実践例

    データベース操作では、テーブルから特定のデータや行を抽出することが日常的によくあります。通常、SELECT文で取得した行はテーブル内に格納されている順序で返されますが、場合によっては、特定の列を基準にして昇順または降順で並べ替えた結果を取得したいこともあるでしょう。そんなときに活躍するのが「ORDER BY」句です。以下で具体的な使い方を見ていきましょう。例えば、「name」フィールドを含む複数のカラムを持つテーブルがあるとします。テーブルからすべての行を取得したいけれど、名前のアルファベット順に並べ替えた状態で結果を受け取りたい——こうしたケースでは、ORDER BY句を使って「name」フ