PostgreSQL
 sql >> Datenbank >  >> RDS >> PostgreSQL

Doppelte Datensätze zurückgeben (ActiveRecord, Postgres)

Ein SQL-y-Weg

Lassen Sie uns das Problem zuerst einfach in SQL lösen, damit uns die Rails-spezifische Syntax nicht austrickst.

Diese SO-Frage ist eine ziemlich klare Parallele:Duplikate finden Werte in einer SQL-Tabelle

Die Antwort von KM (Zweiter von oben, im Moment nicht angekreuzt) erfüllt Ihre Kriterien für die Rückgabe aller duplizierten Datensätze zusammen mit ihren IDs. Ich habe KMs modifiziert SQL, um Ihrem zu entsprechen Tabelle...

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

Der Teil innerhalb des INNER JOIN ( ) ist im Wesentlichen das, was Sie bereits generiert haben. Eine gruppierte Tabelle mit duplizierten Titeln und Anzahlen. Der Trick ist JOIN es zu den unveränderten movies hinzufügen Tabelle, die alle Filme ausschließt, die keine Übereinstimmungen in der Abfrage von Duplikaten haben.

Warum ist das in Rails so schwer zu generieren? Der schwierigste Teil ist das, weil wir JOIN sind movies ansehen zu movies , müssen wir Tabellenaliase erstellen (m und dupes in meiner Abfrage oben).

Leider bietet it Rails keine sauberen Möglichkeiten, diese Aliase zu deklarieren. Einige Referenzen:

Glücklicherweise können wir, da wir das SQL in der Hand haben, .find_by_sql verwenden Methode...

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")

Weil wir Movie.find_by_sql aufrufen , geht ActiveRecord davon aus, dass unser handgeschriebenes SQL in Movie gebündelt werden kann Objekte. Es massiert oder generiert nichts, wodurch wir unsere Aliase verwenden können.

Dieser Ansatz hat seine Mängel. Es gibt ein Array und keine ActiveRecord-Beziehung zurück, was bedeutet, dass es nicht mit anderen Bereichen verkettet werden kann. Und in der Dokumentation für find_by_sql Methode , bekommen wir zusätzliche Entmutigung...

A Rails-y Way

Wirklich, was macht das SQL oben? Es wird eine Liste mit Namen erstellt, die mehr als einmal vorkommen. Dann wird diese Liste mit der ursprünglichen Tabelle abgeglichen. Also machen wir das einfach mit Rails.

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

Movie.where(title: titles_with_multiple)

Wir nennen .keys weil die erste Abfrage einen Hash zurückgibt. Die Schlüssel sind unsere Titel. Das where() -Methode kann ein Array annehmen, und wir haben ihr ein Array von Titeln übergeben. Gewinner.

Man könnte argumentieren, dass eine Linie von Ruby eleganter ist als zwei. Und wenn diese eine Ruby-Zeile einen gottlosen SQL-String enthält, wie elegant ist das dann wirklich?

Hoffe, das hilft!