Во-первых, давайте просто решить эту проблему в SQL, так что Rails-специфический синтаксис Безразлично Не обманывай нас.
Ответ от КМ (второй сверху, не отмеченных на данный момент) соответствует вашим критериям возвращения всех дублирующих записей вместе с их идентификаторами. Я изменил 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 не предоставляет никаких чистых способов объявления этих псевдонимов. Некоторые ссылки:
К счастью, так как мы получили 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 Relation, что означает, что он не может быть привязан к другим областям. И, in the documentation for the find_by_sql
method, мы получаем дополнительное уныние ...
This should be a last resort because using, for example, MySQL specific terms will lock you to using that particular database engine or require you to change your call if you switch engines.
А Rails-й путь
Действительно, что это SQL делать выше? Он получает список имен, которые появляются более одного раза. Затем он сопоставляет этот список с исходной таблицей. Итак, давайте просто сделаем это с помощью Rails.
titles_with_multiple = Movie.group(:title).having("count(title) > 1").count.keys
Movie.where(title: titles_with_multiple)
Мы называем .keys
, поскольку первый запрос возвращает хэш. Ключи - наши названия. Метод where()
может принимать массив, и мы передали ему массив названий. Победитель.
Вы можете утверждать, что одна строка Ruby более элегантна, чем две. И если эта строка Ruby содержит в себе нечестивую строку SQL, насколько она элегантна?
Надеюсь, это поможет!
Удивительный ответ, суперинформативный! Очень крутой трюк с массивом в .where(), я бы сделал неуклюжий каждый цикл. – Ashbury
Рад, что я мог бы помочь! :) –