Ruby on rails 检索具有空数组的记录时出现问题
我有一个大约100个用户的表,还有一个用户ID数组。我想做的是显示不属于此用户ID数组的所有用户。当我这样做的时候Ruby on rails 检索具有空数组的记录时出现问题,ruby-on-rails,ruby-on-rails-3,postgresql,activerecord,arel,Ruby On Rails,Ruby On Rails 3,Postgresql,Activerecord,Arel,我有一个大约100个用户的表,还有一个用户ID数组。我想做的是显示不属于此用户ID数组的所有用户。当我这样做的时候 User.where('id NOT IN (?)', [9, 2, 3, 4]) SELECT "users".* FROM "users" WHERE (id NOT IN (NULL)) 它成功返回用户id不属于该数组的记录。但是,如果该数组是空的,那么 User.where('id NOT IN (?)', []) 它不会返回任何用户,SQL查询如下所示 Us
User.where('id NOT IN (?)', [9, 2, 3, 4])
SELECT "users".* FROM "users" WHERE (id NOT IN (NULL))
它成功返回用户id不属于该数组的记录。但是,如果该数组是空的,那么
User.where('id NOT IN (?)', [])
它不会返回任何用户,SQL查询如下所示
User.where('id NOT IN (?)', [9, 2, 3, 4])
SELECT "users".* FROM "users" WHERE (id NOT IN (NULL))
有人知道为什么会发生这种情况,或者这可能是一个bug吗?我在PostgreSQL中使用Rails 3.2.5。ActiveRecord(至少3.2.1)将空数组视为空数组。调用中的占位符,其中
调用由处理。如果您对代码进行一点跟踪,您会发现:
然后:
一个空数组将满足所有四个条件以使您到达c.quote(nil)
,这就是NULL的来源。所有导致c.quote(nil)
的特殊逻辑都表明这是故意行为
用空列表表示(或不表示):
where c in ()
应该会产生一个SQL错误,所以AR人员可能正试图通过悄悄地将错误的SQL转换为c in(null)
来防止这种情况。请注意,以下两种情况均不存在:
select ... from t where c in (null);
select ... from t where c not in (null);
由于SQL的NULL行为,应该产生任何结果。这是一个典型的新手错误,AR人员真的应该更清楚
我自己也希望有一个例外:告诉我我将要部署一颗脚弹,比仅仅给我一把不同的枪要友好得多
执行摘要:
where('c in(?),[])
或where('c not in(?),[])
,因为这两条语句都没有多大意义在Rails 4中,您可以使用
User.where.not(id:[])
,这将为您提供正确的结果。它产生:
SELECT "users".* FROM "users" WHERE (1 = 1)
不幸的是,用户。其中('id NOT IN(?),[])
应该是等效的,但不是。它仍然会给您错误的结果:
SELECT "users".* FROM "users" WHERE (id NOT IN (NULL))
参考资料:
User.where.not(id: [])
这将为您处理空数组问题。我不知道这是否是要求解决的问题,但我来这里查找所有具有空(序列化)数组属性的记录。我为Rails 5.0解决了这个问题,如下所示:
User.where(my_array_attribute: nil)
反之亦然:
User.where.not(my_array_attribute: nil)
这看起来像是Rails问题,或者可能是
Pg
gem问题;它将空数组视为NULL
。非常奇怪,而且行为恶劣。你能直接用Pg
gem测试一个准备好的语句,看看它是这样对待数组参数的,还是Rails/ActiveRecord级别在这样做?@CraigRinger:这将是Rails/ActiveRecord问题,而不是Pg
问题。AR自己处理占位符。@CraigRinger:AR的人有时在SQL方面出人意料地糟糕,他们是故意这么做的。在这里插入“儿子,我很失望”的图片。@muistooshort是的,这不是我会选择的工具。然后,Hibernate(至少同样流行)也有自己的一些令人兴奋的怪癖,比如默认忽略串行列的DEFAULT nextval(…)
,而是从所有表中共享的自己的Hibernate\u序列生成ID。求爱!然而,由于AR拥有自己的占位符,我不禁对SQL注入和安全性感到好奇;似乎不是。。。超级健壮。是的,理智的东西在这里肯定是个例外。@CraigRinger:我,像往常一样,责备MySQL:)我现在明白为什么我的测试失败了。:)我不同意要一个例外。如果我想让作用域无论是否传递空数组都能正常工作,那么构造一个AR作用域就更优雅了,在这里我不必执行空数组保护。@gabe欢迎你不同意,但“正常工作”通常是隐藏bug的捷径,我非常喜欢一个告诉我要讲道理的工具,而不是一个试图讲道理却默默地做错事的工具。在一个模糊相关的注释中,User.where(:id=>[[],[3]])给出了无效的sql:“选择用户
*FROM用户
其中用户
id
在(,3)”中请考虑清楚地解释为什么这可能是正确的答案。@ DavidL:这保证了数组不会是空的。这还假定没有值为0的id(在Rails中通常是这样)。
User.where.not(my_array_attribute: nil)