Ruby on rails ActiveRecord:可以使用.where(foo:“bar”)成功查询,但是.where.not(foo:“bar”)不会返回正确的结果

Ruby on rails ActiveRecord:可以使用.where(foo:“bar”)成功查询,但是.where.not(foo:“bar”)不会返回正确的结果,ruby-on-rails,ruby,activerecord,rails-activerecord,ruby-on-rails-5,Ruby On Rails,Ruby,Activerecord,Rails Activerecord,Ruby On Rails 5,我有一个这样构建的查询: @events = current_organization.events.order(started_at: :asc) 我想查询所有状态未取消的事件。但是,当我使用这样的查询时: current_organization.events.order(started_at: :asc).where.not(status: "canceled") 它什么也不返回。然而,为了试验起见,我尝试了: @events = current_organization.events

我有一个这样构建的查询:

@events = current_organization.events.order(started_at: :asc)
我想查询所有状态未取消的事件。但是,当我使用这样的查询时:

current_organization.events.order(started_at: :asc).where.not(status: "canceled")
它什么也不返回。然而,为了试验起见,我尝试了:

@events = current_organization.events.where(status: "canceled")
它成功地返回了已取消的事件。由于某种原因,反向不起作用。这有什么原因吗


编辑:我唯一能找到的解决方法就是使用wherestatus:nil,但这真的不直观

您的问题更新如下:

编辑:我唯一能找到的解决方法就是使用wherestatus:nil,但这真的不直观

这很重要。这告诉我您的状态列允许空值,并且您有空值

这些空值加上ActiveRecord对where.not的实现有点差,这是造成问题的原因。如果我们看一下由以下程序生成的SQL:

where.not(status: "canceled")
我们看到:

("events"."status" != 'canceled') 
但在SQL中,x=null和x null对所有x都计算为null,包括当x本身为null且null在SQL中不是真实值时;这意味着当涉及null时,xy与x=y并不完全相反:如果一行的状态为null,那么where status='cancelled'和where status!='“取消”将找到它

无论何时涉及null,您都必须使用按预期方式处理null的运算符:is null、is not null、is distinct from、is not distinct from、

在状态列中允许空值对我来说听起来很奇怪,修复它会使问题消失:

添加一个迁移,将所有空状态更改为更好的工作状态。status is null列表示行/模型根本没有状态,这很奇怪,所以请给它们一个真实的状态代码。 添加一个迁移,使您的状态列不为null,这样您就再也不用担心null状态了。 是否将模型的验证更新为不允许status.nil?发生。
一般来说,不要在任何地方使用可为null的列,除非您确定null是有意义的,并且准备好处理null在SQL中的工作方式。

尝试检查to_SQL输出。这有助于调试sql语句current_organization.events.orderstarted_at::asc.where.notstatus:Cancelled.to_SQLEvents模型上是否设置了默认范围?@MickeySheu,以下是不同的输出@events=current\u organization.events.orderstarted\u at::asc.wherestatus:cancelled.to\u sql=>SELECT\events\.\events\\ FROM\events\WHERE\events\.\organization\u id\=1和\events\.\status\=“cancelled”ORDER BY\events\.\asc”@events=current\u organization.events.orderstarted\u at::asc.WHERE.notstatus:Cancelled.to_sql=>“选择\events\.\FROM\events\WHERE\events\.\organization\u id\=1和\events\.\status\!='cancelled'ORDER BY\events\.\started\ASC”@mysmallidea,在我的事件模型上没有设置默认范围为什么希望WHERE.not查询找到任何内容?您确定该组织存在未取消的事件吗?将默认值设置为“我的列”是否与使该列不为null相同?不完全相同,但您可以将其设置为“不为null”并添加默认值。但是,您确实希望列不为null,否则null将在其中结束,并导致问题。您的回答很好地解释了SQL如何处理null。我继续对那个专栏进行了必要的修改,我认为从现在开始,这不会给我带来任何问题。非常感谢。