皆さんMySQLは使ってますか?今回は、データベース機能の基本である抽出に焦点を当てて学んでいきます。具体的にはSELECT文の使い方ですね。
SELECTというとSQLの基本中の基本。ですが、条件の組み合わせ次第で実行速度が100倍以上も変わってしまうような、奥の深いクエリでもあります。奥の深い世界ではありますが、まずは一歩踏み出してみましょう!
データベースの準備
本記事で使うデータベースをあらかじめ準備しておきましょう。この記事では次のようなテーブルをつかいます。
データベース名:select_test_db
テーブル名:monthly_sales
+------+-------+-----------+ | id | sales | client_id | +------+-------+-----------+ | A103 | 125 | 1 | | A102 | 50 | 2 | | A101 | 64 | 4 | | A104 | 37 | 6 | | A102 | 285 | 3 | | A106 | 300 | 6 | | A103 | 24 | 1 | | A101 | 350 | 2 | | B107 | 14 | 1 | +------+-------+-----------+
とある会社のある月の売上データ、という体ですね。以前こちらの記事で学習された方は同じものが使い回せます。
以下のSQL文を実行することで必要なデータベースが作れます。
CREATE DATABASE select_test_db; USE select_test_db; CREATE TABLE monthly_sales(id VARCHAR(5),sales INT,client_id INT); INSERT INTO monthly_sales (id,sales,client_id) VALUES ('A103','125','1'), ('A102','50','2'), ('A101','64','4'), ('A104','37','6'), ('A102','285','3'), ('A106','300','6'), ('A103','24','1'), ('A101','350','2'), ('B107','14','1');
SELECTの基礎
まずは一番の基礎となるSELECTの構文です。
SELECTの基本構文
書式
実際にクエリを書いてみましょう。
SELECT id, client_id FROM monthly_sales;
このようなテーブルが得られましたか?
+------+-----------+ | id | client_id | +------+-----------+ | A103 | 1 | | A102 | 2 | | A101 | 4 | | A104 | 6 | | A102 | 3 | | A106 | 6 | | A103 | 1 | | A101 | 2 | | B107 | 1 | +------+-----------+
これは本来のテーブルから社員IDとクライアントIDだけを抜き出したテーブルになっていますね。このように欲しいデータを指定して、テーブルから必要な要素を抽出するのがSELECTの基本になります。
なお、指定の部分にアスタリスク(*)をつかうことで「すべて」の意味を表すことができます。例えば次のように使用します。
SELECT * FROM monthly_sales;
これはすべてのカラムをmonthly_salesから抽出してください、という意味になります。実行すると、このようにもとのmonthly_salesとまったく同じテーブルが出力されていますね。
+------+-------+-----------+ | id | sales | client_id | +------+-------+-----------+ | A103 | 125 | 1 | | A102 | 50 | 2 | | A101 | 64 | 4 | | A104 | 37 | 6 | | A102 | 285 | 3 | | A106 | 300 | 6 | | A103 | 24 | 1 | | A101 | 350 | 2 | | B107 | 14 | 1 | +------+-------+-----------+ 9 rows in set (0.00 sec)
なお、SELECTでカラムを指定する順番にルールはありません。なので、次のようにすればカラムを入れ替えた上に特定の列を重複させた表示、というものも可能です。
SELECT sales, client_id, id, sales FROM monthly_sales;
+-------+-----------+------+-------+ | sales | client_id | id | sales | +-------+-----------+------+-------+ | 125 | 1 | A103 | 125 | | 50 | 2 | A102 | 50 | | 64 | 4 | A101 | 64 | | 37 | 6 | A104 | 37 | | 285 | 3 | A102 | 285 | | 300 | 6 | A106 | 300 | | 24 | 1 | A103 | 24 | | 350 | 2 | A101 | 350 | | 14 | 1 | B107 | 14 | +-------+-----------+------+-------+ 9 rows in set (0.00 sec)
ややこしくなるのであまり出番はないでしょうが、こういった方法もある、というのは覚えておいてもいいでしょう。
カラムの四則演算
SQLではレコードに対して四則演算を行うことも可能です。
たとえばこの売上データ、表示されている数字の部分に(万円)が省略されているとしましょう。そうすると、正確な売上を算出するにはsalesカラムの値に10000をそれぞれかければ良いわけです。具体的なクエリは次のようになります。
SELECT id, sales * 10000 FROM monthly_sales;
実行結果は次のようになります。
+------+---------------+ | id | sales * 10000 | +------+---------------+ | A103 | 1250000 | | A102 | 500000 | | A101 | 640000 | | A104 | 370000 | | A102 | 2850000 | | A106 | 3000000 | | A103 | 240000 | | A101 | 3500000 | | B107 | 140000 | +------+---------------+ 9 rows in set (0.01 sec)
もちろん、掛け算以外にも足し算・引き算・割り算といった基本的な四則演算に対応しています。また、カラム同士の計算にも対応しており、例えば次のように売上の下一桁に顧客IDを接続する、なんてこともできたりします。
SELECT id, sales * 10000 + client_id FROM monthly_sales;
実行結果は下のとおりです。
+------+---------------------------+ | id | sales * 10000 + client_id | +------+---------------------------+ | A103 | 1250001 | | A102 | 500002 | | A101 | 640004 | | A104 | 370006 | | A102 | 2850003 | | A106 | 3000006 | | A103 | 240001 | | A101 | 3500002 | | B107 | 140001 | +------+---------------------------+ 9 rows in set (0.00 sec)
実際はもっと健全な使い方がありますが、今回は例の都合ということでご勘弁ください。
関数の利用
SELECT文は文中で関数を利用することができます。関数とはプログラミング用語で入力に対して特定の処理をした出力を返すもの、という意味です。
関数の入力に当たるものを引数(ひきすう)、出力を返り値・戻り値と呼びます。これだけだと初心者の方はさっぱりでしょう。
言葉の難しさに心を折られないよう、ちょっと踏ん張って欲しいポイントです。実際に具体例をみたほうがわかりやすいので、レコードから平均を計算するAVG関数を見てみましょう。
SELECT AVG(sales) FROM monthly_sales;
結果は次のようになります。
+------------+ | AVG(sales) | +------------+ | 138.7778 | +------------+ 1 row in set (0.00 sec)
これは何をやっているのかというと、salseカラムの各データから平均値を計算して、その結果を表示している、という処理になります。AVG()が関数、salesが引数、138.7778が戻り値となります。
こうやって実例を繰り返し使っていけば言葉の難しさもそのうち受け入れることができるようになります。
2年、3年と継続していくと、そのうち上で書いたような表現も当たり前に使いこなせるようになりますので、まずは継続して行くことを目標にがんばりましょう。
ちなみに関数はこの他にも合計値を求めるSUM()、円周率を求めるPI()、MySQLのサーバーバージョンを表示するVERSION()、現在使っているデータベースを表示するDATABASE()、文字列を結合するCONTACT()などなどものすごい量があります。
関数の解説だけでちょっとした参考書レベルの情報量になってしまうので、関数は必要になったら調べる、というスタンスでつきあっていくのが良いのではないでしょうか。
条件を絞る:WHERE・LIMIT句
つづいてSELECTの重要ポイントであるWHEREとLIMIT句についてみていきます。これらに共通するのは情報量を制限するということ。
今回のようにレコードが20を超えなければ人の目でも十分検証可能ですし、表示にもまったく時間がかかりません。ですが、実際に運用されているテーブルはレコードが数万、数十万、下手をすれば数千万から数億以上といったものも存在します。
このようなテーブルで全件表示を行ってしまっては、いつまでたっても表示が終わらないばかりか、リソースを無駄に消費しているとすらいえます。
なので、SELECTとWHERE、LIMITを上手に組み合わせることで、必要な情報のみを必要な量だけ抽出するすべを身に着けなければいけない、というわけなのです。
表示数を制限する:LIMIT
順番が逆になりますが、まずは挙動のわかりやすいLIMITから学びましょう。LIMITの書式は次のようになります。
書式
実際に試してみましょう。
SELECT id, sales FROM monthly_sales LIMIT 3;
実行結果はこのようになるはずです。
+------+-------+ | id | sales | +------+-------+ | A103 | 125 | | A102 | 50 | | A101 | 64 | +------+-------+ 3 rows in set (0.00 sec)
こちらが指定したとおり、レコード数が3つになっていますね。現実ではレコード数が事前に大きいことがわかっている場合やサイズがよくわからない場合があります。
こういった場合、いつもクエリにLIMIT 1000を付けておくことを心がけると、検索がいつまでたっても終わらない!!という悲劇を未然に防ぐことができます。実践ではよく使うテクニックなので、ぜひ覚えておいて下さい。
条件で絞り込む:WHERE
さて、本題のWHERE句です。WHEREは比較演算子をつかった条件を利用することで、条件に合致したレコードを抽出することができるようになる句です。演算子とは計算(演算)に使う記号のことです。
+、-といった算術演算子、and,orといった論理演算子などとともに、今回紹介する比較のための比較演算子があります。言葉は難しそうですが、要するに小学校でやった等号・不等号とその親戚です。以下にMySQLで利用できる比較演算子を紹介します。
No | プロパティ名 | 意味 |
---|---|---|
1 | Name | 名前として使用する文字列を指定 |
2 | RefersTo | A1、B3などのセルのアドレスで名前の参照先を指定 |
3 | RefersToR1C1 | R1C1 形式の表記法を使用して、名前の参照先を指定 |
4 | Visible | 名前を表示/非表示をTrue/Falseで指定。規定値はTrue |
5 | MacroType | マクロの種類を以下から指定。 1:Functionプロシージャ 2:Subプロシージャ 3:なし(定義した名前がFunction、Subを参照しない) |
表の上の方はまさに小学校以来おなじみの等号・不等号ですね。昔のコンピュータは≧と≦が扱えなかったため、<>と=の組み合わせで表現する習慣になっています。具体例で動作を確認してみましょう。
ここでは売上の125を基準にいろいろな操作を試していきます。まずは=。
SELECT id, sales FROM monthly_sales WHERE sales = 125;
+------+-------+ | id | sales | +------+-------+ | A103 | 125 | +------+-------+ 1 row in set (0.00 sec)
つづいて不等号から >=。
SELECT id, sales FROM monthly_sales WHERE sales >= 125;
+------+-------+ | id | sales | +------+-------+ | A103 | 125 | | A102 | 285 | | A106 | 300 | | A101 | 350 | +------+-------+ 4 rows in set (0.00 sec)
算数では出てこない<>は次のようになります。
SELECT id, sales FROM monthly_sales WHERE sales <> 125;
+------+-------+ | id | sales | +------+-------+ | A102 | 50 | | A101 | 64 | | A104 | 37 | | A102 | 285 | | A106 | 300 | | A103 | 24 | | A101 | 350 | | B107 | 14 | +------+-------+
ここまでは割と直観的に理解できるのではないでしょうか。ここからは文字を使った指定方法です。INはBの部分にリストを持ち、その中に該当するものを抽出します。
=が1つの値しか指定できないのに対して、複数の値に拡張したものがINということもできるでしょう。具体例は次のようになります。
SELECT id, sales FROM monthly_sales WHERE sales IN (125,285,300);
+------+-------+ | id | sales | +------+-------+ | A103 | 125 | | A102 | 285 | | A106 | 300 | +------+-------+ 3 rows in set (0.00 sec)
NOTは否定の意味を持ちます。NOTに続く部分をひっくり返す感じですね。上の例にNOTを適用すると、(125,285,300)「以外<」という意味になります。
SELECT id, sales FROM monthly_sales WHERE sales NOT IN (125,285,300);
+------+-------+ | id | sales | +------+-------+ | A102 | 50 | | A101 | 64 | | A104 | 37 | | A103 | 24 | | A101 | 350 | | B107 | 14 | +------+-------+ 6 rows in set (0.00 sec)
BETWEEN B AND CはBとCの間、という意味になります。
B,Cにそれぞれ値を指定してあげれば範囲を表すことができます。
SELECT id, sales FROM monthly_sales WHERE sales BETWEEN 50 AND 125;
今回の例では50以上125以下のレコードが抽出されました。
+------+-------+ | id | sales | +------+-------+ | A103 | 125 | | A102 | 50 | | A101 | 64 | +------+-------+ 3 rows in set (0.00 sec)
最後にBETWEENにNOTをつけることで範囲を逆転させることができます。
SELECT id, sales FROM monthly_sales WHERE sales NOT BETWEEN 50 AND 125;
今回の例では50未満と125より大きいレコードが抽出されたのが確認できますね。
+------+-------+ | id | sales | +------+-------+ | A104 | 37 | | A102 | 285 | | A106 | 300 | | A103 | 24 | | A101 | 350 | | B107 | 14 | +------+-------+ 6 rows in set (0.01 sec)
以上、比較演算子を使ったWHEREの絞り込みを紹介しました。
絞り込む条件を組み合わせる:論理式
最後にいままで学んできたことを組み合わせて、より複雑な絞り込みを行う手段を身に着けましょう。条件を組み合わせるには先ほども少し登場した論理演算子が活躍します。論理演算子とはMySQLにおいては条件を組み合わせるための演算子です。
たとえば売上が50以上、ただしIDがA101は除く、というような条件で抽出したい時、今までの知識だけではいまひとつ上手くできません。条件を組み合わせる方法が無いからですね。それを解決するのが論理演算子なのです。
MySQLで使える論理演算子は以下のとおりです。
No | 入力タイプ | 入力例 |
---|---|---|
1 | 値 + px | 10px 、 20px |
2 | &(パーセント) or 値 + em | 30%、0.3em |
3 | 値のみ | 1.5、2 |
それぞれ論理積(アンド)、論理和(オア)、排他的論理和(エックスオア)、否定(ノット)という名前がついています。MySQL以外の他のプログラミング言語でも毎度でてくるので、今覚えてしまうと後々役に立つかもしれません。
では、それぞれの働きを見ていきましょう。
条件「かつ」:AND
ANDは前後にある条件を日本語の「かつ」で結びつけます。例えば次のクエリ。
SELECT id, sales FROM monthly_sales WHERE sales >=10 AND sales <50;
+------+-------+ | id | sales | +------+-------+ | A104 | 37 | | A103 | 24 | | B107 | 14 | +------+-------+ 3 rows in set (0.01 sec)
これは売上が10以上かつ、50未満を指定して抽出したものになります。これぐらいならBETWEENを使っても実現できますが、例えばカラムをまたいだ条件指定や条件を複数つなげたい場合は論理演算子が必須になります。
次のORで実例を見ていきましょう。
条件「または」:OR
ORは前後にある条件を日本語の「または」で結びつけます。例をみてみましょう。
SELECT * FROM monthly_sales WHERE sales >=50 OR client_id <4;
実行結果は以下のとおりになります。
+------+-------+-----------+ | id | sales | client_id | +------+-------+-----------+ | A103 | 125 | 1 | | A102 | 50 | 2 | | A101 | 64 | 4 | | A102 | 285 | 3 | | A106 | 300 | 6 | | A103 | 24 | 1 | | A101 | 350 | 2 | | B107 | 14 | 1 | +------+-------+-----------+ 8 rows in set (0.00 sec)
一見全部のレコードが拾われたように見えますが、これは条件が売上50以上「または」取引先IDが4未満、というものだったからです。条件に合致していることを確かめてみてください。
全体のテーブルとくらべると売上37,取引先6のA104のデータだけが弾かれているのがわかるはずです。
その他の演算子:NOT,XOR
さて、先ほどMySQLには4つの論理演算子がある、といいました。そしてここまででAND,ORを紹介しました。残るは2つなのですが、じつは既にNOTについては紹介済みです。
比較演算子のNOT IN, NOT BETWEENで登場したあのNOTです。NOTの意味は「否定」。後ろに来る論理演算子の内容を逆転させます。
例えばNOT(sales >50 AND sales < 250)であれば「salesが50より大きく、かつ、250未満」以外のデータ。つまり、salesが50以下か250以上のデータが抽出されます。
言葉にするとややこしい感じですが、繰り返し使っていけばだんだんと体に馴染んでくるようなものなので、論理演算は好き嫌いせずに色々試してみると上達が早まります。
一方のXORは排他的論理和といい、なかなか特殊な動きをする論理演算子です。抽出条件の設定よりは論理演算で出番のある演算子です。初心者のうちはこんなものもあるんだ、程度の認識で十分でしょう。
条件式を組み合わせる
それでは最後にいままで学んできたことをぜんぶまとめて、複雑な条件式をつくる練習をしてみましょう。
例として使うのは先ほど触れた「売上が50以上、ただしIDがA101は除く」にくわえて「もしくは取引先ID2,4,6以外」という条件もプラスしてみましょう。それぞれの条件はクエリにすると以下のようになります。
IDがA101を除く:id <> ‘A101’
取引先ID2,4,6以外:client_id NOT IN (2,4,6)
なお、いままでずっと数字のみを扱っていたため紹介が遅れましたが、カラムや条件式に文字列を使う場合シングルクォーテーション(’)もしくはダブルクォーテーション(”)で囲みます。これらの条件を論理演算子で結ぶと次のようになります。
sales >= 50 AND id <> 'A101' OR client_id NOT IN (2,4,6)
ではこれをクエリにして実行してみましょう。
SELECT * FROM monthly_sales WHERE sales >= 50 AND id <> 'A101' OR client_id NOT IN (2,4,6);
実行結果は次のようになります。
+------+-------+-----------+ | id | sales | client_id | +------+-------+-----------+ | A103 | 125 | 1 | | A102 | 50 | 2 | | A102 | 285 | 3 | | A106 | 300 | 6 | | A103 | 24 | 1 | | B107 | 14 | 1 | +------+-------+-----------+ 6 rows in set (0.01 sec)
条件と実行結果をじっくりと見比べてみてください。なお、ANDとORが条件式に混在している場合、AND→ORの処理順になります。この場合ですと、「売上が50以上、ただしIDがA101は除く」もしくは「取引先ID2,4,6以外」という条件の結果なわけです。
条件式はなれるまで難しく感じるかもしれませんが、繰り返し読み書きしていくうちに自然と扱えるようになるものです。繰り返しと継続が肝になります。がんばりましょう。
まとめ
いかがでしたか?今回はSELECTについて基礎からWHEREを使った条件の絞り込みまでを紹介してきました。冒頭でも言いましたが、SELECTはWHEREなどの条件の組み合わせで劇的に速度が変わる可能性があります。
よりシンプルな条件で検索し、暗黙の型変換をなくす。言葉で書くとこれだけですが、これを実現できるのは地道な思考と実践を繰り返してきた人のみです。
地味ではありますが、上手にできれば確実に威力を発揮するスキルですので、少しずつでも自分の頭で考えて条件を組み立てられるようにしましょう。この記事が皆様のMySQL学習の一助となれば幸いです。