2013-02-21 25 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