我的项目中有一个名为“代码”的表。
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, '']
进行查询或以其他方式进行思考。
答案 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 NULL
和IS NOT NULL
或以ROR语法
Code.where(name: [nil, '']).count
Code.where.not(name: [nil, '']).count
答案 2 :(得分:1)
SQL查询不会返回具有 NULL 值的记录。
供您参考,https://robots.thoughtbot.com/activerecord-s-where-not-and-nil,How to check for Is not Null And Is not Empty string in SQL server?