2013-02-21 4 views
2

나는 Transaction (account_id, dateamount)과 중복되는 테이블 (transactions)을 가지고 있습니다.AREL에서 테이블을 자체에 연결하여 중복 된 항목을 찾는 방법은 무엇입니까?

내 영어 기능 요구 사항은 "동일한 account_id, 날짜 및 금액을 가진 둘 이상의 트랜잭션이있는 모든 트랜잭션을보고 싶습니다."입니다. 나는 레일 3.2.x와 포스트 그레스를 사용하고

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 

: AREL에 포기

일시적으로, 나는 SQL에서이 같은 생산.

원래, 나는 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를 원합니다. 요점은 중복을 확인하는 데 ID가 무시되기를 바랍니다.

누구든지 AREL의 올바른 방향으로 나를 가리킬 수 있으면 감사하겠습니다. find_by_sql은 레코드가 필요할 때 유용하지만 ActiveAdmin 범위를 만들려고합니다. 배열을 좋아하지 않습니다.

+0

나는 downvotes 상관 없어,하지만 난이을 downvoted 된 이유에 댓글 없음에 마음 downvotes을합니까? – makdad

+1

아마 그 프로필 사진 : P – pchap10k

답변

1

당신은 다음처럼 액티브 트랜잭션 모델에서 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 

그러나 다음 아이디의이 참여

가 .. 아마 당신이 원하지 않는 것을. 최소한

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

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

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를 반환합니다.하지만이 웹 사이트에 나를 올려 놓았지만 유감스럽게도 제공 한 쿼리는 Postgres가 아닌 MySQL에서 작동합니다. 나는 Heroku에있다. .. – makdad

+0

@makdad는 Postgres에 익숙하지 않지만 Heroku Postgres가 9.0 이상이면 ['string_agg'] (http://www.postgresql.org/docs/9.0)를 사용할 수있다. /static/functions-aggregate.html). – maxenglander