Postgres 10 для столбца конфликта имеет то же имя, что и столбец в возвращаемой таблице = неоднозначный

У меня есть следующее определение таблицы:

CREATE TABLE test.table_on_conflict (
  a INTEGER NOT NULL,
  b INTEGER,
  CONSTRAINT table_pkey PRIMARY KEY(a)
) 
WITH (oids = false);

и определение функции:

CREATE OR REPLACE FUNCTION test.update_on_conflict (
  _a integer,
  _b integer
)
RETURNS TABLE (
  a integer,
  b integer
) AS
$body$
BEGIN

INSERT INTO test.table_on_conflict (a, b)
SELECT _a, _b
ON CONFLICT (a) DO UPDATE SET b = EXCLUDED.b;           

RETURN QUERY
SELECT t.a, t.b
FROM test.table_on_conflict t
WHERE t.a = _a;

END;
$body$
LANGUAGE 'plpgsql'
VOLATILE
CALLED ON NULL INPUT
SECURITY INVOKER
COST 100 ROWS 1000;

Поскольку в возвращаемой таблице есть столбец "a", ON CONFLICT (a) DO UPDATE SET... выдает ошибку:

ERROR:  column reference "a" is ambiguous 
LINE 3: ON CONFLICT (a) DO UPDATE SET b = EXCLUDED.b
                     ^ 
DETAIL:  It could refer to either a PL/pgSQL variable or a table column.
QUERY:  INSERT INTO test.table_on_conflict (a, b) SELECT _a, _b ON CONFLICT (a) DO UPDATE SET b = EXCLUDED.b
CONTEXT:  PL/pgSQL function test.update_on_conflict(integer,integer) line 4 at SQL statement

Есть ли способ устранить неоднозначность без использования имени ограничения?

1 ответ

Решение

Я вижу два разных решения:

Сначала упростим вашу функцию до функции SQL:

CREATE OR REPLACE FUNCTION update_on_conflict (_a integer, _b integer)
  RETURNS TABLE (a integer, b integer) AS
$body$

  INSERT INTO table_on_conflict (a, b)
  values (_a, _b)
  ON CONFLICT (a) DO UPDATE 
    SET b = EXCLUDED.b
  returning *;           

$body$
LANGUAGE sql;

Если вам нужен PL/pgSQL (потому что у вас есть другой код, который вы не показали нам), вы можете объявить функцию как RETURNS setof table_on_conflict

CREATE OR REPLACE FUNCTION update_on_conflict (_a integer, _b integer)
  RETURNS setof  table_on_conflict
AS
$body$
begin

  return query
    INSERT INTO table_on_conflict (a, b)
    values (_a, _b)
    ON CONFLICT (a) DO UPDATE SET b = EXCLUDED.b
    returning *;           

end;  
$body$
LANGUAGE plpgsql;

Отдельный select не нужно ни в коем случае. Вы можете напрямую вернуть результат оператора INSERT.


Не связано, но: название языка является идентификатором. Не помещайте это в одинарные кавычки.

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