先日少しはまった話。
MySQLにはSELECT … INTO 構文というものがあります。これを利用すると簡単にクエリー結果を変数に格納することができます。
参考:MySQL :: MySQL 5.6 リファレンスマニュアル :: 13.2.9.1 SELECT … INTO 構文
仕事で、MySQLのストアドを利用して、指定のIDとOUTパラメータを引数にセットし、OUTパラメータに引数に対応する値を返すというストアドを同僚が作っていました。そのストアドはSELECT … INTO 構文を使って下記のようになっていました。
CREATE DEFINER=`root`@`localhost` PROCEDURE `P_GetFruit`(IN p_id INT, OUT p_name VARCHAR(45)) BEGIN SELECT fruit_name INTO @name FROM fruit WHERE fruit_id = p_id LIMIT 1; SET p_name = @name; END
この時、p_idに1を指定すると、p_nameには「りんご」という値が入ります。
もちろん、p_idに2を指定すると、p_nameには「みかん」という値が入ります。
では、ここでp_idに10を指定するとどうなるでしょう。fruid_idが10のfruit_nameはないから、結果はnullになる。同僚もそうなると思ったようですが、違いました。
結果は一つ前に実行したときに取得した「みかん」を取得。プログラム作って動かしていた自分は、最初、「やけに同じ結果が返ってくるなぁ。てっきりnullが返ってくると思ったのだけど」なんて呑気に思い、しばらくバグに気づきませんでした。
これはなぜかというと、MySQLの変数はセッション変数で、つなげている間は結果が保持されるためだそうです。
参考:mysqlでユーザ定義変数をつかう – 眠すぎて明日が見えない
なので、上記のように変数に格納したい場合は、いったんnullで初期化する記述を追加したほうがいいです。
CREATE DEFINER=`root`@`localhost` PROCEDURE `P_GetFruit`(IN p_id INT, OUT p_name VARCHAR(45)) BEGIN SET @name = null; SELECT fruit_name INTO @name FROM fruit WHERE fruit_id = p_id LIMIT 1; SET p_name = @name; END
ただ、この程度だったら直接outパラメータを指定したほうがシンプルかもしれないですけどね。
CREATE DEFINER=`root`@`localhost` PROCEDURE `P_GetFruit`(IN p_id INT, OUT p_name VARCHAR(45)) BEGIN SELECT fruit_name INTO p_name FROM fruit WHERE fruit_id = p_id LIMIT 1; END
それより、WorkBenchがちょくちょく結果を表示してくれないことがあった困る。何で、「1 row(s) returned」って書いてあるのに、表示してくれないことがあるんだ……。
コメント