「何このSQL、意味がわからない…」
マニュアルを見ればすぐわかるものではなく、何のためにこんなコードを書いたのか、意図がわからないSQLを集めました。
「先輩、このSQLどういう意味ですか?」と、会社の後輩に聞かれて、あなたは答えられるでしょうか?
※以下、MySQL用のSQLをサンプルコードとして紹介しています。データベースは、MySQLのサンプルデータベースEmployees、SQL実行結果の表示にはphpMyAdminを使用しています。
目次
count(1)の意味は、count(*)と同じ
select count(1) from employees;
count(*)ならわかるけど、count(1)ってどういうことなんでしょう?
実は、count(1)の実行結果は、count(*)と同じ。
その昔、count(*)の代わりにcount(1)を使うと、処理が少し速くなるという時代があっとようです。
今は、最適化エンジンが進化して特に実行速度は変わらなくなりました。
count(1)の意味は、
select 1 from テーブル名で抽出できるデータの件数になります。
select 1 from テーブル名 を実行すると、決め打ちで「1」が抽出されます。 なお、count(0)の実行結果も、全く同じになります。
なお、count(カラム名)とすると、指定したカラムがNULL以外の値のものをカウントします。
where 1=1の意味は、「常に真」 where句が可変のとき役立つ
一見意味のない、where 1=1(常に真)という条件ですが、プログラムと連携するときに少し役立ちます。(where 1 でも同様) 例えば、データ検索用の条件入力用画面からSQLを組み立てる場合。
通常なら、条件がない場合はwhere句なし、一番最初の条件には「and」を入れない、という微妙に面倒な処理を書かなければなりません。
select * from 書籍テーブル where タイトル=xxx and 分類=xxx and 国名コード=xxx
where 1=1を決め打ちで入れておくと、検索条件が入力されたフィールドを「and 項目=条件」でつないでいくことでSQLが完成します。
select * from 書籍テーブル where 1=1 and タイトル=xxx and 分類=xxx and 国名コード=xxx
プログラマーのちょっとした工夫なのですが、「エッ、なんだこれ」というコードを書いてしまうのは、メンテナンス等の面では問題あるかも知れません。
SQLでのコロンの意味は2種類ある
「SQLのコロンの意味ってなんですか?」
と聞かれたとしたら、2つのケースがあります。
MySQLで代入を表す明示的な書き方の場合と、Oracleでのバインド変数を表す場合です。
MySQLで代入を表す「:=」
MySQLでは、コロン・イコール(「:=」)と、イコール(「=」)は、ほぼ同じ意味です。
MySQLでのイコール(「=」)は、値の評価(比較)と、値の代入という2つの動きをします。ただし、set文以外での=は「値の評価」という動きになります。
そこで、select文などで、ユーザ定義変数に値の代入をする場合は、=ではなく、:=を使います。
SET @t1=1, @t2=2, @t3:=4; SELECT @t1, @t2, @t3, @t4 := @t1+@t2+@t3;
= は SET 以外のステートメントでは比較演算子 = として扱われるので、割り当て演算子にはこちらではなく、:= を使用する必要があります。
MySQL :: MySQL 5.6 リファレンスマニュアル :: 9.4 ユーザー定義変数より
Oracleでバインド変数を表す「:変数名」
SQL内で:変数名と表記した部分に、C言語やPHPなどから渡される値が入ります。「:変数名」の部分をバインド変数と言います。
BEGIN select * from usertable where name=:val; END;
SQLの構造自体は変えられないという制限があるため、バインド変数を使うことで、SQLインジェクション対策になります。
SQLインジェクションは、検索画面に入力した文字列をそのままSQLとして発行した場合、予期せずdelete文などのデータベースを破壊するSQLを発行してしまうこと。
例えば、検索画面にて「0;delete from usertable;」という値を入れた場合、入力値をそのままSQLのwhere句として発行する仕組みだと、内部でdelete文が発行されてしまう脆弱性が出来てしまうんですね。
また、実行計画(最適化)を使いまわせるので、わずかながらSQLのレスポンスがあがるのもメリット。大量のSQLを発行する問い合わせ画面などに向いていると言えるでしょう。
ただし、バッチ処理など1つのSQL文で大量のデータ処理をするケースで使うと、処理の最適化が出来ないため、逆に大きくパフォーマンスが落ちるケースもあるため、注意が必要です。
バインド変数は、データベースによって表記方法が違います。はてなマーク「?」で表記するデータベースもあります。
DELIMITER //の意味は、MySQLの仕様回避
DELIMITER // CREATE FUNCTION helloworld() RETURNS VARCHAR(20) BEGIN return 'Hello world'; END // DELIMITER ;
上記は、MySQLのストアドプロシジャ(またはファンクション)を定義する場合の書き方です。
しかし、初見では「DELIMITER //」で、「エッ?」と思うこと必至。
DELIMITERは、区切り文字を変更するのですが、なぜ区切り文字を変更する必要があるのか直感ではわからないんですよね。
答えは、MySQLはセミコロン「;」が出現すると、定義文の途中であろうとSQLを実行してしまうという仕様のため。
DELIMITERの行を抜いて実行すると、「return ‘Hello world’;」のところでSQLを発行してしまい、「ENDがない」ため、Syntax Errorになります。
SQLのカッコの意味は、サブクエリを表す
SQL初見の人が、カッコの部分を「どういう意味だろう?」と疑問に思うのは、サブクエリ(副問い合わせ)のことを指しているケースが多いと思います。
カッコはサブクエリを表します。select文の実行結果を、別のselect文の条件に使うことです。
SELECT first_name, last_name, birth_date FROM employees a WHERE birth_date = ( select min(birth_date) from employees b )
あ上記は、employeesテーブルを自己連結して、誕生日が最も古い社員を抽出しています。
実行結果は以下のとおりです。
employeesテーブルに、「a」と「b」という別名をつけて、サブクエリとしています。
サブクエリが複雑化すると、可読性が落ち、実行速度も遅くなる傾向があるため、使いどころには注意ですが、ぜひともマスターしたいテクニックですね。
outer joinとinner joinの意味は、ベン図で直感で理解できる
プログラマーとして、outer joinとinner joinは体で覚えていても、会社の後輩に「何が違うんですか?」と聞かれたとき、説明が難しいと思います。
同様に、right joinとleft joinも説明しずらいもの。
実は、ベン図を書いて説明すると比較的伝わりやすいんですよね。
こちらの記事を参考になさってください。