PostgreSQL: синтаксическая ошибка в "рефкурсоре" или рядом с ним [дубликат]

Когда я работаю с базами данных Microsoft SQL Server, я иногда возвращаю несколько наборов результатов из хранимых процедур. Я часто возвращаю так много, что становится трудно понять, что есть что. Чтобы решить эту проблему, я следую соглашению, которое я узнал от коллеги: 1-й набор результатов - это «карта», которая определяет имена для 2-го и других наборов результатов. Он имеет единственную запись, где каждое имя поля - это имя набора результатов, а соответствующее значение поля - его индекс в возвращаемом массиве наборов результатов. Клиентский код обращается к определенным наборам результатов, сначала узнавая индекс по имени.

Следующий простой пример демонстрирует идею:

      create or alter procedure divide
  @a int,
  @b int
as
begin
  declare
    @error int = 0

  -- Name-to-index map
  select
    1 as result,
    2 as error

  -- Result
  if @b = 0
  begin
    set @error = 1
    select
      null as result
  end
  else
  begin
    select
      @a / @b as result
  end

  -- Error
  select
    @error as error
end

В этом примере первый набор результатов (индекс: 0) показывает, что есть еще два набора результатов: один называется «результат» (индекс: 1), а другой - «ошибка» (индекс: 2). Оба содержат только одну запись: результат деления и код ошибки соответственно.


Пример звонка №1:

      exec divide @a = 91, @b = 13

Наборы результатов в формате JSON:

      [
  [{ result: 1, error: 2 }],
  [{ result: 7 }],
  [{ error: 0 }]
]

Пример вызова №2:

      exec divide @a = 91, @b = 0

Наборы результатов в формате JSON:

      [
  [{ result: 1, error: 2 }],
  [{ result: null }],
  [{ error: 1 }]
]

Я попытался перенести эту технику на PostgreSQL 14, используя официальную документацию и особенно эту страницу . Я придумал это:

      create or replace function divide(
  a integer,
  b integer
)
returns setof refcursor
language sql as
$$
  declare
    ref1 refcursor;
    ref2 refcursor;
    ref3 refcursor;
    error int := 0;

  begin
    -- Name-to-index map
    open ref1 for select
      1 as result,
      2 as error;
    return next ref1;

    -- Result
    if b = 0 then
      error := 1;
      open ref2 for select
        null as result;
    else
      open ref2 for select
        a / b as result;
    end if;
    return next ref2;

    -- Error
    open ref3 for select
      error;
    return next ref3;
  end;
$$;

К сожалению, я получаю сообщение об ошибке: syntax error at or near "refcursor", ссылаясь на refcursor в 1-й строке после declare.

1 ответ

Вы использовали неправильную языковую декларацию. Ваша процедура находится в plpgsqlно вы объявили это простым sqlчерез language sqlзаявление вверху.

Замена

      create or replace function divide(
  a integer,
  b integer
)
returns setof refcursor
language sql as

с

      create or replace function divide(
  a integer,
  b integer
)
returns setof refcursor
language plpgsql as

Решает проблему.

Другие вопросы по тегам