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

Returner duplikerede poster (activerecord, postgres)

En SQL-y måde

Først, lad os lige løse problemet i SQL, så den Rails-specifikke syntaks ikke narre os.

Dette SO-spørgsmål er en ret klar parallel:Find duplikat værdier i en SQL-tabel

Svaret fra KM (anden fra toppen, ikke markeret, i øjeblikket) opfylder dine kriterier for at returnere alle duplikerede poster sammen med deres ID'er. Jeg har ændret KM'er SQL, der matcher din bord...

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

Delen inde i INNER JOIN ( ) er i bund og grund det, du allerede har genereret. En grupperet tabel med duplikerede titler og tæller. Tricket er JOIN ing det til de umodificerede movies tabel, som vil udelukke alle film, der ikke har matches i forespørgslen om duper.

Hvorfor er det så svært at generere i Rails? Den sværeste del er det, fordi vi er JOIN ved at bruge movies til movies , skal vi oprette tabelaliasser (m og dupes i min forespørgsel ovenfor).

Desværre giver it Rails ikke nogen rene måder at erklære disse aliaser på. Nogle referencer:

Heldigvis, da vi har SQL i hånden, kan vi bruge .find_by_sql metode...

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

Fordi vi kalder Movie.find_by_sql , ActiveRecord antager, at vores håndskrevne SQL kan samles i Movie genstande. Det masserer eller genererer ikke noget, hvilket lader os lave vores aliaser.

Denne tilgang har sine mangler. Det returnerer et array og ikke en ActiveRecord Relation, hvilket betyder, at det ikke kan kædes sammen med andre scopes. Og i dokumentationen til find_by_sql metode , får vi ekstra modløshed...

En skinnende vej

Virkelig, hvad laver SQL'en ovenfor? Den får en liste over navne, der vises mere end én gang. Så matcher den denne liste mod den originale tabel. Så lad os bare gøre det ved at bruge Rails.

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

Movie.where(title: titles_with_multiple)

Vi kalder .keys fordi den første forespørgsel returnerer en hash. Nøglerne er vores titler. where() metode kan tage en række, og vi har givet den en række titler. Vinder.

Du kan argumentere for, at en linje af Ruby er mere elegant end to. Og hvis den ene linje af Ruby har en ugudelig streng af SQL indlejret i sig, hvor elegant er den så egentlig?

Håber dette hjælper!



  1. Den nemmeste måde at konvertere en Blob til en byte-array

  2. Opdel kommasepareret streng og indsæt til en tabel (int)

  3. Opret tabel i procedure

  4. Oprettelse af en kold standby for PostgreSQL ved hjælp af Amazon AWS