In primo luogo, facciamo solo risolvere il problema in SQL, in modo che la sintassi delle guide specifico doesn ci ingannano.
La risposta da KM (secondo dall'alto, non spuntate, al momento) corrisponde ai tuoi criteri di tornare tutti i record duplicati con i loro ID. Ho modificato SQL di KM per abbinare vostro tavolo ...
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
La parte all'interno del INNER JOIN ()
è essenzialmente quello che hai generato già. Una tabella raggruppata di titoli e conteggi duplicati. Il trucco è JOIN
nella tabella movies
non modificata, che escluderà tutti i film che non hanno corrispondenze nella query dei duplicati.
Perché è così difficile da generare in Rails? La parte più difficile è che, dal momento che siamo JOIN
ing movies
a movies
, dobbiamo creare alias di tabella (m
e dupes
nella mia query sopra).
Purtroppo, Rails non fornisce alcun metodo pulito per dichiarare questi alias. Alcuni riferimenti:
Per fortuna, dal momento che abbiamo la SQL nella mano, possiamo utilizzare il metodo .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")
perché stiamo chiamando Movie.find_by_sql
, ActiveRecord presume che il nostro SQL scritto a mano possa essere raggruppato negli oggetti Movie
. Non massaggia o genera nulla, che ci permette di fare i nostri pseudonimi.
Questo approccio ha i suoi difetti. Restituisce un array e non un rapporto ActiveRecord, il che significa che non può essere incatenato con altri ambiti. E, in the documentation for the find_by_sql
method, otteniamo ulteriore scoraggiamento ...Way
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.
A Rails-y
realtà, ciò che sta facendo l'SQL di cui sopra? Sta ottenendo una lista di nomi che appaiono più di una volta. Quindi, confronta quella lista con la tabella originale. Quindi, facciamolo usando Rails.
titles_with_multiple = Movie.group(:title).having("count(title) > 1").count.keys
Movie.where(title: titles_with_multiple)
Noi chiamiamo .keys
perché la prima query restituisce un hash. Le chiavi sono i nostri titoli. Il metodo where()
può prendere un array e gli abbiamo consegnato una serie di titoli. Vincitore.
Si potrebbe obiettare che una riga di Ruby è più elegante di due. E se quella riga di Ruby ha una stringa empia di SQL incorporata al suo interno, quanto è elegante in realtà?
Spero che questo aiuti!
Una risposta sorprendente, super informativa! Un trucco molto interessante con array in .where(), avrei fatto un grosso giro ogni ciclo. – Ashbury
Contento di poterti aiutare! :) –