Как функция PostgreSQL может принимать целое число или массив целых чисел для одной и той же функции? - PullRequest
1 голос
/ 23 сентября 2019

У меня есть функция в Postgres 9.6, которая принимает параметр int[].Я хотел бы, чтобы функция также принимала одно целое (и при необходимости преобразовывала его в массив из одного элемента).

 CREATE OR REPLACE FUNCTION get_subordinates(inp_persona_ids integer[])
 -- Get all subordnates of the people passed in as array
 -- TODO allow a single persona ID (int) to be passed in as inp_persona_ids
 RETURNS TABLE (persona_id int) AS
 $$
    BEGIN
        RETURN QUERY(
            WITH RECURSIVE children AS (
                -- passed in persona_id
                SELECT
                    id AS persona_id,
                    manager_id
                FROM
                    personas
                WHERE
                    id = ANY(inp_persona_ids)
                UNION
                -- and all subordinates
                SELECT
                    p.id AS persona_id,
                    p.manager_id
                FROM
                    personas p
                    JOIN children c ON p.manager_id = c.persona_id
            )
            SELECT 
                children.persona_id
            FROM
                children
            LEFT JOIN
                personas on children.persona_id = personas.id
            WHERE personas.disabled IS NOT TRUE
        );
    END;
$$ LANGUAGE plpgsql

Как бы изменить определение функции, а также добавить некоторую условную логику впроверить на int и изменить на ARRAY[int] при необходимости?

Ответы [ 2 ]

1 голос
/ 23 сентября 2019

Невозможно обработать это в одной функции, но вы можете просто перегрузить функцию параметром integer и передать ее в виде массива в существующую функцию:

CREATE OR REPLACE FUNCTION get_subordinates(inp_persona_id integer)
RETURNS TABLE (persona_id int) AS
$$
BEGIN
    RETURN QUERY SELECT * FROM get_subordinates(ARRAY[inp_persona_id]);
END;
$$ LANGUAGE plpgsql;

Возможно, выможет также захотеть проверить аргумент (ы) против NULL, это ваше дело.

0 голосов
/ 26 сентября 2019

Это возможно возможно с одной функцией с использованием модификатора VARIADIC:

CREATE OR REPLACE FUNCTION get_subordinates(VARIADIC inp_persona_ids int[])
  RETURNS TABLE (persona_id int) AS
$func$
WITH RECURSIVE children AS (   -- passed in persona_id
   SELECT id AS persona_id, manager_id, disabled
   FROM   personas
   WHERE  id = ANY(inp_persona_ids)

   UNION ALL   -- and all subordinates
   SELECT p.id AS persona_id
        , p.manager_id
   FROM   children c
   JOIN   personas p ON p.manager_id = c.persona_id
)
SELECT c.persona_id
FROM   children c
WHERE  c.disabled IS NOT TRUE
$func$  LANGUAGE sql;

Но вам нужно добавить ключевое слово VARIADIC в вызове при предоставлении массива вместо списка:

SELECT * FROM  get_subordinates(VARIADIC '{1,2,3}'::int[]);
SELECT * FROM  get_subordinates(1,2,3);
SELECT * FROM  get_subordinates(1);

Если это не вариант, вы вернетесь к перегрузке функции, как предложено в другом ответе.

См .:

В сторону

  • Похоже, это может быть более простая функция SQL.
  • UNION не имеет смысла.Дубликаты могут возникать только в том случае, если ваше дерево идет по кругу, что создает бесконечный цикл, и rCTE выдает ошибку.Использовать более дешевые UNION ALL.
  • LEFT JOIN не имело смысла.Добавление WHERE заставило его вести себя как обычный [INNER] JOIN в любом случае.
  • Но полностью удалить объединение и получить столбец disabled внутри rCTE.
...