hotoolong's blog

RailsやVim、業務で気になったことを綴ってます

MySQLでユーザ定義変数とcountを組み合わせて失敗した

MySQLでユーザ定義変数を使っていたときのお話です。

ユーザ情報に紐づくアカウント数に合わせて出力する形式を変更して解析しようとしてたのですが、 MySQLのユーザー定義変数をcase文で判断させようとしたところ挙動がおかしくなってしまいました。

ユーザ情報はusersテーブルに 紐づくアカウント情報はaccountsテーブルに登録してるとして、 ユーザ情報毎にアカウント情報の数を出力させて 5件以上アカウント情報が登録されているユーザは!!で強調するように出力しようとしたときに 一旦ユーザ定義変数に格納してcase文で条件分岐しようとして以下のようなSQL文を作成していました。

select
   u.id ,
   u.name,
  @b:=count(a.id),
  case @cnt:=count(a.id)
    when @cnt >= 5 then concat('!! ', @cnt, ' !!')
    else @cnt
  end
from users u
inner join accounts a on a.user_id = d.id
group by u.id;

出力はしようとしたcount(a.id)の値は何も表示されずに出力されてしまいました。

MySQL :: MySQL 5.6 リファレンスマニュアル :: 9.4 ユーザー定義変数

には

SELECT ステートメントでは、それぞれの選択式は、クライアントに送信されるときにのみ評価されます。つまり、HAVING、GROUP BY、または ORDER BY 句では、選択式リストで値を割り当てられた変数を参照しても、予想どおりには機能しないということです。

と記載されているので、countで式評価したものを変数に入れるというのは難しそうです。 面倒ですが、 count(a.id)を何度も記載して出力結果を表示することで代用することにしました。 count(a.id) のような短さであればいいのですが、すごく長くなってしまった場合は一時変数に入れたくなりますね。