Рельсы, где условие с использованием NOT NULL

используя стиль rails 3, как бы я написал противоположность:

Foo.includes(:bar).where(:bars=>{:id=>nil})

Я хочу найти, где id не равен нулю. Я попробовал:

Foo.includes(:bar).where(:bars=>{:id=>!nil}).to_sql

но это возвращает:

=> "SELECT     \"foos\".* FROM       \"foos\"  WHERE  (\"bars\".\"id\" = 1)"

Это определенно не то, что мне нужно, и почти похоже на ошибку в ARel.

5 ответов


канонический способ сделать это с Rails 3:

Foo.includes(:bar).where("bars.id IS NOT NULL")

ActiveRecord 4.0 и выше добавляет where.not так что вы можете сделать это:

Foo.includes(:bar).where.not('bars.id' => nil)
Foo.includes(:bar).where.not(bars: { id: nil })

при работе с областями между таблицами я предпочитаю использоватьmerge так что я могу более легко использовать существующие.

Foo.includes(:bar).merge(Bar.where.not(id: nil))

кроме того, поскольку includes не всегда выбирает стратегию соединения, вы должны использовать references здесь также, в противном случае вы может оказаться недопустимым SQL.

Foo.includes(:bar)
   .references(:bar)
   .merge(Bar.where.not(id: nil))

Я больше не рекомендуем использовать Squeel для этого, поскольку он не всегда имеет штатного сопровождающего, и это зависит от частных API, которые вызывают частые изменения.


это не ошибка в ARel, это ошибка в вашей логике.

что вы хотите здесь:

Foo.includes(:bar).where(Bar.arel_table[:id].not_eq(nil))

Для Rails4:

Итак, то, что вы хотите, - это внутреннее соединение, поэтому вам действительно нужно просто использовать предикат joins:

  Foo.joins(:bar)

  Select * from Foo Inner Join Bars ...

но для записи, если вы хотите условие "NOT NULL", просто используйте предикат not:

Foo.includes(:bar).where.not(bars: {id: nil})

Select * from Foo Left Outer Join Bars on .. WHERE bars.id IS NOT NULL

обратите внимание, что этот синтаксис сообщает об устаревании (он говорит о фрагменте строки SQL, но я думаю, что условие хэша изменяется на строку в синтаксическом анализаторе?), поэтому обязательно добавьте ссылки в конец:

Foo.includes(:bar).where.not(bars: {id: nil}).references(:bar)

предупреждение об устаревании: похоже, вы хотите загрузить таблицу(ы) (один из. :...), на которые ссылаются в строковом фрагменте SQL. Например:

Post.includes(:comments).where("comments.title = 'foo'")

В настоящее время Active Record распознает таблицу в строке и знает чтобы присоединить таблицу комментариев к запросу, а не загружать комментарии в отдельном запросе. Однако, делать это без написания полноценного SQL парсер изначально порочна. Поскольку мы не хотим писать SQL парсер, мы удаляем это функциональность. Отныне ты должен явно сообщите Active Record, когда вы ссылаетесь на таблицу из строка:

Post.includes(:comments).where("comments.title = 'foo'").references(:comments)

с рельсами 4 легко:

 Foo.includes(:bar).where.not(bars: {id: nil})

Смотрите также: http://guides.rubyonrails.org/active_record_querying.html#not-conditions


Не уверен, что это полезно, но это то, что сработало для меня в Rails 4

Foo.where.not(bar: nil)