【问题标题】:shouldn't `where.not(field: "something")` include `where(field: nil)`?`where.not(field: "something")` 不应该包含 `where(field: nil)` 吗?
【发布时间】:2014-12-09 20:21:48
【问题描述】:

也许我快疯了,或者只是需要休息一下,但在我的 Rails 控制台中 Order.where(state: nil).count 返回 1010,但 Order.where.not(state: "pending").count 返回 0... 如果订单的状态为 nil,那么它是不是“待定”,所以我希望 not(state: "pending") 返回的集合包含集合 where(state: nil)

难道不是这样工作的吗?如果不是,arel 的工作方式是否不同?

编辑:更多信息!当我转到另一个数据库时,其中一些记录的状态不是 nil,我运行 Order.where.not(state: "pending").count 时,我得到了一堆订单,其中没有一个是“待定”,但也没有一个是 nil。 where.not 似乎在向查询中隐式添加and not nil

编辑:在绝望中,我转向了黑暗的灵魂。

# look into another shop, that has records
o = Order.where(shop_id: 2)

# summon dread spirits
t = Order.arel_table[:state]

o.where(t.eq(nil).or(t.eq("pending").not)).count

=> 1569

o.where(t.eq(nil)).count

=> 1471

所以在这种情况下,我得到了状态既不是 nil 也不是“pending”的 98 条记录,并且我得到了所有状态为 nil 的记录。我真的很想知道为什么我不能只说where.not("pending") 并具有相同的效果。如果有一个选项我可以调用?比如where.not("pending", include_nil: true)?

编辑:根据@Filip Bartuzi 的评论要求

Order.where.not(state: "pending").to_sql

=> "SELECT \"orders\".* FROM \"orders\"  WHERE \"orders\".\"shop_id\" = 2 AND (\"orders\".\"state\" != 'pending')"

Orders.where(state: nil).to_sql

=> "SELECT \"orders\".* FROM \"orders\"  WHERE \"orders\".\"shop_id\" = 2 AND \"orders\".\"state\" IS NULL"

【问题讨论】:

  • 您确定数据库中只有NULL/'pending' 值吗?以这种方式检查:Order.pluck(:state)
  • 很遗憾,我无法访问 rails 环境,因此无法自行测试,但请您粘贴 Order.where.not(status: "pending").to_sqlOrder.where(status:nil) 的值

标签: ruby-on-rails-4 arel


【解决方案1】:

Order.where.not(state: "pending").to_sql 生成:

=> "SELECT \"orders\".* FROM \"orders\" WHERE \"orders\".\"shop_id\" = 2 AND (\"orders\".\"state\" != 'pending')"

它将返回所有具有 VALUES 且不是“待定”的记录。当您将pending 设置为nil 时(如Order.first.update! state: nil 它在数据库中分配NULL

NULL 不会被解释为 SQL 中的值,因此它不会包含在 SELECT 响应中

所以答案是:where.not(field: “something”) 不包括where(field: nil)

你可以在这里查看它是如何工作的:

http://www.w3schools.com/sql/trysql.asp?filename=trysql_select_all

进入分类表,首先执行

UPDATE Categories
SET CategoryName = NULL
WHERE CategoryName = 'Beverages'

所以现在我们有了计数 8 的类别,其中一个在列 CategoryName 上有 NULL

现在执行:

SELECT CategoryName FROM Categories
WHERE CategoryName != 'Condiments'

如您所见,返回了 6 条记录(因此它使用 NULL 跳过了一条)

【讨论】:

  • 好的,所以要同时包含不是事物的值和非值,我必须始终跳转到 arel_table 样式 or 查询?还是有别的办法?
  • 首先我认为你不应该将任何值表示为 NULL。因此,如果您的订单可以是“待处理”或“已取消”,您应该将“已取消”存储为字符串或数字表示。如果您使用 Rails 4,我建议在 Order 模型上使用 enum
  • 啊好的,我使用 nil 作为默认状态,但您是正确的,默认状态应该是实际状态。好建议。
【解决方案2】:

SQL 实现遵循 3 值逻辑,其中 NULL 不是值,而是表示值的缺失。 3 值逻辑为逻辑运算定义了如下真值表:(此处为未知)

p       |q      |p OR q |p AND q|p = q
True    |True   |True   |True   |True
True    |False  |True   |False  |False
True    |Unknow |True   |Unknown|Unknown
False   |True   |True   |False  |False
False   |False  |False  |False  |True
False   |Unknown|Unknown|False  |Unknown
Unknown |True   |True   |Unknown|Unknown
Unknown |False  |Unknown|False  |Unknown
Unknown |Unknown|Unknown|Unknown|Unknown

由于 where 测试数据集中每个条目的相等性 (row.state == 'pending'),如果 row.state 为 NULL,则根据上面的真值表,结果为“未知”。 'Unknown' 不正确,因此该行不包含在结果集中。

更多信息请访问Wikipedia

【讨论】:

    猜你喜欢
    • 2011-01-21
    • 1970-01-01
    • 1970-01-01
    • 2023-02-08
    • 1970-01-01
    • 1970-01-01
    • 2020-12-05
    • 2015-05-07
    • 2011-04-13
    相关资源
    最近更新 更多