Агрегатная функция для соответствующей строки - PullRequest
0 голосов
/ 06 ноября 2018

У меня есть следующая таблица с объединенным первичным ключом id и ts для реализации историзации:

create table "author" (
  "id"     bigint     not null,
  "ts"     timestamp  not null default now(),
  "login"  text       unique not null,
  primary key ("id", "ts")
);

Теперь меня интересует только последнее значение login. Для этого я группирую по id:

select "id", max("ts"), "login" from "author" group by "id";

Но это выдает ошибку: login должен использоваться в статистической функции.

id и max("ts") однозначно идентифицируют строку, потому что набор (id, ts) является первичным ключом. Мне нужен login, который соответствует строке, обозначенной id и max("ts").

Я могу написать дополнительный выбор, чтобы найти login:

select ao."id", max(ao."ts"), 
       (select ai.login from "author" ai
        where ao."id" = ai."id" and max(ao."ts") = ai.ts)
from "author" ao
group by "id";

Это работает, но это довольно шумно и не очень умно, потому что он ищет всю таблицу, хотя поиск группы будет достаточно.

Существует ли агрегатная функция, которая позволяет избежать выбора и дает мне оставшиеся login, которые принадлежат id и max("ts")?

1 Ответ

0 голосов
/ 06 ноября 2018

Вы должны определить правильный ключ, чтобы получить значение, которое вам нравится из таблицы.

Правильный ключ:

 select "id", max("ts") from "author" group by "id";

И используя это, чтобы получить желаемый логин:

 select a1."id", a1.ts, a1.login
 from "author" a1
      inner join (select "id", max("ts") maxts, "login" from "author" group by "id") a2
      ON a1.id = a2.id AND a1.ts = a2.maxts;

В качестве альтернативы, используя оконные функции:

 SELECT "id", "ts", login
 FROM (
      select "id", "ts", CASE WHEN "ts" = max("ts") OVER (PARTITION BY "id") THEN 1 ELSE 0 END as isMax, "login" from "author" group by "id"
       ) dt
 WHERE isMax = 1

Есть несколько других способов снять шкуру с этой кошки, но в этом и заключается суть.

...