PL / pgSQL列名与变量相同

时间:2015-04-13 07:59:48

标签: postgresql plpgsql race-condition uniqueidentifier

我是plpgsql的新手,我试图创建一个函数来检查表中是否存在某个值,如果不存在则会添加一行。

CREATE OR REPLACE FUNCTION hire(
    id_pracownika integer,
    imie character varying,
    nazwisko character varying,
    miasto character varying,
    pensja real)
  RETURNS TEXT AS
$BODY$
DECLARE
wynik TEXT;
sprawdzenie INT;
BEGIN
sprawdzenie = id_pracownika;
IF EXISTS (SELECT id_pracownika FROM pracownicy WHERE id_pracownika=sprawdzenie) THEN
wynik = "JUZ ISTNIEJE";
RETURN wynik;
ELSE
INSERT INTO pracownicy(id_pracownika,imie,nazwisko,miasto,pensja)
VALUES (id_pracownika,imie,nazwisko,miasto,pensja);
wynik = "OK";
RETURN wynik;   
END IF;
END;
$BODY$
  LANGUAGE plpgsql VOLATILE
  COST 100;

问题是我收到的错误是id_pracownika是列名和变量。

如何指定" id_pracownika"在这样的上下文中是指列名?

2 个答案:

答案 0 :(得分:6)

CREATE OR REPLACE FUNCTION hire(
    id_pracownika integer
  , imie varchar
  , nazwisko varchar
  , miasto varchar
  , pensja real)
  RETURNS TEXT AS
$func$
BEGIN

IF EXISTS (SELECT 1 FROM pracownicy p
           WHERE p.id_pracownika = hire.sprawdzenie) THEN
   RETURN 'JUZ ISTNIEJE'::text;  -- wynik
ELSE
   INSERT INTO pracownicy(id_pracownika,imie,nazwisko,miasto,pensja)
   VALUES (hire.sprawdzenie,hire.imie,hire.nazwisko,hire.miasto,hire.pensja);

   RETURN 'OK'::text;  -- wynik
END IF;

END
$func$  LANGUAGE plpgsql;
  • 与@pozs评论一样,使用函数名对模式限定列名和前缀函数参数,以便在必要时消除歧义。 但请注意,INSERT的目标列表中的列名可能不会加前缀。无论如何,这些都不会模棱两可。

  • 就像@Frank评论的那样,最好避免这种含糊不清,这样可以减少错误。 如果您还需要列名作为函数参数名,那么避免命名冲突的一种方法是在函数内部使用ALIAS。这是ALIAS实际上有用的极少数情况之一。 或者您可以在$1之前引用输入参数: id_pracownika ,在这种情况下为"OK"

但还有更多:

  • 字符串文字(文本常量)必须用单引号括起来:'确定',而不是 :=

  • plpgsql中的赋值运算符为EXISTS

  • SELECT id_pracownika表达式中,选择 并不重要。 SELECT 1SELECT 123/0甚至VOLATILE COST 100相同。只有行的存在才有意义。

  • 分配变量比其他编程语言相对昂贵。如果有一种优雅的方法可以保存其中一些操作,那么这是plpgsql的首选方式。尽可能在SQL语句中直接执行。

  • SELECT是函数的默认装饰器。你不必拼出那些。

INSERTUPSERT

你的功能是" SELECT或INSERT"的另一个实现。 - INSERT INTO pracownicy(id_pracownika,imie,nazwisko,miasto,pensja) VALUES (hire.sprawdzenie,hire.imie,hire.nazwisko,hire.miasto,hire.pensja); ON CONFLICT DO NOTHING RETURNING 'OK'::text; -- wynik IF NOT FOUND THEN RETURN 'JUZ ISTNIEJE'::text; END IF; 问题的变体,面对并发写入负载比您想象的更复杂。 (您的简单解决方案忽略的潜在问题,顺便说一句,并且可能使其失败!)详情:

POSTERT in Postgres 9.5

Postgres团队(最突出的是Peter Geoghegan)已经在Postgres 9.5中实施了UPSERT。 Is SELECT or INSERT in a function prone to race conditions?这种新语法将执行干净工作

{{1}}

答案 1 :(得分:0)

这是我测试的一个示例,我使用EXECUTE运行select并使用动态列名将其结果放入游标中。

<强> 1。创建表格:

create table people (
  nickname varchar(9),
  name varchar(12),
  second_name varchar(12),
  country varchar(30)
  );

<强> 2。创建功能:

CREATE OR REPLACE FUNCTION fun_find_people (col_name text, col_value varchar)
RETURNS void AS
$BODY$
DECLARE
    local_cursor_p refcursor;
    row_from_people RECORD;

BEGIN
    open local_cursor_p FOR
        EXECUTE 'select * from people where '|| col_name || ' LIKE ''' || col_value || '%'' ';

    raise notice 'col_name: %',col_name;
    raise notice 'col_value: %',col_value;

    LOOP
        FETCH local_cursor_p INTO row_from_people; EXIT WHEN NOT FOUND;

        raise notice 'row_from_people.nickname: %',  row_from_people.nickname ;
        raise notice 'row_from_people.name: %', row_from_people.name ;
        raise notice 'row_from_people.country: %', row_from_people.country;
    END LOOP;
END;
$BODY$ LANGUAGE 'plpgsql'

第3。运行功能 select fun_find_people('name', 'Cristian'); select fun_find_people('country', 'Chile');