PostgreSQL
 sql >> Base de données >  >> RDS >> PostgreSQL

Commande avec une relation has_many

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