使用Active Record,Rails和Postgres查找具有多个重复字段的行

new*_*ere 93 postgresql activerecord ruby-on-rails

使用Postgres和Activerecord在多列中查找具有重复值的记录的最佳方法是什么?

我发现这个解决方案在这里:

User.find(:all, :group => [:first, :email], :having => "count(*) > 1" )

但它似乎不适用于postgres.我收到这个错误:

PG :: GroupingError:错误:列"parts.id"必须出现在GROUP BY子句中或用于聚合函数

new*_*ere 196

经过测试和工作的版本

User.select(:first,:email).group(:first,:email).having("count(*) > 1")
Run Code Online (Sandbox Code Playgroud)

此外,这有点无关但很方便.如果你想看看每个组合的发现时间,最后加上.size:

User.select(:first,:email).group(:first,:email).having("count(*) > 1").size
Run Code Online (Sandbox Code Playgroud)

然后你会得到一个如下所示的结果集:

{[nil, nil]=>512,
 ["Joe", "test@test.com"]=>23,
 ["Jim", "email2@gmail.com"]=>36,
 ["John", "email3@gmail.com"]=>21}
Run Code Online (Sandbox Code Playgroud)

认为这很酷,以前没见过.

感谢Taryn,这只是她答案的调整版本.

  • 我必须将一个explict数组传递给`select()`,如:`User.select([:first,:email]).group(:first,:email).having("count(*)> 1") .count`为了工作. (7认同)
  • 使用`.size`而不是`.count` (4认同)
  • 添加`.count`给出`PG :: UndefinedFunction:ERROR:function count` (3认同)
  • 我正在尝试相同的方法,但尝试获取User.id,将其添加到select和group返回一个空数组.如何返回整个用户模型,或者至少包含:id? (3认同)
  • 你可以试试 User.select([:first,:email]).group(:first,:email).have("count(*) > 1").map.count (2认同)

Tar*_*ast 30

发生该错误是因为POSTGRES要求您在SELECT子句中放置分组列.

尝试:

User.select(:first,:email).group(:first,:email).having("count(*) > 1").all
Run Code Online (Sandbox Code Playgroud)

(注意:未经测试,您可能需要调整它)

已编辑以删除id列

  • 那不行; `id`列不是该组的一部分,所以你不能引用它,除非你聚合它(例如`array_agg(id)`或`json_agg(id)`) (7认同)

Ben*_*bin 7

如果您需要完整型号,请尝试以下(基于@ newUserNameHere的答案).

User.where(email: User.select(:email).group(:email).having("count(*) > 1").select(:email))
Run Code Online (Sandbox Code Playgroud)

这将返回行的电子邮件地址不唯一的行.

我不知道在多个属性上执行此操作的方法.


its*_*lay 5

如果您使用PostgreSQL ,则使用单个查询获取所有重复项:

def duplicated_users
  duplicated_ids = User
    .group(:first, :email)
    .having("COUNT(*) > 1")
    .select('unnest((array_agg("id"))[2:])')

  User.where(id: duplicated_ids)
end

irb> duplicated_users
Run Code Online (Sandbox Code Playgroud)