mysql – 为什么Rails在使用where子句哈希语法的范围内添加“O​​R 1 = 0”

我正在使用的项目是在RDS上使用MySQL(具体是mysql2 gem)。

当我使用一个条件的散列,包括一个范围在一个where语句我有一个奇怪的除了我的查询。

User.where(id: [1..5])

User.where(id: [1...5])

分别产生以下查询:

SELECT `users`.* FROM `users` WHERE ((`users`.`id` BETWEEN 1 AND 5 OR 1=0))
SELECT `users`.* FROM `users` WHERE ((`users`.`id` >= 1 AND `users`.`id` < 5 OR 1=0))

查询工作非常正常,因为OR FALSE实际上是无效的。我只是想知道为什么Rails或者AREL将这个代码片段添加到查询中。

编辑

它看起来像可以解释这是line 26 in ActiveRecord::PredicateBuilder的线。仍然不知道哈希如何可以是空的?在这一点上,但也许别人做。

编辑2

这是intersting。我正在调查Filip的评论,看看他为什么这样做,因为它似乎就像一个澄清,但他是正确的1..5!= [1..5]。前者是从1到5的包含范围,其中后者是其第一个元素是前者的数组。我试着把这些放到一个AREL里面,在这个调用中看到SQL产生,OR 1 = 0不存在!

User.where(id: 1..5) #=> SELECT "users".* FROM "users"  WHERE ("users"."id" BETWEEN 1 AND 5)
User.where(id: 1...5) #=> SELECT "users".* FROM "users"  WHERE ("users"."id" >= 1 AND "users"."id" < 5)

虽然我仍然不知道为什么AREL添加OR 1 = 0,它永远是假的,看起来是不必要的。这可能是由于数组和范围的处理方式不同。

基于你发现的事实,[1..5]不是正确的方式来指定范围…我已经发现为什么[1..5]的行为如此。要到达那里,我首先发现一个散列条件中的空数组产生1 = 0 SQL条件:

User.where(id: []).to_sql
# => "SELECT \"users\".* FROM \"users\"  WHERE 1=0"

而且,如果您查看ActiveRecord::PredicateBuilder::ArrayHandler code,您将看到数组值总是被分割为范围和其他值。

ranges, values = values.partition { |v| v.is_a?(Range) }

这就解释了为什么在使用非范围值时看不到1 = 0。也就是说,从数组中获取1 = 0而不包括范围的唯一方法是提供一个空数组,产生1 = 0的条件,如上所示。当所有数组都有一个范围时,您将获得范围条件(范围),并分别获取执行的空数组条件(值)。我的猜测是没有一个很好的理由,这只是简单易于让它比避免它(因为结果集是等同的)。如果分区代码有点聪明,那么就不用再附加额外的空值数组,并且可以跳过1 = 0的条件。

至于1 = 0是从哪里来的…我认为来自数据库适配器,但我找不到确切的位置。但是,我会称之为尝试找不到记录。换句话说,WHERE 1 = 0不会返回任何用户,这对于WHERE id = null的替代SQL是有意义的,它会发现其ID为null的任何用户(意识到这不是真正正确的SQL语法) 。这是我试图找到所有用户的ID在空集(我们不是要求无ids或者空ids或其他)的期望。所以,在我看来,把1 = 0的确切位置作为一个黑盒子就可以了。至少我们现在可以理解为什么阵列内部的范围导致它出现!

UPDATE

我也发现,即使直接使用ARel,你仍然可以得到1 = 0:

User.arel_table[:id].in([]).to_sql
# => "1=0"
http://stackoverflow.com/questions/21886242/why-is-rails-is-adding-or-1-0-to-queries-using-the-where-clause-hash-syntax-wi

本站文章除注明转载外,均为本站原创或编译
转载请明显位置注明出处:mysql – 为什么Rails在使用where子句哈希语法的范围内添加“O​​R 1 = 0”