sql >> Database >  >> RDS >> PostgreSQL

Bestelling met een has_many relatie

De zoekopdracht zou als volgt kunnen werken:

SELECT a.*
FROM   article a
LEFT   JOIN (
   SELECT DISTINCT ON (article_id)
          article_id, value
   FROM   metrics m
   WHERE  name = 'score'
   ORDER  BY article_id, date_created DESC
   ) m ON m.metrics_id = a.metrics_id
ORDER  BY m.value DESC;

Eerste , haal de "meest recente" value op voor name = 'score' per artikel in de subquery m . Meer uitleg voor de gebruikte techniek in dit gerelateerde antwoord:

Je lijkt echter het slachtoffer te worden van een zeer fundamentele misvatting:

Er is geen "natuurlijke volgorde" in een tafel. In een SELECT , moet u ORDER BY goed gedefinieerde criteria. Voor deze query ga ik uit van een kolom metrics.date_created . Als je niets van dien aard hebt, heb je geen enkele manier om "meest recent" te definiëren en gedwongen zijn terug te vallen op een willekeurige keuze uit meerdere kwalificerende rijen:

   ORDER  BY article_id

Dit is niet betrouwbaar. Postgres kiest een rij naar keuze. Kan veranderen bij elke update van de tabel of elke wijziging in het queryplan.

Volgende , LEFT JOIN naar de tabel article en ORDER BY value . NULL sorteert als laatste, dus artikelen zonder kwalificerende waarde gaan als laatste.

Opmerking:sommige niet-zo-slimme ORM's (en ik ben bang dat Ruby's ActiveRecord er een van is) gebruiken de niet-beschrijvende en niet-onderscheidende id als naam voor de primaire sleutel. U moet zich aanpassen aan uw werkelijke kolomnamen, die u niet heeft opgegeven.

Prestaties

Moet fatsoenlijk zijn. Dit is een "eenvoudige" vraag wat Postgres betreft. Een gedeeltelijke index met meerdere kolommen op tabel metrics zou het sneller maken:

CREATE INDEX metrics_some_name_idx ON metrics(article_id, date_created)
WHERE name = 'score';

Kolommen in deze volgorde. In PostgreSQL 9.2+ zou je de kolomwaarde kunnen toevoegen om alleen-index scans mogelijk te maken:

CREATE INDEX metrics_some_name_idx ON metrics(article_id, date_created, value)
WHERE name = 'score';



  1. TSQL:Hoe kan ik lokale tijd naar UTC converteren? (SQL-server 2008)

  2. NOT IN in postgresql werkt niet

  3. DPI-1047:64-bit Oracle Client-bibliotheek kan niet worden geladen

  4. mySQL:Levenshtein-afstand gebruiken om duplicaten in 20.000 rijen te vinden