Frågan kan fungera så här:
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;
Först , hämta det "senaste" value
för name = 'score'
per artikel i underfrågan m
. Mer förklaring till den använda tekniken i detta relaterade svar:
Du verkar dock falla offer för en mycket grundläggande missuppfattning:
Det finns ingen "naturlig ordning" i ett bord. I en SELECT
, du måste ORDER BY
väl definierade kriterier. För denna fråga antar jag kolumnen metrics.date_created
. Om du inte har något sådant har du ingen möjlighet för att definiera "senaste" och tvingas falla tillbaka till ett godtyckligt val från flera kvalificerande rader:
ORDER BY article_id
Detta är inte pålitlig. Postgres väljer en rad som den väljer. Kan ändras med uppdateringar av tabellen eller ändringar i frågeplanen.
Nästa , LEFT JOIN
till tabellen article
och ORDER BY value
. NULL
sorterar sist, så artiklar utan kvalificerat värde hamnar sist.
Obs:vissa inte så smarta ORM:er (och jag är rädd att Ruby's ActiveRecord är en av dem) använder det icke-beskrivande och icke-särskiljande id
som namn på primärnyckeln. Du måste anpassa dig till dina faktiska kolumnnamn, som du inte angav.
Prestanda
Borde vara anständigt. Detta är en "enkel" fråga vad Postgres beträffar. Ett partiellt flerkolumnindex på metrics
i tabellen skulle göra det snabbare:
CREATE INDEX metrics_some_name_idx ON metrics(article_id, date_created)
WHERE name = 'score';
Kolumner i denna ordning. I PostgreSQL 9.2+ kan du lägga till kolumnvärdet för att göra index-genomsökningar möjliga:
CREATE INDEX metrics_some_name_idx ON metrics(article_id, date_created, value)
WHERE name = 'score';