PostgreSQL
 sql >> Datenbank >  >> RDS >> PostgreSQL

Bestellung mit einer has_many-Beziehung

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