La consulta podría funcionar así:
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;
Primero , recupera el value
"más reciente" para name = 'score'
por artículo en la subconsulta m
. Más explicación de la técnica utilizada en esta respuesta relacionada:
Sin embargo, pareces ser víctima de un concepto erróneo muy básico:
No hay ningún "orden natural" en una mesa En un SELECT
, necesitas ORDER BY
criterios bien definidos. Para el propósito de esta consulta, asumo una columna metrics.date_created
. Si no tienes nada por el estilo, no tienes de ninguna manera para definir "más reciente" y se ven obligados a recurrir a una selección arbitraria de varias filas de calificación:
ORDER BY article_id
Esto es no de confianza. Postgres elegirá una fila como elija. Puede cambiar con cualquier actualización de la tabla o cualquier cambio en el plan de consulta.
Siguiente , LEFT JOIN
a la tabla article
y ORDER BY value
. NULL
se clasifica en último lugar, por lo que los artículos sin valor de calificación van en último lugar.
Nota:algunos ORM no tan inteligentes (y me temo que ActiveRecord de Ruby es uno de ellos) utilizan el id
no descriptivo ni distintivo. como nombre para la clave principal. Tendrá que adaptarse a los nombres de las columnas reales, que no proporcionó.
Rendimiento
Debería ser decente. Esta es una consulta "simple" en lo que respecta a Postgres. Un índice parcial de varias columnas en la tabla metrics
lo haría más rápido:
CREATE INDEX metrics_some_name_idx ON metrics(article_id, date_created)
WHERE name = 'score';
Columnas en este orden. En PostgreSQL 9.2+, puede agregar el valor de la columna para hacer posibles los escaneos de solo índice:
CREATE INDEX metrics_some_name_idx ON metrics(article_id, date_created, value)
WHERE name = 'score';