A consulta poderia funcionar assim:
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;
Primeiro , recupere o
value
"mais recente" para name = 'score'
por artigo na subconsulta m
. Mais explicações para a técnica usada nesta resposta relacionada:Você parece ser vítima de um equívoco muito básico:
Não existe nenhuma "ordem natural" em uma mesa. Em um
SELECT
, você precisa ORDER BY
critérios bem definidos. Para o propósito desta consulta, estou assumindo uma coluna metrics.date_created
. Se você não tem nada do tipo, você não tem como para definir "mais recente" e são forçados a recorrer a uma escolha arbitrária de várias linhas de qualificação: ORDER BY article_id
Isso não confiável. O Postgres escolherá uma linha conforme escolher. Pode mudar com qualquer atualização na tabela ou qualquer alteração no plano de consulta.
Próximo ,
LEFT JOIN
para a tabela article
e ORDER BY value
. NULL
classifica por último, então os artigos sem valor qualificável vão por último. Nota:alguns ORMs não tão inteligentes (e temo que o ActiveRecord do Ruby seja um deles) usam o
id
não descritivo e não distintivo como nome para a chave primária. Você terá que se adaptar aos seus nomes de coluna reais, que você não forneceu. Desempenho
Deve ser decente. Esta é uma consulta "simples" no que diz respeito ao Postgres. Um índice parcial de várias colunas na tabela
metrics
tornaria mais rápido:CREATE INDEX metrics_some_name_idx ON metrics(article_id, date_created)
WHERE name = 'score';
Colunas nesta ordem. No PostgreSQL 9.2+, você pode adicionar o valor da coluna para possibilitar varreduras somente de índice:
CREATE INDEX metrics_some_name_idx ON metrics(article_id, date_created, value)
WHERE name = 'score';