[英]PL/pgSQL column name the same as variable
我是 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”是指列名?
假设id_pracownika
是表的PRIMARY KEY
。 或者至少定义了UNIQUE
。 (如果它不是NOT NULL
,则 NULL 是一个极端情况。)
SELECT
或INSERT
您的函数是“SELECT 或 INSERT”的另一种实现UPSERT
问题的一个变体,它在并发写入负载时比看起来更复杂。 看:
在 Postgres 9.5 或更高版本中,使用Postgres Wiki 中的UPSERT ( INSERT ... ON CONFLICT ...
)详细信息。 这种新语法做得很干净:
CREATE OR REPLACE FUNCTION hire(
_id_pracownika integer
, _imie varchar
, _nazwisko varchar
, _miasto varchar
, _pensja real)
RETURNS text
LANGUAGE plpgsql AS
$func$
BEGIN
INSERT INTO pracownicy
( id_pracownika, imie, nazwisko, miasto, pensja)
VALUES (_id_pracownika,_imie,_nazwisko,_miasto,_pensja);
ON CONFLICT DO NOTHING
RETURNING 'OK';
IF NOT FOUND THEN
RETURN 'JUZ ISTNIEJE';
END IF;
END
$func$;
表限定列名以在必要时消除歧义。 (您也可以使用函数名称作为函数参数的前缀,但这很容易变得尴尬。)
但是INSERT
的目标列表中的列名可能不是表限定的。 (无论如何都不要模棱两可。)
最好避免这种先验的歧义,这样就不容易出错。 有些人(包括我)喜欢通过在所有函数参数和变量前面加上下划线来做到这一点。
如果您也确实需要一个列名作为函数参数名,避免命名冲突的一种方法是在函数内使用ALIAS
。 ALIAS
实际上有用的罕见情况之一。
或者按顺序位置引用函数参数:在这种情况下, id_pracownika
为$1
。
如果所有其他方法都失败了,您可以通过设置#variable_conflict
来决定什么优先。 看:
还有更多:
UPSERT 中的RETURNING
子句很复杂。 看:
字符串文字(文本常量)必须用单引号括起来: 'OK',而不是
。 看:"OK"
与其他编程语言相比,分配变量的成本相对更高。 将分配保持在最低限度,以便在 plpgsql 中获得最佳性能。 尽量直接在 SQL 语句中做。
VOLATILE COST 100
是函数的默认装饰器。 没有必要把这些拼写出来。
...
IF EXISTS (SELECT FROM pracownicy p
WHERE p.id_pracownika = hire.id_pracownika) THEN
RETURN 'JUZ ISTNIEJE';
ELSE
INSERT INTO pracownicy(id_pracownika,imie,nazwisko,miasto,pensja)
VALUES (hire.id_pracownika,hire.imie,hire.nazwisko,hire.miasto,hire.pensja);
RETURN 'OK';
END IF;
...
在EXISTS
表达式中, SELECT
列表无关紧要。 SELECT id_pracownika
, SELECT 1
,甚至SELECT 1/0
- 都是一样的。 只需使用一个空的SELECT
列表。 只有任何符合条件的行的存在才重要。 看:
这是我测试的一个示例,我使用 EXECUTE 运行选择并将其结果放入游标中,使用动态列名。
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');
select fun_find_people('name', 'Cristian'); select fun_find_people('country', 'Chile');
从 Erwin Brandstetter 的答案中获得启发。
CREATE OR REPLACE FUNCTION test_upsert(
_parent_id int,
_some_text text)
RETURNS text
LANGUAGE plpgsql AS
$func$
DECLARE a text;
BEGIN
INSERT INTO parent_tree (parent_id, some_text)
VALUES (_parent_id,_some_text)
ON CONFLICT DO NOTHING
RETURNING 'ok' into a;
return a;
IF NOT FOUND THEN
return 'JUZ ISTNIEJE';
END IF;
END
$func$;
a
变量保存返回类型文本。parent_id = 10
,那么结果如下:test_upsert
------------
(1 row)
不确定的用法:
IF NOT FOUND THEN return 'JUZ ISTNIEJE'; END IF;
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.