Dotaz by mohl fungovat takto:
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;
Za prvé , načtěte "nejnovější" value
pro name = 'score'
na článek v poddotazu m
. Další vysvětlení použité techniky v této související odpovědi:
Zdá se však, že jste se stali obětí velmi základní mylné představy:
Neexistuje žádný "přirozený řád" v tabulce. V SELECT
, musíte ORDER BY
dobře definovaná kritéria. Pro účely tohoto dotazu předpokládám sloupec metrics.date_created
. Pokud nic takového nemáte, nemůžete definovat „nejnovější“ a jsou nuceni vrátit se k libovolnému výběru z více kvalifikačních řádků:
ORDER BY article_id
Toto není spolehlivý. Postgres si vybere řádek podle svého. Může se změnit s jakoukoli aktualizací tabulky nebo jakoukoli změnou v plánu dotazů.
Další , LEFT JOIN
do tabulky article
a ORDER BY value
. NULL
seřadí jako poslední, takže články bez kvalifikační hodnoty budou poslední.
Poznámka:Některé nepříliš chytré ORM (a obávám se, že Ruby's ActiveRecord je jedním z nich) používají nepopisné a nerozlišující id
jako název primárního klíče. Budete se muset přizpůsobit skutečným názvům sloupců, které jste nezadali.
Výkon
Mělo by být slušné. Toto je "jednoduchý" dotaz, pokud jde o Postgres. Částečný vícesloupcový index v tabulce metrics
by to zrychlilo:
CREATE INDEX metrics_some_name_idx ON metrics(article_id, date_created)
WHERE name = 'score';
Sloupce v tomto pořadí. V PostgreSQL 9.2+ můžete přidat hodnotu sloupce, aby bylo možné skenovat pouze index:
CREATE INDEX metrics_some_name_idx ON metrics(article_id, date_created, value)
WHERE name = 'score';