Функция для выбора существующего значения или вставки новой строки - PullRequest
0 голосов
/ 21 мая 2018

Я новичок в работе с PL / pgSQL и пытаюсь создать функцию, которая либо найдет идентификатор существующей строки, либо вставит новую строку, если она не найдена, и выдаст новуюЯ БЫ.

Запрос, содержащийся в функции ниже, прекрасно работает сам по себе, и функция создается прекрасно.Однако, когда я пытаюсь запустить его, я получаю сообщение об ошибке «ОШИБКА: ссылка на столбец« id »является неоднозначной».Кто-нибудь может определить мою проблему или предложить более подходящий способ сделать это?

create or replace function sp_get_insert_company(
    in company_name varchar(100)
)
returns table (id int)
as $$
begin
    with s as (
        select 
            id
        from 
            companies
        where name = company_name
    ), 
    i as (
        insert into companies (name)
        select company_name 
        where not exists (select 1 from s)
        returning id
    )
    select id
    from i
    union all
    select id
    from s;
end;
$$ language plpgsql;

Вот как я вызываю функцию:

select sp_get_insert_company('TEST')

И это ошибка, которую я получаю:

Ошибка SQL [42702]: ОШИБКА: ссылка на столбец "id" является неоднозначной
Подробно: может относиться либо к переменной PL / pgSQL, либо к столбцу таблицы.
Где:Функция PL / pgSQL sp_get_insert_company (с изменением символов) строка 3 в операторе SQL

Ответы [ 2 ]

0 голосов
/ 22 мая 2018

В отображаемой функции нет необходимости в returns table (id int). предполагается , чтобы всегда возвращать ровно один целочисленный идентификатор.Упростите до RETURNS int.Это также заставляет ERROR: column reference "id" is ambiguous уйти, так как мы неявно удалили параметр OUT id (видимый во всем функциональном блоке).

Также нет необходимости в LANGUAGE plpgsql.Может быть просто LANGUAGE sql, тогда вам не нужно будет добавлять RETURNS QUERY.Итак:

CREATE OR REPLACE FUNCTION sp_get_insert_company(_company_name text)
  RETURNS int AS
$func$
   WITH s as (
     select c.id  -- still good style to table-qualify all columns
     from   companies c
     where  c.name = _company_name
   ), 
   i as (
     insert into companies (name)
     select _company_name
     where  not exists (select 1 from s)
     returning id
   )
   select s.id from s 
   union all
   select i.id from i
   LIMIT 1;  -- to optimize performance
$func$  LANGUAGE sql;

За исключением , что он все еще страдает от проблем параллелизма .Найдите правильное решение для вашей нераскрытой версии Postgres в этом тесно связанном ответе:

0 голосов
/ 21 мая 2018

Как говорится в сообщении, id там дважды.Один раз в запросах, один раз в определении таблицы типа возврата.Каким-то образом это конфликтует.

Попробуйте квалифицировать выражения столбца везде.

...
with s as (
    select 
        companies.id
    from 
        companies
    where name = company_name
), 
i as (
    insert into companies (name)
    select company_name 
    where not exists (select 1 from s)
    returning companies.id
)
select i.id
from i
union all
select s.id
from s;
...

При определении выражения столбца СУБД больше не путает id таблицы с id вопределение возвращаемого типа.

Следующая проблема будет в том, что у вашего SELECT нет цели.Он скажет вам сделать PERFORM вместо этого.Но я предполагаю, что вы хотите вернуть результаты.Для этого измените тело на

...
RETURN QUERY (
with s as (
    select 
        companies.id
    from 
        companies
    where name = company_name
), 
i as (
    insert into companies (name)
    select company_name 
    where not exists (select 1 from s)
    returning companies.id
)
select i.id
from i
union all
select s.id
from s);
...

.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...