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"是指列名?
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_pracownika是SELECT 1和甚至是一样的SELECT 123/0.只有行的存在才重要.
分配变量比其他编程语言相对昂贵.如果有一种优雅的方法来保存这些操作,那么这是plpgsql的首选方式.尽可能在SQL语句中直接执行.
VOLATILE COST 100是函数的默认装饰器.你不必拼出那些.
SELECT 要么 INSERT您的函数是"SELECT或INSERT"的另一个实现 - UPSERT问题的一种变体,面对并发写入负载比您想象的更复杂.(您的简单解决方案忽略的潜在问题,顺便说一句,并且可能使其失败!)详细信息:
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)
| 归档时间: |
|
| 查看次数: |
4383 次 |
| 最近记录: |