PostgreSQL
 sql >> Database >  >> RDS >> PostgreSQL

Restituire record duplicati (activerecord, postgres)

Un modo SQL-y

Innanzitutto, risolviamo il problema in SQL, in modo che la sintassi specifica di Rails non ci inganni.

Questa domanda SO è un parallelo abbastanza chiaro:Trovare duplicati valori in una tabella SQL

La risposta di KM (seconda dall'alto, non contrassegnata, al momento) soddisfa i tuoi criteri di restituzione di tutti i record duplicati insieme ai loro ID. Ho modificato KM SQL in modo che corrisponda a tuo tavola...

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 di INNER JOIN ( ) è essenzialmente ciò che hai già generato. Una tabella raggruppata di titoli e conteggi duplicati. Il trucco è JOIN inviandolo ai movies non modificati tabella, che escluderà tutti i film che non hanno corrispondenze nella query dei duplicati.

Perché è così difficile da generare in Rails? La parte più complicata è che, perché siamo JOIN in movies a movies , dobbiamo creare alias di tabella (m e dupes nella mia domanda sopra).

Purtroppo, it Rails non fornisce alcun modo pulito per dichiarare questi alias. Alcuni riferimenti:

Fortunatamente, dato che abbiamo l'SQL in mano, possiamo usare .find_by_sql metodo...

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 presuppone che il nostro SQL scritto a mano possa essere raggruppato in Movie oggetti. Non massaggia né genera nulla, il che ci consente di fare i nostri alias.

Questo approccio ha i suoi difetti. Restituisce una matrice e non una relazione ActiveRecord, il che significa che non può essere concatenato con altri ambiti. E, nella documentazione per find_by_sql metodo , otteniamo ulteriore scoraggiamento...

Un modo Rails-y

Davvero, cosa sta facendo l'SQL sopra? Sta ottenendo un elenco di nomi che appaiono più di una volta. Quindi, sta abbinando quell'elenco alla tabella originale. Quindi, facciamolo usando Rails.

titles_with_multiple = Movie.group(:title).having("count(title) > 1").count.keys

Movie.where(title: titles_with_multiple)

Chiamiamo .keys perché la prima query restituisce un hash. Le chiavi sono i nostri titoli. Il where() il metodo può richiedere un array e gli abbiamo consegnato un array di titoli. Vincitore.

Si potrebbe obiettare che una riga di Ruby è più elegante di due. E se quell'unica riga di Ruby ha una stringa empia di SQL incorporata, quanto è davvero elegante?

Spero che questo aiuti!