2

重複を含む可能性のあるテーブルがtransactionsあります(私たちにとって、重複とは、、、およびがTransaction同じです)。account_iddateamount

私の英語の機能要件は、「同じaccount_id、日付、および金額で複数のトランザクションが存在するすべてのトランザクションを表示したい」です。

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

Rails3.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

..これはイライラします。groupby句のIDが必要ないためです。要点は、重複をチェックするときにIDを無視することです。

誰かが私をARELの正しい方向に向けることができれば、私はこれをスコープにする必要があります-find_by_sqlレコードが必要な場合は素晴らしいですが、ActiveAdminスコープを作成しようとしています-配列は好きではありません。

4

3 に答える 3

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

どちらの方法も、メモリの面でコストがかかります。幸運を。

于 2013-02-25T14:58:04.333 に答える
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
于 2013-02-25T23:55:51.930 に答える
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

于 2013-02-26T02:15:26.303 に答える