La requête pourrait fonctionner comme ceci :
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;
Premier , récupère la value
"la plus récente" pour name = 'score'
par article dans la sous-requête m
. Plus d'explications sur la technique utilisée dans cette réponse connexe :
Vous semblez cependant être victime d'une idée fausse très basique :
Il n'y a pas d'"ordre naturel" dans un tableau. Dans un SELECT
, vous devez ORDER BY
critères bien définis. Aux fins de cette requête, je suppose une colonne metrics.date_created
. Si vous n'avez rien de tel, vous n'avez aucun moyen pour définir "le plus récent" et sont obligés de se rabattre sur un choix arbitraire parmi plusieurs lignes de qualification :
ORDER BY article_id
Ce n'est pas fiable. Postgres choisira une ligne au fur et à mesure. Peut changer avec toute mise à jour de la table ou toute modification du plan de requête.
Suivant , LEFT JOIN
au tableau article
et ORDER BY value
. NULL
trie en dernier, donc les articles sans valeur qualificative passent en dernier.
Remarque :certains ORM pas si intelligents (et j'ai bien peur que l'ActiveRecord de Ruby en fasse partie) utilisent l'identifiant id
non descriptif et non distinctif comme nom pour la clé primaire. Vous devrez vous adapter à vos noms de colonnes réels, que vous n'avez pas fournis.
Performances
Devrait être décent. Il s'agit d'une requête "simple" en ce qui concerne Postgres. Un index multicolonne partiel sur la table metrics
le rendrait plus rapide :
CREATE INDEX metrics_some_name_idx ON metrics(article_id, date_created)
WHERE name = 'score';
Colonnes dans cet ordre. Dans PostgreSQL 9.2+, vous pouvez ajouter la valeur de la colonne pour rendre possibles les analyses d'index uniquement :
CREATE INDEX metrics_some_name_idx ON metrics(article_id, date_created, value)
WHERE name = 'score';