Postgres: найти максимальное значение в массиве int?

с использованием Postgres 9.3...

Может кто-нибудь объяснить, почему я не могу использовать функцию max непосредственно для невложенного массива..?

Насколько я понимаю, функция unnest возвращает "setof", как и оператор select. Так почему же короткая версия этого запроса не работает? (Я что-то упустил концептуально или моя проблема связана с синтаксисом?)

table: foo_history: 

id | history::smallint
----------------------------------- 
1  |  {10,20,30,50,40}

Это не работает?

Select id, max(unnest(history)) as vMax from foo_history;

...а этот делает...?

WITH foo as (
    select id, unnest(history) as history 
    from foo_history
)
Select 
    id, max(history) as vMax
From foo 
Group by id;

person warchitect    schedule 05.02.2015    source источник
comment
Несмотря на то, что я написал свою собственную функцию, чтобы решить проблему, я все еще немного запутался. Функция unnest возвращает набор строк, а функция max работает с набором строк. Это ошибка или я чего-то не понимаю?   -  person warchitect    schedule 06.02.2015
comment
Да, есть. max является агрегатом, поэтому он работает с одним входом для каждого кортежа. Он не может принимать набор в качестве входных данных. Чтобы сделать то, что вы описываете, вы должны использовать подзапрос, например select id, (select max(x) from unnest(history) x) as vmax from foo_history.   -  person Craig Ringer    schedule 07.02.2015


Ответы (3)


Если вы установите модуль intarray, он предоставит несколько дополнительных операторов массива, которые позволят вам писать то, что вы хотите, хотя и несколько неэффективно:

CREATE EXTENSION intarray;

SELECT id, (sort_desc(history))[1] as vMax
FROM foo_history;

Было бы довольно легко написать функции наибольшего и наименьшего для массивов, чтобы добавить их к intarray, код довольно прост.

В противном случае вы можете просто написать функцию SQL:

CREATE OR REPLACE FUNCTION array_greatest(anyarray)
RETURNS anyelement
LANGUAGE SQL
AS $$
  SELECT max(elements) FROM unnest($1) elements
$$;

и используйте это:

SELECT id, array_greatest(history) as vMax
FROM foo_history;
person Craig Ringer    schedule 06.02.2015
comment
Спасибо. Сразу после написания этого я написал свою собственную аналогичную функцию, которая возвращает позицию наибольшего значения в массиве. Это не было особенно сложно, однако я удивлен, что все остальные функции уже встроены, что-то такое простое еще не поддерживалось. - person warchitect; 06.02.2015
comment
@user2259963 user2259963 Каждая функция и утилита должны быть написаны кем-то, и если кто-то не хочет этого достаточно сильно, он не будет написан. В этом конкретном случае я попробую еще раз в ближайшее время, я многое узнал о кодировании для Pg с тех пор, как в последний раз попробовал это, и я хочу, чтобы он поддерживался в ядре. - person Craig Ringer; 07.02.2015
comment
Я ценю, что кто-то еще видит необходимость. Дайте мне знать, если я могу помочь. К сожалению, в моем случае я до сих пор не понимаю принципиальной разницы между тем, что я считаю набором записей и набором строк. Очень легко превратить набор записей в массив, но не наоборот; Если мы пойдем другим путем, данные будут поддерживаться существующими агрегатными функциями. Сейчас я работаю над функцией для вычисления стандартного отклонения подмножества массива. :) - person warchitect; 11.02.2015
comment
Я получаю: Ошибка SQL [42703]: ОШИБКА: столбец x не существует Где: функция SQL array_greatest во время встраивания. Вам нужно поставить x после unnest($1) в вашей функции, иначе это не сработает. - person rept; 11.09.2020

в PostgreSQL 9.6 и 8.4:

SELECT max(x) FROM unnest(ARRAY[1,2,80,3,15,4]) as x;
person Oleg Shalaev    schedule 09.07.2017
comment
Когда мы доберемся до 9.6, это будет здорово! - person warchitect; 11.07.2017

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

Предложение group by работает, как и ожидалось, потому что теперь вы агрегируете в набор, а затем получаете максимум от набора. :)

person David Hoelzer    schedule 05.02.2015
comment
Просто кажется, что мой 2nd пример очень неэффективен, если учесть, что может быть много миллионов записей. Вроде как задом наперед...?? Возможно, в этом случае подойдет пользовательская функция... - person warchitect; 05.02.2015
comment
Судя по вашему комментарию, самая большая функция должна работать, но она тоже не работает. Обе функции возвращают... "ОШИБКА: функция с набором значений вызвана в контексте, который не может принять набор" - person warchitect; 05.02.2015