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';