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