Postgres выбирает все столбцы, но группирует по одному столбцу

#sql #postgresql

#sql #postgresql

Вопрос:

У меня есть простая таблица с идентификатором unit_id oid, меткой времени time, diag bytea. Первичный ключ представляет собой комбинацию как time, так и unit_id.

Идея этого запроса состоит в том, чтобы получить последнюю строку (наибольшую временную метку) для каждого уникального идентификатора unit_id. Однако строки для каждого unit_id с последним временем не всегда возвращаются.

Я действительно хочу группировать только по идентификатору unit_id, но postgres заставляет меня также использовать diag, поскольку я выбираю это.

 SELECT DISTINCT ON(unit_id) max(time) as time, diag, unit_id 
FROM diagnostics.unit_diag_history  
GROUP BY unit_id, diag
  

Ответ №1:

Каждый раз, когда вы начинаете думать, что вам нужна локализованная ГРУППА, вам следует начать думать о функциях окна.

Я думаю, вам нужно что-то вроде этого:

 select unit_id, time, diag
from (
    select unit_id, time, diag,
           rank() over (partition by unit_id order by time desc) as rank
    from diagnostics.unit_diag_history
) as dt
where rank = 1
  

Возможно, вы захотите добавить что-то в ORDER BY, чтобы также последовательно разрывать связи, но это не изменит общую технику.

Комментарии:

1. Можем ли мы сделать это без использования sub select ?

2. @metdos: я ничего не могу придумать, но может быть способ. Что не так с производными таблицами?

Ответ №2:

Вы можете объединить сгруппированный выбор с исходной таблицей:

 SELECT d.time, d.diag, d.unit_id
FROM(
    SELECT unit_id, max(time) as max_time
    FROM diagnostics.unit_diag_history
    GROUP BY unit_id
) s JOIN diagnostics.unit_diag_history d
ON s.unit_id = d.unit_id AND s.max_time = d.time
  

Комментарии:

1. Это единственный ответ, который я нашел за несколько дней поиска в Google, который мне каким-либо образом помог (исходя из MySQL).

2. Очень старый комментарий, но все еще очень полезный 🙂