Ако приемем 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 подзаявки?