SQLのような方法
まず、Rails固有の構文が私たちをだまさないように、SQLの問題を解決しましょう。
このSOの質問は、かなり明確な類似点です。重複を見つけるSQLテーブルの値
KMからの回答(上から2番目、現時点ではチェックマークなし)は、重複するすべてのレコードをIDとともに返すという基準を満たしています。 KMを変更しました あなたのに一致するSQL テーブル...
SELECT
m.id, m.title
FROM
movies m
INNER JOIN (
SELECT
title, COUNT(*) AS CountOf
FROM
movies
GROUP BY
title
HAVING COUNT(*)>1
) dupes
ON
m.title=dupes.title
INNER JOIN ( )
内の部分 基本的には、すでに生成したものです。重複したタイトルとカウントのグループ化されたテーブル。秘訣はJOIN
です 変更されていないmovies
にそれを追加する テーブル。重複のクエリで一致するものがない映画はすべて除外されます。
Railsでこれを生成するのが難しいのはなぜですか?最も難しいのは、JOIN
だからです。 ing movies
movies
へ 、テーブルエイリアス(m
)を作成する必要があります およびdupes
上記の私のクエリで)。
残念ながら、Railsはこれらのエイリアスを宣言するためのクリーンな方法を提供していません。いくつかの参考文献:
- RailsGitHubの問題 「参加」と「エイリアス」に言及します。惨めさ。
- SO質問:エイリアステーブルを使用したActiveRecordクエリ名前
幸い、SQLが手元にあるので、.find_by_sql
を使用できます。 メソッド...
Movie.find_by_sql("SELECT m.id, m.title FROM movies m INNER JOIN (SELECT title, COUNT(*) FROM movies GROUP BY title HAVING COUNT(*)>1) dupes ON m.first=.first")
Movie.find_by_sql
を呼び出しているため 、ActiveRecordは、手書きのSQLをMovie
にバンドルできることを前提としています。 オブジェクト。マッサージも生成もしないため、エイリアスを作成できます。
このアプローチには欠点があります。 ActiveRecordリレーションではなく配列を返します。つまり、他のスコープとチェーンすることはできません。また、find_by_sql
のドキュメントにある
Rails-y Way
本当に、SQLは上記で何をしているのですか?複数回表示される名前のリストを取得しています。次に、そのリストを元のテーブルと照合します。それでは、Railsを使用してそれを実行しましょう。
titles_with_multiple = Movie.group(:title).having("count(title) > 1").count.keys
Movie.where(title: titles_with_multiple)
.keys
と呼びます 最初のクエリがハッシュを返すためです。キーは私たちのタイトルです。 where()
メソッドは配列を取ることができ、タイトルの配列を渡しました。勝者。
Rubyの1行は2行よりもエレガントであると言えるでしょう。そして、Rubyのその1行にSQLの不敬虔な文字列が埋め込まれている場合、それは本当にどれほどエレガントですか?
これがお役に立てば幸いです!