ど素人から毛を生やす。<延>

[MySQL]サブクエリの実行結果をCASEで比較したい話。(ユーザ定義変数)

Web > Other 2022年10月14日(最終更新:1月前)

どもです。
本日の要件は、PHPで書くなら、こう。

$tmp  = サブクエリを使った重い処理;
$tmp2 = 基準値;

if($tmp == $tmp2){
	echo 'A';
}else if($tmp > $tmp2){
	echo 'B';
}else if($tmp < $tmp2){
	echo 'C';
}

これを、MySQLで、かつプロシージャを使用せずにSELECTしたい。

冗長だったり重かったりな書き方はいくらでも思いつく、が、これをできるだけスマートに…できるのか……???

SELECT
CASE [サブクエリを使った重い処理]
WHEN 0 THEN 'A' 
WHEN 1 THEN 'B' 
ELSE 'C' END AS res

当然と言えば当然だが、ここまではできる。
また、WHENの数が増えても処理速度は大きく変わらなかった。つまり、WHENが増えても[サブクエリを使った重い処理]は一度しか実行されないと思われる。

SELECT
CASE WHEN [サブクエリを使った重い処理] = [基準値] THEN 'A'
     WHEN [サブクエリを使った重い処理] > [基準値] THEN 'B'
     ELSE 'C' AS res

これなら結果は適うが、コードが冗長なのは勿論のこと、WHENが増えるごとに明らかに実行時間が増加した。
[サブクエリを使った重い処理]はWHENの数だけ実行されてしまうのだろう。これは拙い。

ユーザー定義変数を用いれば解決できる

SELECT
@a := [サブクエリを使った重い処理] AS sub,
CASE
	WHEN @a = [基準値] THEN 'A'
	WHEN @a > [基準値] THEN 'B'
	ELSE 'C' END AS res

こうすれば、[サブクエリを使った重い処理]の実行結果を[@a]に保存し、同一セッション内の処理で使い回せるんですって!
MySQLにも変数ってあったんだぁ…(無知)

参照:MySQL 5.6 リファレンスマニュアル

果たして、サブクエリを使うのが正解なのだろうか?

問題は無事に解決できたのですが、残った疑問が。
そもそも、1つのSQLで解決しようとするのが正しいのか?という。

例えば、素直に[サブクエリを使った重い処理]と[基準値]をそれぞれSELECTして、実際に処理するソースの方で比較するという無難of無難な解決法があります。

あるいは、サブクエリなんて使わずに、[サブクエリを使った重い処理]を単体実行して結果を一時テーブルに落としてからSELECTするのも良いでしょう。

SQLの話ですが複雑なSQL中のサブクエリがボトルネック化したという話、そもそもMySQL5.5以前のサブクエリはとても重いという話(今どき5.5以前を使っている環境があるのか、はさて置き)などもあったりして、サブクエリを使う、という選択肢自体が安定しているとは言い難い。

一方、一時テーブルはそういった悩みからは解放されますが、例えばWHEREが複雑だった場合、SQL実行を2回に分けるのは如何なものか、という感覚がある。

いくらか調べてみましたが、この問題についてはハッキリと「どちらの方が良い」という結論は得られませんでした。
今回のケースだと、サブクエリのキーが重複する、同じ処理が2回走ってしまう可能性が高いため、一時テーブルの方がスマートに処理できると判断。

一周回ってそもそもサブクエリを使わないオチになってしまった。なんともはや。(´・ω・`)

この記事は役に立ちましたか?
  • _(:3」∠)_ 面白かった (0)
  • (・∀・) 参考になった (0)
  • (`・ω・´) 役に立った (0)