Функция PostgreSQL с именами таблиц и столбцов в качестве параметров и будет возвращать минимальное и максимальное значения этого столбца (любого типа) в виде массива? - PullRequest
1 голос
/ 29 мая 2019

Я пытаюсь создать в PostgreSQL функцию, которая бы принимала имя таблицы и имя одного столбца в этой таблице (в varchars); и вернуть массив, который будет иметь минимальные и максимальные значения этого столбца.

Заранее я не (не хочу) знать тип столбца, т.е. тип элементов в возвращаемом массиве.

Я пытался создать функцию с полиморфным произвольным массивом в качестве возвращаемого типа, но продолжаю использовать синтаксические ошибки. Пробовал как в SQL, так и в PLPQSQL.

CREATE OR REPLACE FUNCTION minmax(tablename character varying, columnname character varying, OUT minmaxa anyarray) AS
$function$
BEGIN
   EXECUTE FORMAT('SELECT array_agg(foo) AS %s FROM (
            (SELECT min(%s) AS foo FROM %s)
            UNION
            (SELECT max(%s) AS foo FROM %s)
    ) AS foobar'
       , columnname
       , columnname, tablename
       , columnname, tablename)
   INTO minmaxa; 
END
$function$
LANGUAGE plpgsql;

Строка из ФОРМАТА будет:

SELECT array_agg(foo) AS columnname FROM ( 
  (SELECT min(columnname) AS foo FROM tablename)
  UNION
  (SELECT max(columnname) AS foo FROM tablename)
 ) AS foobar

Тогда контрольный пример:

create table example (columnA int, columnB varchar);
insert into example (columnA, columnB) values (1, 'ac'), (2, 'ab'), (3, 'aa');

select minmax('example', 'columnA');
select minmax('example', 'columnB');

select array_agg(columnA) from (
   (select min(columnA) AS columnA from example)
   UNION
   (select max(columnA) AS columnA from example)
  ) AS foobar;

Должен вернуться:

{1,3}
{ 'Аа', 'ас'}
{1,3}

Но в настоящее время определение функции дает: «Ошибка SQL [42P13]: ОШИБКА: невозможно определить тип данных результата Подробно: функция, возвращающая полиморфный тип, должна иметь хотя бы один полиморфный аргумент. "

Я могу заставить его работать, определив фиктивный параметр функции 'foo':

CREATE OR REPLACE FUNCTION minmax(tablename character varying, columnname character varying, foo anyelement, OUT minmaxa anyarray)

(Примечание. Параметр функции foo нигде не используется в теле функции.)

А теперь даем фиктивное значение правильного типа возвращаемого массива при вызове функции:

select minmax('example', 'columnB', ''::varchar);
select minmax('example', 'columnA', 0::int);

Тогда это работает, но что нужно изменить, чтобы мне не понадобился этот фиктивный параметр функции?

Ответы [ 2 ]

2 голосов
/ 29 мая 2019

Вы не можете сделать это со стандартными полиморфными типами, но вы можете сделать это с помощью jsonb.

CREATE OR REPLACE FUNCTION minmax(tablename regclass, columnname character varying)
RETURNS JSONB AS
$function$
DECLARE
  minmaxa jsonb;
BEGIN
   EXECUTE FORMAT('SELECT jsonb_agg(foo) AS %I FROM (
            (SELECT min(%I) AS foo FROM %I)
            UNION
            (SELECT max(%I) AS foo FROM %I)
    ) AS foobar'
       , columnname
       , columnname, tablename
       , columnname, tablename)
   INTO minmaxa;
   RETURN minmaxa;
END
$function$
STABLE
LANGUAGE plpgsql;


-- Test with integers
CREATE TABLE test (a int);
insert into test (a) values (1), (2), (3);
select minmax('test'::regclass, 'a');
 minmax
--------
 [1, 2]
(1 row)


-- Test with timestamps
create table test2 (a timestamp);
insert into test2 values ('2012-01-01T00:00:00'), ('2015-01-01T00:00:00');
select minmax('test2'::regclass, 'a');
                     minmax
------------------------------------------------
 ["2012-01-01T00:00:00", "2015-01-01T00:00:00"]
(1 row)

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

1 голос
/ 29 мая 2019

Боюсь, что невозможно легко избавиться от того атрибута, который вы называете foo.Как я понимаю из документации , значение, переданное в качестве параметра foo, требуется, чтобы сообщить Postgres, каким будет тип возвращаемых данных.

38.2.5.Полиморфные типы

Пять псевдотипов, представляющих особый интерес, - это anyelement, anyarray, anynonarray, anyenum и anyrange, которые в совокупности называются полиморфными типами.Любая функция, объявленная с использованием этих типов, называется полиморфной функцией.Полиморфная функция может работать со многими различными типами данных, , причем конкретные типы данных определяются типами данных, фактически переданными ей в конкретном вызове .

Полиморфные аргументы и результатысвязаны друг с другом и разрешаются к определенному типу данных при анализе запроса, вызывающего полиморфную функцию.Каждой позиции (либо аргумент, либо возвращаемое значение), объявленной как anyelement, разрешено иметь любой конкретный фактический тип данных, , но в любом данном вызове они должны быть одного и того же фактического типа .

* 1020.* Итак, насколько я понимаю, это то, что с полиморфной функцией удаление атрибута foo невозможно, и ваша функция выглядит таковой, поскольку она использует псевдотип anyarray.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...