質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Ruby on Rails

Ruby on Railsは、オープンソースのWebアプリケーションフレームワークです。「同じことを繰り返さない」というRailsの基本理念のもと、他のフレームワークより少ないコードで簡単に開発できるよう設計されています。

Q&A

解決済

2回答

3517閲覧

[Rails]where("カラム名 = ?", 値)とwhere(カラム名: 値)で取得できる結果が違う

s_diff

総合スコア107

Ruby on Rails

Ruby on Railsは、オープンソースのWebアプリケーションフレームワークです。「同じことを繰り返さない」というRailsの基本理念のもと、他のフレームワークより少ないコードで簡単に開発できるよう設計されています。

0グッド

0クリップ

投稿2019/02/28 02:18

編集2019/02/28 02:28

Ruby On Railsでwhere句を使い、

ruby

1odp_this_month = OrderDownloadPlan.where(user_id: @user.id).where("expire_at = ? or expire_at >= ?", nil, date.beginning_of_month).last 2

のレコードを取得したいと思っています。
date.beginning_of_monthの値は2018-12-01で、
OrderDownloadPlan.where(user_id: @user.id)のレコードは一つだけで以下のような値が入っています。

[0] #OrderDownloadPlan:0x007fadfcfedb28 {

:id => 2, :user_id => 1, :status_id => "enable", :started_at => Mon, 10 Dec 2018 00:00:00 JST +09:00, :expire_at => nil, :created_at => Tue, 11 Dec 2018 10:16:39 JST +09:00, :updated_at => Thu, 28 Feb 2019 09:44:45 JST +09:00 }

しかし、where(カラム名: 値)で取得できるレコードが、where("カラム名 = ?", 値)では取得できず、OR検索が上手くいきません。

###環境
Rails 4.2.6

###試したこと

ruby

1odp_this_month = OrderDownloadPlan.where(user_id: @user.id).where("expire_at = ?", nil)

出力

(0.5ms) SELECT COUNT(*) FROM order_download_plans WHERE order_download_plans.user_id = 1 AND (expire_at = NULL OR expire_at >= '2018-12-01 00:00:00.000000')

[]

ruby

1odp_this_month = OrderDownloadPlan.where(user_id: @user.id).where(expire_at: nil)

出力

(0.4ms) SELECT COUNT(*) FROM order_download_plans WHERE order_download_plans.user_id = 1 AND order_download_plans.expire_at IS NULL

OrderDownloadPlan Load (0.6ms) SELECT order_download_plans.* FROM order_download_plans WHERE order_download_plans.user_id = 1 AND order_download_plans.expire_at IS NULL
[
[0] #OrderDownloadPlan:0x007fadfcfedb28 {
:id => 2,
:user_id => 1,
:status_id => "enable",
:started_at => Mon, 10 Dec 2018 00:00:00 JST +09:00,
:expire_at => nil,
:created_at => Tue, 11 Dec 2018 10:16:39 JST +09:00,
:updated_at => Thu, 28 Feb 2019 09:44:45 JST +09:00
}
]

sql文を見ても、同じ処理をしているように思えます。

###知りたいこと

以下の二点について知りたいです。
・ where("カラム名 = ?", 値)とwhere(カラム名: 値)の違い
・ where("expire_at >= ?", date.beginning_of_month)とwhere(expire: nil)をORでつなぐ方法

ご教示いただけることがあれば、何卒よろしくお願いいたします。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

ベストアンサー

3値論理で動くデータベースの仕様です。

NULL = NULLはtrueではないと解釈されるので、NULLを含む値を検索したい場合、column IS NULLという専用の構文を使う必要があります。

Railsから.where(column: nil)とやった場合には自動でIS NULLに変換してくれますが、.where('column = ?', nil)とした場合には?を置き換えるだけなので= NULLとなり、検索できません。

投稿2019/02/28 02:23

maisumakun

総合スコア145183

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

maisumakun

2019/02/28 02:24

or検索については、Rails 5以上であれば.orというメソッドがあります。
s_diff

2019/02/28 02:31

ご回答ありがとうございます。 環境を書き忘れていました。申し訳ありません。 追記しています。 ご指摘の通り、odp_this_month = OrderDownloadPlan.where(user_id: @user.id).where("expire_at is ?", nil)のようにすることでレコードを取得できました。 いつもありがとうございます。
maisumakun

2019/02/28 02:33

なお、NULL同士を比較した場合にtrueとなる「IS DISTINCT FROM」という演算子もありますが、標準として規定はされているものの、実装しているのはPostgresぐらいで、Sqliteでは「IS」だけ、MySQLでは「<=>」を使う必要があるなど、いまのところ統一がなされていません。
guest

0

発行されているSQL違いますよね。

where("expire_at = ?", nil) の場合 expire_at = NULL

where(expire_at: nil) の場合 expire_at IS NULL

NULL= で比較することはできません。

http://www.sql-reference.com/select/is_null.html

また、OR条件なら生SQL書かなくてもActive Recordの or メソッドを使えば良いのではないでしょうか。

https://qiita.com/QUANON/items/0033a5adb76d0cb963cd

投稿2019/02/28 02:29

退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

s_diff

2019/02/28 02:33

ご回答ありがとうございます。 expire_at = NULLとexpire_at IS NULLが異なるということを知りませんでした。 そういった細かい部分を自分勝手に理解してしまうことで、迷宮に入ってしまいがちなので気をつけて行きたいと思います。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問