假设
id_pracownika
是表的主键,或至少定义为
UNIQUE
。(如果它不是
NOT NULL
,那么 NULL 是一个特殊情况。)
SELECT
或 INSERT
您的函数是“SELECT or INSERT”的另一种实现——这是
UPSERT
问题的变体,在并发写入负载面前比看起来更加复杂。请参见:
使用 Postgres 9.5 或更高版本的 UPSERT
在 Postgres 9.5 或更高版本中,使用 UPSERT(
INSERT ... ON CONFLICT ...
)
详情请参阅 Postgres Wiki。 这个新语法可以很好地完成工作:
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;
IF FOUND THEN
RETURN 'OK';
ELSE
RETURN 'JUZ ISTNIEJE';
END IF;
END
$func$;
关于特殊变量
FOUND
:
在必要的情况下,使用表限定列名以消除歧义。(您也可以在函数参数前缀中加上函数名称,但这很快就会变得笨拙。)
但是,在INSERT
的目标列表中的列名可能没有表限定。那些从来不会有歧义。
最好先避免模棱两可。一些人(包括我)喜欢用下划线作为所有函数参数和变量的前缀。
如果您确实需要将列名作为函数参数名,避免命名冲突的一种方法是在函数内部使用ALIAS
。这是ALIAS
实际上有用的少数情况之一。
你可以通过 顺序位置 引用函数参数:$1
在这种情况下表示 id_pracownika
。
如果其他方法都失败了,你可以通过设置 #variable_conflict
来确定哪个优先级更高。参见:
还有更多内容:
UPSERT中的RETURNING
子句有复杂性。请参见:
字符串字面量(文本常量)必须用单引号括起来:'OK',而不是"OK"
。请参见:
相对于其他编程语言,赋值变量的成本更高。为了获得最佳性能,请尽可能直接在SQL语句中执行操作,尽量减少赋值。
VOLATILE COST 100
是函数的默认装饰器。不需要详细说明。
在Postgres 9.4或更早版本中没有UPSERT
...
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;
...
但在
SELECT
和
INSERT
之间存在微小的竞争条件,因此在大量并发写入负载下不完全可靠。
在
EXISTS
表达式中,
SELECT
列表并不重要。
SELECT id_pracownika
、
SELECT 1
,甚至是
SELECT 1/0
- 都一样。只需使用空的
SELECT
列表即可。只有任何符合条件的行的存在才是重要的。请参见:
hire.id_pracownika
引用参数,使用pracownicy.id_pracownika
引用列(像往常一样)。文档链接 - pozssprawdzenie = id_pracownika;
赋值了,所以只需在INSERT INTO pracownicy(id_pracownika..,..,) VALUES(sprawdzenie,..,..)
中使用sprawdzenie
即可。 - Vivek S.