由于未知OID被视为String,ActiveRecord和SQL不会返回相同结果的情况

时间:2016-06-14 16:09:23

标签: ruby-on-rails postgresql activerecord

我有问题。之前我发布了一个类似的问题,我要问的是哪个问题得到了解答,可以在这里找到上下文ActiveRecord Count and SQL count do not match

这个问题与计算查询结果有关。在这个问题中,我得到的是不同的对象结果,而不是得到相同的计数结果。

这是ActiveRecord代码:

scope :unverified_with_no_associations, -> {
  find_by_sql("SELECT DISTINCT(accounts.id, accounts.email) FROM accounts WHERE level = 0 AND id NOT IN
                (SELECT DISTINCT(account_id) FROM verifications) AND id NOT IN 
                (SELECT DISTINCT(account_id) FROM positions) AND id NOT IN
                (SELECT DISTINCT(account_id) FROM edits) AND id NOT IN
                (SELECT DISTINCT(account_id) FROM posts) AND id NOT IN
                (SELECT DISTINCT(account_id) FROM reviews) AND id NOT IN
                (SELECT DISTINCT(sender_id) FROM kudos) AND id NOT IN
                (SELECT DISTINCT(account_id) FROM stacks WHERE account_id IS NOT NULL)")

这会返回[#<Account:0x007f96bf143c70 id: >]并在sql输出unknown OID 2249: failed to recognize type of 'row'. It will be treated as String.

之后收到此消息

如果我在数据库中运行上面的sql代码,我将检索我需要的内容:

 -------row-------
 (1234,me@gmail.com)

导致这种不匹配的原因是什么,我该如何避免它。我发现这篇关于自定义postgres类型Custom postgres types的帖子,但这看起来我需要了解事物的细节,我想避免这种情况。有人知道为什么这是一个问题吗?

1 个答案:

答案 0 :(得分:1)

您遇到此问题是因为ActiveRecord无法将此行识别为您帐户表格中的行。 AR没有解析你的sql而且它不知道如何处理匿名皮质。

如果您使用find_by_sql所选属性未正确映射到您的模型但仍可访问,请尝试:

result.id
result.email

但你也有两种方法可以解决这个问题。

首先(这是非常讨厌但很简单的解决方案),将您的sql转换为Arel,即范围的虚拟内容:

scope :unverified_with_no_associations, -> {
  send(:default_scoped).from(Arel.sql("(SELECT * FROM accounts WHERE level = 0 AND id NOT IN
                (SELECT DISTINCT(account_id) FROM verifications) AND id NOT IN 
                (SELECT DISTINCT(account_id) FROM positions) AND id NOT IN
                (SELECT DISTINCT(account_id) FROM edits) AND id NOT IN
                (SELECT DISTINCT(account_id) FROM posts) AND id NOT IN
                (SELECT DISTINCT(account_id) FROM reviews) AND id NOT IN
                (SELECT DISTINCT(sender_id) FROM kudos) AND id NOT IN
                (SELECT DISTINCT(account_id) FROM stacks WHERE account_id IS NOT NULL))  
                AS accounts"))

...并调用AR不同的方法:

Account.unverified_with_no_associations.select(:id, :email).distinct

第二(这是更好的解决方案):

不要直接使用sql。使用Arelhttps://github.com/rails/arel)或squeelhttps://github.com/activerecord-hackery/squeel

重写您的范围