postgresql: как получить первичный ключ из предложения group by?

Это запрос, который выбирает набор нужных строк:

select max(a), b, c, d, e
from T
group by b, c, d, e;

таблица имеет первичный ключ, в графе id.

Я хотел бы идентифицировать эти строки в следующем запросе, получив первичный ключ из каждой из этих строк. Как мне это сделать? Это не работает:

select id, max(a), b, c, d, e
from T 
group by b, c, d, e;

ERROR:  column "T.id" must appear in the GROUP BY clause or be used in an aggregate function

Я пробовал это, копаясь в некоторых других вопросах postgresql, но не повезло:

select distinct on (id) id, max(a), b, c, d, e
from T 
group by b, c, d, e;

ERROR:  column "T.id" must appear in the GROUP BY clause or be used in an aggregate function

что мне делать? Я знаю, что может быть только одна id для каждого результата, потому что это первичный ключ... Я буквально хочу первичный ключ вместе с остальными данными для каждой строки, которую возвращает начальный (рабочий) запрос.

5 ответов


Если вам все равно, какой id вы получаете, то вам просто нужно обернуть ваш id в некоторой агрегатной функции, которая гарантированно даст вам действительный id. The max и min Сростки приходят на ум:

-- Or min(id) if you want better spiritual balance.
select max(id), max(a), b, c, d, e
from T 
group by b, c, d, e;

в зависимости от ваших данных я думаю, что использование функции окна было бы лучшим планом (благодаря злому Отто для загрузки в голову):

select id, a, b, c, d, e
from (
    select id, a, b, c, d, e, rank() over (partition by b,c,d,e order by a desc) as r
    from T
) as dt
where r = 1

в силу того, что вы группировка, может (и, скорее всего) быть более одной совпадающей записи (например, более одной id value) на возвращаемую запись.

PostgreSQL довольно строгий - он не догадается, что вы имеете в виду.

  1. вы можете запустить подзапрос
  2. вы можете запустить другой запрос на основе b,c,d,e
  3. можно использовать array_agg функция группировки, чтобы получить массив id значения в запись.

см. Этот вопрос: эквивалент Postgresql GROUP_CONCAT?

Я предлагаю вам рассмотреть #3 как наиболее эффективную из возможностей.

надеюсь, что это помогает. Спасибо!


используйте исходный запрос в качестве подзапроса и используйте эти результаты для присоединения к исходной таблице для поиска идентификатора.

SELECT T.id, T.a, T.b, T.c, T.d, T.e
    FROM (SELECT max(a) AS MaxA, b, c, d, e
              FROM T
              GROUP BY b,c,d,e) q
        INNER JOIN T
            ON T.a = q.MaxA
                AND T.b = q.b
                AND T.c = q.c
                AND T.d = q.d
                AND T.e = q.e

- Это не то, что вы просили, но я подозреваю, что вы пытаетесь сделать, чтобы получить одну строку, соответствующую максимальному значению одного столбца для каждой группы определяются несколько других столбцов. Например, найти день, который был самым жарким понедельником / вторником / etc в течение всего года.

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

create table T as (
  id integer primary key,
  a integer,
  b integer,
  c integer,
  d integer)

затем создайте представление "max" as

create view T_maxgroups as 
  select max(a) as a, b, c, d 
  from T
  group by b, c, d

(Это ваш первоначальный запрос), а затем присоедините это представление к своей таблице, чтобы получить строки с максимальными значениями:

select T.* from T join maxgroups using (a,b,c,d) 

juuust curious работает ли добавление его в предложение group by?

select T.id, max(a), b, c, d, e
from T 
group by T.id b, c, d, e;