Zapytanie może działać tak:
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;
Pierwszy , pobierz „najnowszą” value
dla name = 'score'
na artykuł w podzapytaniu m
. Więcej wyjaśnień dotyczących zastosowanej techniki w tej powiązanej odpowiedzi:
Wydaje się jednak, że padasz ofiarą bardzo podstawowego nieporozumienia:
Nie ma nie ma „naturalnego porządku” w tabeli. W SELECT
, musisz ORDER BY
dobrze zdefiniowane kryteria. Na potrzeby tego zapytania zakładam kolumnę metrics.date_created
. Jeśli nie masz nic takiego, nie masz mowy aby zdefiniować "najnowsze" i są zmuszeni powrócić do arbitralnego wyboru z wielu kwalifikujących się wierszy:
ORDER BY article_id
To nie wiarygodny. Postgres wybierze wiersz według własnego uznania. Może ulec zmianie wraz z każdą aktualizacją tabeli lub zmianą planu zapytań.
Dalej , LEFT JOIN
do tabeli article
i ORDER BY value
. NULL
sortuje na końcu, więc artykuły bez kwalifikującej się wartości idą na końcu.
Uwaga:niektóre niezbyt inteligentne ORM (a obawiam się, że ActiveRecord Ruby jest jednym z nich) używają nieopisowego i nierozróżnialnego id
jako nazwa klucza podstawowego. Musisz dostosować się do rzeczywistych nazw kolumn, których nie podałeś.
Wydajność
Powinno być przyzwoite. To "proste" zapytanie, jeśli chodzi o Postgres. Częściowy indeks wielokolumnowy w tabeli metrics
przyspieszyłoby to:
CREATE INDEX metrics_some_name_idx ON metrics(article_id, date_created)
WHERE name = 'score';
Kolumny w tej kolejności. W PostgreSQL 9.2+ możesz dodać wartość kolumny, aby umożliwić skanowanie tylko z indeksem:
CREATE INDEX metrics_some_name_idx ON metrics(article_id, date_created, value)
WHERE name = 'score';