sql >> Databasteknik >  >> RDS >> PostgreSQL

Returnera dubbletter av poster (activerecord, postgres)

Ett SQL-y-sätt

Låt oss först lösa problemet i SQL, så att den Rails-specifika syntaxen inte lurar oss.

Denna SO-fråga är en ganska tydlig parallell:Hittar duplikat värden i en SQL-tabell

Svaret från KM (nästa från toppen, ej bockmarkerat, för tillfället) uppfyller dina kriterier för att returnera alla duplicerade poster tillsammans med deras ID. Jag har ändrat KM:er SQL för att matcha 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 inuti INNER JOIN ( ) är i huvudsak vad du redan har genererat. En grupperad tabell med dubblerade titlar och antal. Tricket är JOIN överföra den till de omodifierade movies tabell, vilket kommer att utesluta alla filmer som inte har matchningar i frågan om duper.

Varför är detta så svårt att skapa i Rails? Det svåraste är det eftersom vi är JOIN ing movies till movies måste vi skapa tabellalias (m och dupes i min fråga ovan).

Tyvärr tillhandahåller it Rails inga rena sätt att deklarera dessa alias. Några referenser:

Lyckligtvis, eftersom vi har SQL i handen, kan vi använda .find_by_sql metod...

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

Eftersom vi kallar Movie.find_by_sql , ActiveRecord antar att vår handskrivna SQL kan buntas in i Movie objekt. Det masserar inte eller genererar något, vilket låter oss göra våra alias.

Detta tillvägagångssätt har sina brister. Den returnerar en array och inte en ActiveRecord Relation, vilket betyder att den inte kan kedjas med andra scopes. Och i dokumentationen för find_by_sql metod , vi blir extra missmodiga...

Ett spårlöst sätt

Verkligen, vad gör SQL ovan? Den får en lista med namn som visas mer än en gång. Sedan matchar den den listan mot den ursprungliga tabellen. Så låt oss bara göra det med Rails.

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

Movie.where(title: titles_with_multiple)

Vi anropar .keys eftersom den första frågan returnerar en hash. Nycklarna är våra titlar. where() Metoden kan ta en array, och vi har gett den en mängd titlar. Vinnare.

Du kan hävda att en linje av Ruby är mer elegant än två. Och om den där ena raden av Ruby har en ogudaktig sträng av SQL inbäddad i sig, hur elegant är den egentligen?

Hoppas detta hjälper!



  1. Codeigniter, mysql, select_max och lägg till 1 innan du infogar en annan post

  2. VÄLJ DISTINKT på en kolumn

  3. excel till oracle db med VS 2005 C#

  4. Dålig prestanda på en PostgreSQL-fråga