Ruby on Rails和查询(理解的问题)

时间:2018-12-12 07:37:38

标签: mysql ruby-on-rails ruby-on-rails-5

我的项目中有一个名为“代码”的表。

irb(main):017:0> Code.new                                      
=> #<Code id: nil, company_id: nil, name: nil, employee_uuid: nil, employee_email: nil, redeemed_at: nil, created_at: nil, updated_at: nil>

在我的数据库中,我总共有97994个代码条目。

irb(main):018:0> Code.all.count
(127.7ms)  SELECT COUNT(*) FROM "codes"
=> 97994

所以,我不明白的是以下内容。 到目前为止,我已经使用name属性对其进行了测试。

irb(main):019:0> Code.where(name: "").count
(135.0ms)  SELECT COUNT(*) FROM "codes" WHERE "codes"."name" = ?  [["name", ""]]
=> 0
irb(main):020:0> Code.where(name: " ").count
(18.3ms)  SELECT COUNT(*) FROM "codes" WHERE "codes"."name" = ?  [["name", " "]]
=> 0

如果执行相反的查询,它应该给我丢失的对象,在这种情况下,是我的总代码量。

irb(main):021:0> Code.where.not(name: "").count 
(116.3ms)  SELECT COUNT(*) FROM "codes" WHERE ("codes"."name" != ?)  [["name", ""]]
=> 94652
irb(main):022:0> Code.where.not(name: " ").count
(19.9ms)  SELECT COUNT(*) FROM "codes" WHERE ("codes"."name" != ?)  [["name", " "]]
=> 94652

但是我得到的结果是94652,而不是97994(来自Code.all.count)

这让我感到奇怪。我确实检查了剩下的代码是什么:

irb(main):023:0> rest = Code.all - Code.where(name: "") - Code.where.not(name: "")
Code Load (1030.6ms)  SELECT "codes".* FROM "codes"
Code Load (16.1ms)  SELECT "codes".* FROM "codes" WHERE "codes"."name" = ?  [["name", ""]]
Code Load (489.1ms)  SELECT "codes".* FROM "codes" WHERE ("codes"."name" != ?)  [["name", ""]]
... a huge array was returned
irb(main):024:0> rest.last
=> #<Code id: 86217, company_id: 307, name: nil, employee_uuid: "XXXXXXXXXXXXXX", employee_email: "XXXXX@EMAIL.COM", redeemed_at: "2018-07-09 12:30:29", created_at: "2018-12-11 13:07:57", updated_at: "2018-12-11 13:07:57">

我对此感到很好奇,所以我又检查了一件事:

irb(main):027:0> rest.last.name == ""
=> false
irb(main):028:0> rest.last.name != ""
=> true

所以rest.last.name不是“”(当然不是,名称是nil

但我仍然明白了

irb(main):025:0> Code.where(name: "").include? rest.last
Code Load (108.1ms)  SELECT "codes".* FROM "codes" WHERE "codes"."name" = ?  [["name", ""]]
=> false
irb(main):026:0> Code.where.not(name: "").include? rest.last
Code Load (365.9ms)  SELECT "codes".* FROM "codes" WHERE ("codes"."name" != ?)  [["name", ""]]
=> false

我一直以为某物及其负数总会成为总金额,这意味着何时某物发生,什么时候该物不发生将为我们提供始终的答案。 A + !A = 1 为什么我看到这个?我不能遵循这个。

预先感谢您的帮助。

更新问题以回答评论:

irb(main):002:0> Code.where(name: [nil, '']).count                                                   
(432.2ms)  SELECT COUNT(*) FROM "codes" WHERE ("codes"."name" = '' OR "codes"."name" IS NULL)
=> 3342

这个数字就是

irb(main):003:0> Code.all.count - Code.where.not(name: "").count
(315.2ms)  SELECT COUNT(*) FROM "codes"
(332.5ms)  SELECT COUNT(*) FROM "codes" WHERE ("codes"."name" != ?)  [["name", ""]]
=> 3342

好吧,到目前为止,我了解到当我测试字符串是否为空时,SQL无法与Nil进行比较。这意味着我需要使用数组[nil, '']进行查询或以其他方式进行思考。

3 个答案:

答案 0 :(得分:3)

在这种情况下,存储在数据库中的name的默认值为NULL。如果您没有为数据库中的name项保存code,它将被存储为NULL而不是空字符串""

因此,如果您运行查询Code.where(name: "").count,这将显式尝试仅返回名称等于空字符串("")的那些行,而忽略所有具有name = {{ 1}}或NULL。根据您的情况,这是" "

运行查询0时,会收到Code.where(name: [nil, '']).count的结果,该结果等于表中所有行与名称不等于的行之间的差。空字符串(3342)。证明表中有3342行将Code.where.not(name: "").count存储为name

因此,为了避免这种情况,您可以在创建Code表的迁移中将NULL(空字符串)的默认值设置为name属性。这样,您的查询结果将查找名称不存在的条目,即("")一致。

更新:

Code.where(name: "").count将忽略数据库中Code.where.not(name: '')处的记录。原因是形成的查询:

name = NULL

此查询明确尝试查找名称不为“”的那些行,但是为了检查是否存在NULL,我们必须编写一个类似SQL的查询:

SELECT * FROM Codes WHERE name != "";

如果我们在ActiveRecord中写入SELECT * FROM Codes WHERE name IS NOT NULL;,则会生成上述查询。

要在单个查询中实现上述两个不同查询中提到的两个条件,我们将在ActiveRecord中使用以下条件:

Codes.where.not(name: nil)

这将生成以下查询:

Code.where.not(name: [nil, ""])

上面的查询确保我们避免在数据库中同时使用空字符串和NULL值名称的条件的记录。

答案 1 :(得分:2)

这是因为sql !==运算符无法与NULL比较。要进行NULL比较,您需要使用IS NULLIS NOT NULL或以ROR语法

Code.where(name: [nil, '']).count
Code.where.not(name: [nil, '']).count

答案 2 :(得分:1)

当使用 where 子句时,

SQL查询不会返回具有 NULL 值的记录。

供您参考,https://robots.thoughtbot.com/activerecord-s-where-not-and-nilHow to check for Is not Null And Is not Empty string in SQL server?