2013-02-21 54 views
2

我有一张表,transactions,可能包含重复项(对于我们来说,副本是Transaction,具有相同的account_id,dateamount)。如何在AREL中加入表格以查找重复项?

我的英语语言功能的要求是:“我希望看到其中有具有相同ACCOUNT_ID,日期和金额存在超过1个交易的所有交易”。

上AREL放弃暂时,我公司生产的SQL是这样的:

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 

我使用Rails的3.2.x中和Postgres。

本来,我在AREL试过这样:

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

但是,这给了我有关集合函数的SQL错误:

PG::Error: ERROR: column "transactions.id" must appear in the GROUP BY clause or be used in an aggregate function 

..这是令人沮丧的,因为我做希望在group by子句中使用ID - 整个问题是我希望在检查dupe时忽略ID。

我很感激,如果有人能指出我正确的方向AREL我需要使这个范围 - find_by_sql是伟大的,当你需要记录,但我想创建一个ActiveAdmin范围 - 它不喜欢数组。

+0

我不介意downvotes,但我介意downvotes没有意见,为什么我downvoted? – makdad 2013-02-21 02:13:15

+1

可能是个人资料照片:P – pchap10k 2013-02-21 02:27:00

回答

1

您可以在ActiveRecord的交易模型定义使用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 

这两种方法是昂贵的,内存明智的。祝你好运。

+0

最终,浸渍下到SQL是最简单的 - 这是政府,而不是经常使用,所以我很好略慢的查询。 – makdad 2013-04-02 02:22:59

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 
+0

这可能会被清除,但它返回一个ActiveRecord :: Relation – BM5k 2013-02-25 23:57:24

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

+0

Upvote将我放到这个网站上,但不幸的是,你提供的查询在MySQL上而不是在Postgres上。我在Heroku上,所以.. – makdad 2013-02-27 03:24:16

+0

@makdad不太熟悉Postgres,但是如果你的Heroku Postgres是9.0或更高版本,你可以使用['string_agg'](http://www.postgresql.org/docs/9.0) /static/functions-aggregate.html)。 – maxenglander 2013-02-27 05:48:57