Die Abfrage könnte folgendermaßen funktionieren:
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;
Zuerst , rufen Sie den "neuesten" value
ab für name = 'score'
pro Artikel in der Unterabfrage m
. Weitere Erklärungen für die verwendete Technik in dieser verwandten Antwort:
Sie scheinen jedoch einem sehr grundlegenden Missverständnis zum Opfer gefallen zu sein:
Es gibt keine „natürliche Ordnung“ in einer Tabelle. In einem SELECT
, müssen Sie ORDER BY
angeben gut definierte Kriterien. Für diese Abfrage gehe ich von einer Spalte metrics.date_created
aus . Wenn Sie nichts dergleichen haben, haben Sie keine Möglichkeit um "neueste" zu definieren und sind gezwungen, auf eine willkürliche Auswahl aus mehreren qualifizierenden Zeilen zurückzugreifen:
ORDER BY article_id
Das ist nicht zuverlässig. Postgres wählt eine Zeile nach Belieben aus. Kann sich mit jeder Aktualisierung der Tabelle oder jeder Änderung des Abfrageplans ändern.
Weiter , LEFT JOIN
zur Tabelle article
und ORDER BY value
. NULL
wird zuletzt sortiert, sodass Artikel ohne qualifizierenden Wert zuletzt landen.
Hinweis:Einige nicht so schlaue ORMs (und ich fürchte, ActiveRecord von Ruby ist einer davon) verwenden die nicht beschreibende und nicht eindeutige id
als Name für den Primärschlüssel. Sie müssen sich an Ihre tatsächlichen Spaltennamen anpassen, die Sie nicht angegeben haben.
Leistung
Sollte anständig sein. Für Postgres ist dies eine "einfache" Abfrage. Ein partieller mehrspaltiger Index für die Tabelle metrics
würde es schneller machen:
CREATE INDEX metrics_some_name_idx ON metrics(article_id, date_created)
WHERE name = 'score';
Spalten in dieser Reihenfolge. In PostgreSQL 9.2+ könnten Sie den Spaltenwert hinzufügen, um Nur-Index-Scans zu ermöglichen:
CREATE INDEX metrics_some_name_idx ON metrics(article_id, date_created, value)
WHERE name = 'score';