简体   繁体   English

Rails 活动记录查询 - 不等于和空白/空字符串

[英]Rails Active Record Queries - Not Equal and Blank/Empty Strings

I have an active record query with a Not Equal clause for a string.我有一个活动记录查询,其中包含一个字符串的 Not Equal 子句。 For example:例如:

 Post.where.not(title: "Rails 4")

or或者

 Post.where("title != ?", "Rails 4")

However, if the title is empty or blank it will not be included in the results.但是,如果标题为空或空白,则不会包含在结果中。 How can I also include the records that have a blank or empty title?我怎样才能同时包含标题为空或空的记录?

For example:例如:

Posts帖子

id => 1, title => "Rails 4"
id => 2, title => ""
id => 3, title => "Rails 3"

Actual Result:实际结果:

Post.where.not(title: "Rails 4") #=> [3]

Desired Result:期望的结果:

Post.where.not(title: "Rails 4") #=> [2, 3]

试试下面的查询

Post.where("title != ? OR title = ?", "Rails 4",'')

* NOTE I'm assuming you're using a database like postgres and that the issue you're having is with null values, not empty string values. *注意我假设您正在使用像 postgres 这样的数据库,并且您遇到的问题是 null 值,而不是空字符串值。 If empty string values aren't being returned then you have an entirely different issue如果没有返回空字符串值,那么你有一个完全不同的问题

The reason where.not(title: 'Rails 4') doesn't return what you expect is that you have null values in the string field, and any comparison with null will be null, which is falsey. where.not(title: 'Rails 4')没有返回您期望的结果的原因是您在字符串字段中有 null 个值,并且与 null 的任何比较都将是 null,这是错误的。

Posts帖子

id => 1, title => "Rails 4"
id => 2, title => ""
id => 3, title => "Rails 3"
id => 4, title => NULL

In order to include Post #4 in the results, you need to explicitly include null values.为了在结果中包含 Post #4,您需要明确包含 null 个值。 One way to do that is with IS NULL .一种方法是使用IS NULL

# Original - excludes rows with null title
Post.where.not(title: "Rails 4") #=> [2,3]
# SELECT posts.* FROM posts WHERE posts.title != 'Rails 4' 

# Option #1 - explicitly include null
Post.where.not(title: "Rails 4").or(Post.where(email: nil)) #=> [2,3,4]
# SELECT posts.* FROM posts WHERE (posts.title != 'Rails 4' OR posts.title IS NULL)

# Option #2 - replace null values with empty string
POST.where.not("coalesce(posts.title, '') = ?", 'Rails 4')
# SELECT posts.* FROM posts WHERE NOT (coalesce(posts.title, '') = 'Rails 4')

A third solution is to disallow null values in your string field entirely (with a NOT NULL constraint).第三种解决方案是完全禁止字符串字段中的 null 值(具有NOT NULL约束)。 Allowing null values in a string field can have other unexpected side-effects - for example, if you order your posts by 'email' then posts with a null email will show up in a different spot than you posts with an empty string email, but to the user it just looks confusing.在字符串字段中允许 null 值可能会产生其他意想不到的副作用 - 例如,如果您通过“电子邮件”订购帖子,那么带有 null email 的帖子将显示在与带有空字符串 email 的帖子不同的位置,但是对用户来说,它看起来很混乱。

You can manually type the SQL here and possibly create a database dependency, or use ActiveRecord combined with Arel , which is a bit less readable, but works nicely: 您可以在此处手动键入SQL并可能创建数据库依赖项,或者将ActiveRecord与Arel结合使用,后者可读性较差,但运行良好:

table = Post.arel_table

Post.where(table[:title].not_eq('Rails 4').or(table[:title].eq('')))

Pavans答案是正确的,只需使用它

Post.where("title != ? OR title = ?", "Rails 4",'')

I realise this is 7 years old but it still comes up on Google.我意识到这已经 7 年了,但它仍然出现在谷歌上。 A better solution is using reject instead of where.not更好的解决方案是使用 reject 而不是 where.not

Post.all.reject{|x| x.title == "Rails 4"}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM