По SQL-y начин
Първо, нека просто разрешим проблема в SQL, така че специфичният за Rails синтаксис да не ни подведе.
Този SO въпрос е доста ясен паралел:Намиране на дубликат стойности в SQL таблица
Отговорът от KM (втори отгоре, без отметка, в момента) отговаря на вашите критерии за връщане на всички дублирани записи заедно с техните идентификатори. Промених 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
снимане на movies
към movies
, трябва да създадем псевдоними на таблици (m
и dupes
в моята заявка по-горе).
За съжаление, Rails не предоставя чисти начини за деклариране на тези псевдоними. Някои препратки:
- Проблеми с Rails GitHub споменавайки "присъединяване" и "псевдоним". Мизерия.
- SO Въпрос:ActiveRecord заявка с alias'd таблица имена
За щастие, тъй като имаме 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
метод
, получаваме допълнително обезсърчение...
A 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 е по-елегантна от две. И ако този един ред на Ruby има безбожен низ от SQL, вграден в него, колко елегантен е той наистина?
Надявам се това да помогне!