はじめに
未経験でエンジニアになった方は、おそらく最初の技術研修で軽くSQLも触るのではないでしょうか。
自分も漏れなくそのうちの一人でした。
研修でCRUD操作を一通り習得し、
「これでSQLは完璧だ!」と、いざ現場に出てみると、
こんなSQL文が目に飛び込んできました。
SELECT
A.id,
A.name,
CASE
WHEN EXISTS (
SELECT 1
FROM B
WHERE B.id = A.id
) THEN '1'
ELSE '0'
END AS match_flag
FROM
A;
"""SELECT 1""" ってなんだ!?!?
なんとなく使っていた"SELECT"
ここで自分が躓いたのは、
「SELECT文って、テーブルのカラム名を指定して取ってくるやつでしょ!」
というざっくりとした理解をしていたためでした。
このざっくりとした理解から少し深堀りしていくと、SELECT 1の存在意義が段々分かってきます。
SELECT文の基本と言えば、以下のような使い方です。
SELECT
A.id,
A.name
FROM
A;
#結果の例
+---------+-------+
| id | name |
+---------+--------
| 1 | Bob |
+---------+-------+
この処理をもう少し細かく理解してみましょう。
実はこのとき、内部的には以下の処理が行われています(あまり厳密ではないですが)。
①FROM句で指定されたテーブルA全体がスキャンされる
②スキャンされたデータのうち、SELECT文で指定されたもののみを出力する
SELECT 1 の出力結果は?
「じゃあ、SELECT 1」の結果ってどうなるの?という疑問が出てくるかと思います。
結果は、常に1が返ってきます。
具体的には以下の処理が行われるためです。
①FROM句で指定されたテーブルA全体がスキャンされる
②スキャンされたデータのうち、SELECT文で指定されたもの(=1)のみを出力する
→出力値は常に1
「毎回1が出力されるなら意味ないじゃん!!」と思いますよね。
僕も思いました。
ですが、SELECT文を実行することに自体に意味があることケースがあるのです。
その代表例がEXISTS句です。
EXISTS句でSELECT 1を使う理由
ハマりがちなポイント
EXISTS句とは、SELECT文の実行結果について、
「1行でも結果があればTRUEを、0行ならFALSEを返却する」関数です。
ここで、冒頭のSQLのEXISTS句の部分を見てみましょう。
EXISTS (
SELECT 1
FROM B
WHERE B.id = A.id
)
これを最初みたとき、僕は思いました。
「"1" の行数が1行か0行かの判定って、処理として成立しなくない???」
と。
ここが"SELECT 1"を理解するときに陥りがち(だと思われる)ポイントです。
"出力結果"と"実行結果"の違い
以下の単純な事実を理解した瞬間、僕の中のEXISTS句の謎は解けました。
「SELECT文の出力結果(最終的な処理結果)と実行結果(内部的な処理結果)は別物である」
僕は"出力結果"と"実行結果”を混同して考えていたので"SELECT 1 "が理解できなかったのでした。
<誤った考え>
「"1"(SELECT文の出力結果)の行数が1行か0行かの判定って、処理として成立しなくない???」
<正しい考え>
EXISTS句が評価するのは出力結果ではなく実行結果なので、出力結果である"1"に対して評価をするわけではない。
このことを、先ほどのSELECT文の処理の流れで説明すると、以下のようになります。
①FROM句で指定されたテーブルA全体がスキャンされる(実行結果)
②実行結果に対して、EXISTS句の評価が行われる
②スキャンされたデータのうち、SELECT文で指定されたもののみを出力する(出力結果)
※ SELECT 1 の場合、常に出力結果は1になる。
別にSELECT 1を使わなくてもいい
以下のように、出力結果を1にせず、テーブルBの全てのカラムを出力対象としても、結果としては問題ありません。
EXISTS (
SELECT *
FROM B
WHERE B.id = A.id
)
では、なぜSELECT 1 を使うのでしょうか?
個人的には以下の理由があると認識しています。
・意図を明確にするため
→このクエリの実行結果だけが大事で、出力結果は関係ないよ~ということが分かりやすくなる
・処理効率を少しでも高めるため
→クエリの実行結果に多数のカラムがある場合、全てのカラムを出力すると少し処理効率が落ちてしまう
余談ですが、別にSELECT 0でもSELECT 10000でも動作に影響はないです。
ただ慣習的に SELECT 1 を使う人が多いので、その方が意図も伝わりやすいだろう、ということのようです。
おわりに
玄人エンジニアの諸兄姉からすると、「こんな当たり前のことも分からないのか」と言われてしまいそうな内容になってしまいました。
すみません、こんな当たり前のことも分からなかったんです...(;o;)。
ITエンジニアという仕事は、
「見えない部分(=プログラムの内部処理的なところ)を想像して、見えている部分(=出力結果)と切り離して考える」
という思考がときどき求められる気がするのですが、これがどうも新鮮に感じられます。
自分が文系出身だからなんでしょうか?
こういう違和感のようなものは慣れてしまうと感じなくなってしまうので、
初心者がどういうところで躓くのか、
どんな思考が抜けているのか、
だんだん分からなくなってしまうような気がしています。
こういう初心者のうちの小さな違和感については、きちんと書き留めて見返せるようにしておきたいです。