如何在AREL中将表连接到自身以查找重复项?

时间:2013-02-21 02:05:25

标签: ruby-on-rails-3 postgresql activeadmin arel

我有一个表transactions,可能包含重复项(对我们来说,副本是Transaction,具有相同的account_iddate和{{1 }})。

我的英语功能要求是“我希望看到所有交易中存在多个具有相同account_id,日期和金额的交易”。

暂时放弃AREL,我在SQL中制作了类似的东西:

amount

我正在使用Rails 3.2.x和Postgres。

最初,我在AREL尝试了这个:

SELECT * FROM transactions t1, transactions t2 WHERE t1.id != t2.id AND t1.date = t2.date AND t1.amount = t2.amount AND t1.account_id = t2.account_id

但是这给了我关于聚合函数的SQL错误:

Transaction.group(:account_id, :date, :amount).having("count(id) > 1")

..这令人沮丧,因为我想要group by子句中的ID - 整点是我希望在检查dupes时忽略ID。

我很感激,如果有人能指出我正确的AREL方向,我需要将其作为范围 - PG::Error: ERROR: column "transactions.id" must appear in the GROUP BY clause or be used in an aggregate function 在您需要记录时非常好,但我正在尝试创建一个ActiveAdmin范围 - 它不喜欢数组。

3 个答案:

答案 0 :(得分:1)

您可以在ActiveRecord Transaction模型中使用sql定义范围,如下所示:

scope :duplicate_transactions, where(<<-eosql.strip)
  transactions.id IN (
      SELECT 
          t1.id 
      FROM 
          transactions t1, transactions t2
      WHERE 
          t1.id != t2.id AND
          t1.date = t2.date AND
          t1.amount = t2.amount AND
          t1.account_id = t2.account_id
  )
eosql

但是后来的ID被涉及..可能不是你想要的,因为这是一个昂贵的查询。至少在

上创建一个非唯一索引
date, amount, account_id

这张桌子。这应该可以节省一些全表行扫描 ...另一种方法是做一些类似的事情

Transaction.joins(<<eosql.strip)
  LEFT OUTER JOIN transactions t ON 
      transactions.id         != t.id AND
      transactions.date        = t.date AND
      transactions.amount      = t.amount
eosql

两种方式都很昂贵,记忆力很强。祝你好运。

答案 1 :(得分:1)

也许像

def similar
  table = self.class.arel_table
  conditions = %w[ date amount ].map { |field| table[field].eq send(field) }.map &:to_sql
  self.class.where "id != #{ id } AND #{ conditions.join ' AND ' }"
end

答案 2 :(得分:1)

如果您愿意将结果以多行的形式返回给您,您可以尝试以下方式:

select account_id, amount, day, group_concat(id) 
  from purchases 
 group by account_id, amount, day having count(id) > 1;

这将返回一个结果集,其中每行包含给定帐户,日期和金额的重复项。

http://sqlfiddle.com/#!2/86e43/17