MySQLで2つのカラムから重複しない組み合わせを抽出する方法
はじめに
MySQLで2つのカラムから一意(重複しない)な組み合わせを取得したい場合、CASE式を活用するのが効果的です。例えば、(s, t) と (t, s) のようなペアは、順序が逆になっているだけなので同じ組み合わせとして扱いたいケースがあります。単純にSELECT DISTINCTを実行しても、このような順序違いのペアは別々の行として出力されてしまいます。本記事では、CASE式を使ってこの問題を解決する方法を、サンプルコード付きで段階的に解説します。
サンプルテーブルの作成
まず、2つの文字型カラムを持つテーブルを作成します。テーブル作成用のクエリは以下の通りです。
mysql> create table select_DistinctTwoColumns
-> (
-> Id int NOT NULL AUTO_INCREMENT,
-> FirstValue char(1),
-> SecondValue char(1),
-> PRIMARY KEY(Id)
-> );
Query OK, 0 rows affected (0.57 sec)テストデータの挿入
次に、INSERTコマンドを使ってテーブルにいくつかのレコードを挿入します。クエリは以下の通りです。
mysql> insert into select_DistinctTwoColumns(FirstValue,SecondValue) values('s','t');
Query OK, 1 row affected (0.12 sec)
mysql> insert into select_DistinctTwoColumns(FirstValue,SecondValue) values('t','u');
Query OK, 1 row affected (0.24 sec)
mysql> insert into select_DistinctTwoColumns(FirstValue,SecondValue) values('u','v');
Query OK, 1 row affected (0.12 sec)
mysql> insert into select_DistinctTwoColumns(FirstValue,SecondValue) values('u','t');
Query OK, 1 row affected (0.16 sec)登録データの確認
SELECT文を使って、テーブル内のすべてのレコードを表示してみましょう。
mysql> select *from select_DistinctTwoColumns;
実行結果は以下の通りです。
+----+------------+-------------+ | Id | FirstValue | SecondValue | +----+------------+-------------+ | 1 | s | t | | 2 | t | u | | 3 | u | v | | 4 | u | t | +----+------------+-------------+ 4 rows in set (0.00 sec)
ここで注目したいのは、Id=2の (t, u) とId=4の (u, t) です。この2つは値の並びが入れ替わっているだけで、実質的には同じ組み合わせです。しかし、単純なDISTINCTでは順序まで比較対象となるため、これらは重複として認識されません。
CASE式を使って一意な組み合わせを選択する
そこで、CASE式を使って各レコードの2つの値を常に「小さい方・大きい方」の順に揃えます。こうすることで順序が逆のペアも同じ形式に正規化され、DISTINCTによって重複を除外できるようになります。対象となるカラムは、1つ目が「FirstValue」、2つ目が「SecondValue」です。実際のクエリは以下の通りです。
mysql> SELECT distinct
-> CASE
-> WHEN FirstValue<SecondValue THEN FirstValue
-> ELSE SecondValue
-> END AS FirstColumn,
-> CASE
-> WHEN FirstValue > SecondValue THEN FirstValue
-> ELSE SecondValue
-> END AS SecondColumn
-> FROM select_DistinctTwoColumns;実行結果:
+-------------+--------------+ | FirstColumn | SecondColumn | +-------------+--------------+ | s | t | | t | u | | u | v | +-------------+--------------+ 3 rows in set (0.00 sec)
クエリの仕組み
このクエリでは、2つのCASE式がそれぞれ次のような役割を担っています。
- FirstColumn:FirstValueがSecondValueより小さい場合はFirstValueを、それ以外の場合はSecondValueを返します。つまり、2つの値のうち小さい方を出力します。
- SecondColumn:FirstValueがSecondValueより大きい場合はFirstValueを、それ以外の場合はSecondValueを返します。つまり、2つの値のうち大きい方を出力します。
この正規化処理により、(t, u) と (u, t) はどちらも (t, u) という同じ形で出力されるため、DISTINCTキーワードによって1行にまとめられます。その結果、元のテーブルには4件のレコードがありましたが、最終的な出力は3件の一意な組み合わせとなっています。
補足:GREATEST関数とLEAST関数を使う方法
MySQLには、複数の値の中から最大値・最小値をそれぞれ返す GREATEST() 関数と LEAST() 関数が用意されています。これらを使えば、上記のCASE式をより簡潔に書き換えることができます。
mysql> SELECT DISTINCT
-> LEAST(FirstValue, SecondValue) AS FirstColumn,
-> GREATEST(FirstValue, SecondValue) AS SecondColumn
-> FROM select_DistinctTwoColumns;こちらもCASE式とまったく同じ結果が得られるため、可読性を重視する場合はこちらの書き方がおすすめです。
まとめ
MySQLで2つのカラムから順序を考慮しない一意な組み合わせを取得するには、CASE式(またはLEAST/GREATEST関数)を使って値の大小関係に基づいて列を揃え、DISTINCTと組み合わせるのがシンプルで効果的な方法です。ペアデータの重複排除が必要な場面では、ぜひ活用してみてください。
-
MySQLで2列の合計値が最大となるレコードを取得する方法
MySQLで2列の合計値が最大となるレコードを取得する方法 2列の合計値の最大値を取得するには、集計関数MAX()とサブクエリを組み合わせて使用します。まずはサンプル用のテーブルを作成しましょう。 mysql> create table DemoTable1587 -> ( -> Value1 int, -> Value2 int -> ); Query OK, 0 rows affected (0.59 sec) 続いて、insertコマンドを使ってテーブルにいくつかのレコードを挿入します。 mysql> insert in
-
MySQLでテーブルの重複を除いたレコードから平均値を取得するクエリの書き方
MySQLで平均値を求めるには AVG() 関数を使用します。さらに DISTINCT と組み合わせることで、重複しているレコードを除外した状態で平均を計算することができます。この記事では、実際にサンプルテーブルを作成しながら、個別(ユニーク)なレコードから平均値を取得する方法を解説します。サンプルテーブルの作成まず、以下のクエリでテーブルを作成します。mysql> create table DemoTable1934 ( StudentName varchar(20), StudentMarks int ); Query OK, 0 rows affec