SQLで作ったリストをWebページで活用したり、他のシステムで利用するのに便利な機能が、リストの重複をまとめるDISTINCTであり、もちろんMySQLでも利用できます。今回は、MySQLでSELECT文を作るうえで、ぜひマスターしたいDISTINCTの使い方についてご紹介します。
DISTINCT句の機能は重複をまとめる
SQLで重複行をまとめるコマンドと言ったらDISTINCT句です。そして、MySQLでももちろんDISTINCT句が使えます。まずは、DISTINCT句の基本について、解説します。
DISTINCT句の基本
先ほど紹介したように、MySQLでDISTINCT句を利用すると処理に時間がかかります。また、DISTINCT句で抽出したリストを数えたり、加工したりするとさらに時間がかかるので、別の方法を使った方が良いケースもあります。
DISTINCT句は単に重複行をまとめる機能しかないので、使いやすいのが特徴ですが、他のコマンドを使っても同じ結果が得られるケースがたくさんあります。例えば、GROUP BY を使えば、DISTINCT句と同じように重複がまとまります。ぜひ、そういった使い方にも関心を持ちましょう。
DISTINCTの使用例
先ほど解説したように、DISTINCT句は、SELECT文に追加するだけで重複がまとまるシンプルな機能が特徴です。しかし、使い方を工夫すれば、複雑な抽出にも応用可能です。次から、そういったDISTINCT句の使い方のヒントをご紹介します。
一つの要素の重複をまとめる例
DISTINCT句で重複をまとめてユニークな要素名のリストとして使うケースはいろいろあります。例えば、Webページのプルダウンメニューを作ったり、そのリストの要素を検索条件にして別の抽出をしたりと、いろいろな応用が可能です。もちろん、Webシステムを作るプログラムでも作れますが、MySQLで実行するSQLなら短い記述で実現できます。
例えば、次のような簡単なテーブルがあるとします。 DISTINCT句で処理するテーブルの例 id user host --------------------- 1 mysql localhost 2 apache localhost 3 mysql % 4 mysql localhost
上記のテーブルのuser列から重複のないリストを作るとすれば、次のようなSQLを使います。
DISTINCT句を使った例 SELECT DISTINCT user from users where host = 'localhost';
上記のSQLの出力は、次のとおりです。
user ------ mysql apache
複数の要素の重複をまとめる例
DISTINCT句は、対象となる要素が複数ある場合でも使えます。ただし、その場合はSELECT文で抽出されたリストの全てレコードに対してスキャンを行い、指定された複数要素の重複のあるレコードを調べてまとめます。
例えば、次のようなケースでは、userとhostの組み合わせで重複している行のみ除かれます。
DISTINCT句で処理するテーブルの例 id user host --------------------- 1 mysql localhost ←このレコードが重複 2 apache localhost 3 mysql % 4 mysql localhost ←このレコードが重複
DITINCT句を使って、userとhostの2つの要素の重複をまとめるSQL文
SELECT DISTINCT user, host FROM table WHERE host = 'localhost';
上記のDISTINCT句を使ったSQLの実行結果 user host --------------------- mysql localhost ←重複がまとめられ1つに apache localhost
DISTINCT句の応用例
次から、DISTINCT句を使って重複をまとめたSQLの応用例をご紹介します。
ユニークな要素名の数を数える場合
Webシステムを作るのにフレームワークを利用していると、MySQLから抽出したリストが配列に格納されるので、その個数は簡単に調べられます。そのため、MySQL側でSQLを使って数を数えさせる機会は無いかもしれません。とはいえ、DISTINCTを使ったSQLを利用すれば、重複のない要素を数を求めるえることが可能です。
なお、要素の数を数えるには、SQLのCOUNT関数を使います。そして、DISTINCT句はこういった関数の中にも使えるので、DISTINCT句で重複をまとめたリストの数を数えさせることが可能です。
要素の数を数えるSQLの例 SELECT COUNT( DISTINCT user ) FROM table WHERE host = 'localhost';
ただし、要素が複数ある場合は、上記のようには書けません。そのため、FROMにサブクエリーを指定し、COUNT関数でそのレコードを数えるか、CONCAT関数で複数の要素から1つの文字列を作り、それを数えるといった方法で要素の数を数えることもできます。
サブクエリーを用いる例 SELECT COUNT(*) FROM ( SELECT DISTINCT user,host FROM table WHERE host = 'localhost') AS tmp ;
CANCAT関数で1つの文字にして数える例 SELECT COUNT( DISTINCT CANCAT( user, host )) FROM table WHERE host = 'localhost';
重複をまとめ、さらにソートして出力する
DISTINCT句はSELECT文で抽出したリストに対して、重複のまとめを追加で行う機能ですが、まとめる際に独自のソートを実行します。そのため、サブクエリを使って抽出しとソートを行ったリストに対して、さらにDISTINCT句を適用すると、順番がおかしくなってしまいます。
サブクエリを使い、ソートが崩れる例 SELECT DISTINCT T.列1, T.列2 FROM ( SELECT 表1.列1,表1.列2 FROM 表1, 表2 WHERE 表1.列1=表2.列1 ORDER BY 表1.列2 ) T;
なお、ORDER BYは、DISTICT句で重複をまとめたリストに対して最後に適用されるので、サブクエリではなく、最も外側にORDER BYを使えば、重複のない、さらにソートされたリストを作れます。
ソートをサブクエリの外に出した例 SELECT DISTINCT T.列1, T.列2 FROM ( SELECT 表1.列1,表1.列2 FROM 表1, 表2 WHERE 表1.列1=表2.列1 ) T ORDER BY T.列2
なお実際のSQLはもっと複雑ですが、SQLで扱う要素をどう処理していくかを理解していれば、どうすれば期待どおりにソートできるかが解ります。
まとめ
SQLのSELECT結果のリストに対して重複をまとめるDISTINCT句は、いろいろなケースで使えます。しかし、SEELCT文に書かれたSQLで、どのようにデータベースから要素が抽出されるかを理解していないと、希望するリストを作れなかったり、無駄に時間がかかる処理を繰り返すことになります。ぜひ、DISTINCT句の特徴を理解し、MySQLを賢く利用しましょう。