みなさんこんにちは、@ryosk7です。
状況
さくっと本題から入ります。
Mysql2::Error: Operand should contain 1 column(s)
このようなエラーが出た場合の対処法です。
状況としては、
user_ids = @current_user.sample_contents.pluck(:to_user_id)
@samples = SampleModel.where('
(user_id = ? and status = ?) or (user_id = ? and status is not null)',
user_ids, SampleModel.statuses[:open], @current_user.id)
.order(id: "DESC")
このようなコードを書いた際に出力されました。
解決方法
こちらです。
user_ids = @current_user.sample_contents.pluck(:to_user_id)
@samples = SampleModel.where('
(user_id = ? and status = ?) or (user_id = ? and status is not null)',
user_ids.join(","), SampleModel.statuses[:open], @current_user.id)
.order(id: "DESC")
違いにお気づきでしょうか。
配列をカンマで連結した文字列に変えています。
user_ids.join(",")
原因
Active Recordを利用した場合なら、user_idに配列のまま渡しても問題なく認識されますが、
SQL上でも同じようにやっていたことが原因でした。
単一の値であれば問題ないですが、複数の値であれば、リストにした文字列を渡す必要があります。
実際にはこんな感じでSQLが作られます。joinで変換したところはそのままですね。
SQLに強くないので、勉強になりました。
SELECT `sample_models`.* FROM `sample_models` WHERE ((user_id = '10,23,55' and status = 0) or (user_id = 14 and status is not null)) ORDER BY `sample_models`.`id` DESC
参考記事では、INを使ってクエリを叩いています。
同じように書くと、
user_ids = @current_user.sample_contents.pluck(:to_user_id)
@samples = SampleModel.where('
(user_id in (?) and status = ?) or (user_id = ? and status is not null)',
user_ids.join(","), SampleModel.statuses[:open], @current_user.id)
.order(id: "DESC")
このようになります。
SQLもINで作成されていますね。
SELECT `sample_models`.* FROM `sample_models` WHERE ((user_id in ('10,23,55') and status = 0) or (user_id = 14 and status is not null)) ORDER BY `sample_models`.`id` DESC
どちらも同じ結果が得られます。
参考