Ако приемем id_pracownika е PRIMARY KEY на масата. Или поне дефиниран UNIQUE . (Ако не е NOT NULL , NULL е ъглов случай.)
SELECT или INSERT
Вашата функция е друга реализация на "SELECT или INSERT" - вариант на UPSERT проблем, който е по-сложен при едновременно натоварване при запис, отколкото може да изглежда. Вижте:
- Изберете или INSERT във функция предразположени ли са условия на състезание?
С UPSERT в Postgres 9.5 или по-нова версия
В 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
RETURNING 'OK';
IF NOT FOUND THEN
RETURN 'JUZ ISTNIEJE';
END IF;
END
$func$;
Квалифицирайте имената на колоните в таблицата, за да ги дезидентирате, когато е необходимо. (Можете също да поставите префикс на параметрите на функцията с името на функцията, но това става неудобно, лесно.)
Но имената на колони в целевия списък на INSERT може да не е квалифициран за маса. (Все пак никога не е двусмислено.)
Най-добре избягвайте подобни неясноти априори, това е по-малко податливо на грешки. Някои (включително мен) обичат да правят това, като поставят префикс на всички функционални параметри и променлива с долно черта.
Ако положително нуждате име на колона също като име на параметър на функцията, един от начините да избегнете сблъсъци с имена е да използвате ALIAS вътре във функцията. Един от редките случаи, когато ALIAS всъщност е полезно.
Или препоръчайте параметрите на функцията по редна позиция:$1 за id_pracownika в този случай.
Ако всичко друго не успее, можете да решите кое има предимство, като зададете #variable_conflict . Вижте:
- Конфликт на именуване между параметър на функцията и резултат от JOIN с клауза USING
Има още:
-
Има тънкости в
RETURNINGклауза в UPSERT. Вижте:- Как да използвам RETURNING с ON CONFLICT в PostgreSQL?
-
Низовите литерали (текстови константи) трябва да бъдат затворени в единични кавички:'OK', а не
. Вижте:"OK"- Вмъкнете текст с единични кавички в PostgreSQL
-
Присвояването на променливи е сравнително по-скъпо, отколкото в други езици за програмиране. Сведете заданията до минимум за най-добра производителност в plpgsql. Правете колкото е възможно повече в SQL изрази директно.
-
VOLATILE COST 100са декоратори по подразбиране за функции. Няма нужда да ги изричате.
Без UPSERT в Postgres 9.4 или по-стара версия
...
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 списък. От значение е само наличието на който и да е квалификационен ред. Вижте:
- Какво е по-лесно за четене в EXISTS подзаявки?