PL/pgSQL列名与变量相同

use*_*415 5 postgresql plpgsql uniqueidentifier race-condition

我是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;
Run Code Online (Sandbox Code Playgroud)

问题是我收到错误,说这id_pracownika是一个列名和一个变量.

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

Erw*_*ter 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;
Run Code Online (Sandbox Code Playgroud)
  • 与@pozs评论一样,schema-qualify列名和前缀函数参数以及函数名称,以便在必要时消除歧义.但请注意,目标列表中的列名INSERT可能没有前缀.无论如何,这些都不会模棱两可.

  • 就像@Frank评论的那样,最好避免这种歧义开始,这样就不容易出错.如果您还需要列名作为函数参数名,那么避免命名冲突的一种方法是使用ALIAS函数内部.这ALIAS是实际上有用的罕见情况之一.或者,您可以参考输入参数顺序位置:$1对于id_pracownika在这种情况下.

但还有更多:

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

  • plpgsql中的赋值运算符是:=.

  • 在一个EXISTS表达式,没关系什么您选择.SELECT id_pracownikaSELECT 1和甚至是一样的SELECT 123/0.只有行的存在才重要.

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

  • VOLATILE COST 100是函数的默认装饰器.你不必拼出那些.

SELECT 要么 INSERT

您的函数是"SELECT或INSERT"的另一个实现 - UPSERT问题的一种变体,面对并发写入负载比您想象的更复杂.(您的简单解决方案忽略的潜在问题,顺便说一句,并且可能使其失败!)详细信息:

POSTERT in Postgres 9.5

Postgres团队(最突出的是Peter Geoghegan)在Postgres 9.5中实施了UPSERT.Postgres Wiki中的详细信息.这个新语法将做一个干净的工作:

   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;
Run Code Online (Sandbox Code Playgroud)