Заявката може да работи по следния начин:
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;
Първо , извлича "най-новата" value
за name = 'score'
на статия в подзаявката m
. Повече обяснение за използваната техника в този свързан отговор:
Изглежда обаче ставате жертва на много основно погрешно схващане:
Няма "естествен ред" в таблица. В SELECT
, трябва да ORDER BY
добре дефинирани критерии. За целите на тази заявка приемам колона metrics.date_created
. Ако нямате нищо подобно, нямате няма начин за да дефинирате „най-скорошни“ и са принудени да се върнат към произволен избор от множество квалифициращи редове:
ORDER BY article_id
Това не надежден. Postgres ще избере ред, както реши. Може да се промени с всяка актуализация на таблицата или всяка промяна в плана на заявката.
Следващ , LEFT JOIN
към таблицата article
и ORDER BY value
. NULL
сортира последни, така че статиите без квалифицираща стойност отиват последни.
Забележка:някои не толкова интелигентни ORM (и страхувам се, че ActiveRecord на Ruby е един от тях) използват неописателния и неотличителен id
като име за първичния ключ. Ще трябва да се адаптирате към вашите действителни имена на колони, които не сте предоставили.
Ефективност
Трябва да е приличен. Това е "проста" заявка, що се отнася до Postgres. Частичен многоколонен индекс на metrics
на таблицата би го направило по-бързо:
CREATE INDEX metrics_some_name_idx ON metrics(article_id, date_created)
WHERE name = 'score';
Колони в този ред. В PostgreSQL 9.2+ можете да добавите стойността на колоната, за да направите възможно сканирането само на индекс:
CREATE INDEX metrics_some_name_idx ON metrics(article_id, date_created, value)
WHERE name = 'score';