プログラミング

MYSQLのIF文を書こうとしたらドハマりした




IF文書き始めたら夢中になっちゃった★
という話ではございません。

先日、直接DBを書き換える作業がありまして。
削除前後で行数確認して問題なければコミットにしてほしいというオーダーだったので、軽い気持ちでIF文に手を出したら大火傷。。。
syntax error祭り開催。。。

結果的には私がSQLファイルを流して自動で判断させなきゃいけないと思い込んでいただけで、手順とクエリを用意して目視で確認でよかったので事なきを得たのですが。

できないままだとアレなので、何とか動くものを書いてみました。

そもそも

SQLのIF文なんて存在すらググって知ったわ。。。
普段もSQLをゴリゴリ書くことってあまりないんですが、書くとしてもPHPなど他の言語から使うことが多いのでIF文を必要としたことがありませんでした。

そんなわけで今回は

動けばOK

としてます。
最適な書き方は他にもっとあるかもしんない。

ここが大変参考になりました。

実行環境

mysql Ver 8.0.22 for Linux on x86_64

完成形

適当にテーブルを作って確認。
賞味期限ってexpiration dateって言うらしいですが、スペル覚えてなくて打つのが大変だるい。
サンプルなんだからdateとかlimitとかにしておけばよかった。

やりたいこと

こんなテーブルがあったとして

expirationDateに4月~5月の日付が入ってます。

手作業でやるなら、こんな感じで月ごとの件数でも出して削除後に5月の15件だけ残ってる状態であればコミットしてやればいいんですが、これをSQLに全部やらせたい。

ハマったアレコレ

全部syntax errorにするのやめてもらっていいですか。

IF文書くとエラー

ググってIF文ってこうやるのかーと調べて書いてみたらいきなりエラー。

え、どこがエラー?
見たところ書き方あってるし;のつけ忘れもないんですけど?

で約1日ハマりました。。。

結論としては、MYSQLではIF文はストアドプロシージャまたはストアドファンクションの中でしか使えないということでした。
MYSQLのIF文リファレンスにそれ書いておいてよ。。。

ちなみにSQLServerは通常処理の中でも使用可能。
PostgreSQLは無名ブロックの中であれば使えるそうです。

結果を入れた変数の型が謎

IF文で比較する用の件数を事前に取得するところ。
SELECTした結果が複数行の場合、変数に持たせるのはものすごく面倒っぽかったので、それぞれSUMして1行ずつ取得しました。
CASE文も初めて使った。

この結果をもとにフラグでも立てようかなぁと試してみたところ

そのままstringやintと比較しようとするとfalseに。
どうもCastしてやらないといけないみたいです。

変数の型の調べ方が結局わからなかったので、とりあえず今後は比較前に全部Castするようにしよ…。

ストアドプロシージャのパラメータにallを指定するとエラー

ストアドプロシージャを作ろうとしたらまたエラー。

結果としては、allがMYSQLの予約語と被ってるからだめってことでした。
いやそれsyntax errorじゃなくちゃんと言ってくれよ。。。

その他単純な書き間違いも当然syntax errorなので、原因特定がなかなか大変でした。

実行するとこんな感じ

試しに削除対象を5月、削除予定の行に4月を指定して実行。
ちゃんとロールバックされてます。

今度は両方4月を指定してみると、ちゃんと削除が反映されてました。

結論

条件分岐なんて他の言語にやらせればよくない!?

なんてね。
他のRDBMSはともかく、MYSQLの場合ストアドプロシージャorファンクションの中でないとIF文が使えないので、書き捨てたい処理には向いてない気がします。
使った後に削除するの忘れてゴミプロシージャが大量生産されそう。

どうせその環境、メインシステム用の言語がインストールされてるんでしょ?
ならその言語でSQL繋いで好きなだけIF文書けばいいじゃん。

CASEは結構よさそうですが、SELECTやWHEREでしか使えないようなので今回のように後続処理を実行するかどうかの判断はできないし。
あまり複雑な処理をSQLにさせるとデータ量によっては遅くなるので、プログラム側で判断してシンプルなクエリにしたほうがいいような気がします。

ってことで、今回調べた内容は活用されることはないのでした…。

-プログラミング
-,

© 2024 そんなこと猫でもできる Powered by AFFINGER5