Zakładając id_pracownika
to PRIMARY KEY
tabeli. Lub przynajmniej zdefiniowany UNIQUE
. (Jeśli nie jest NOT NULL
, NULL to przypadek narożny.)
SELECT
lub INSERT
Twoja funkcja to kolejna implementacja "SELECT lub INSERT" - wariant UPSERT
problem, który jest bardziej złożony w obliczu współbieżnego obciążenia zapisu, niż mogłoby się wydawać. Zobacz:
- Czy SELECT lub INSERT w funkcji podatnej na wyścigi?
Z UPSERT w Postgresie 9.5 lub nowszym
W Postgresie 9.5 lub nowszym użyj UPSERT (INSERT ... ON CONFLICT ...
) Szczegóły w Postgres Wiki. Ta nowa składnia wykonuje czystą pracę :
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$;
W razie potrzeby kwalifikuj nazwy kolumn do ujednoznacznienia. (Możesz także poprzedzić parametry funkcji nazwą funkcji, ale to staje się niezręczne, łatwo.)
Ale nazwy kolumn na liście docelowej INSERT
może nie być zakwalifikowany do tabeli. (I tak nigdy nie jest dwuznaczny).
Najlepiej unikać takich niejasności a priori, to jest mniej podatne na błędy. Niektórzy (w tym ja) lubią to robić, poprzedzając wszystkie parametry funkcji i zmienne podkreśleniem.
Jeśli zdecydowanie potrzebujesz nazwa kolumny jako nazwa parametru funkcji, jednym ze sposobów uniknięcia kolizji nazw jest użycie ALIAS
wewnątrz funkcji. Jeden z rzadkich przypadków, w których ALIAS
jest rzeczywiście przydatne.
Lub odwołaj się do parametrów funkcji według pozycji porządkowej:$1
dla id_pracownika
w tym przypadku.
Jeśli wszystko inne zawiedzie, możesz zdecydować, co ma pierwszeństwo, ustawiając #variable_conflict
. Zobacz:
- Konflikt nazw między parametrem funkcji a wynikiem JOIN z klauzulą USING
Jest więcej:
-
Istnieją zawiłości
RETURNING
klauzula w UPSERT. Zobacz:- Jak używać RETURNING z ON CONFLICT w PostgreSQL?
-
Literały tekstowe (stałe tekstowe) muszą być ujęte w pojedyncze cudzysłowy:„OK”, a nie
. Zobacz:"OK"
- Wstaw tekst z pojedynczymi cudzysłowami w PostgreSQL
-
Przypisywanie zmiennych jest porównywalnie droższe niż w innych językach programowania. Ogranicz przypisania do minimum, aby uzyskać najlepszą wydajność w plpgsql. Zrób jak najwięcej bezpośrednio w instrukcjach SQL.
-
VOLATILE COST 100
są domyślnymi dekoratorami funkcji. Nie trzeba ich wyjaśniać.
Bez UPSERT w Postgresie 9.4 lub starszym
...
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;
...
W EXISTS
wyrażenie, SELECT
lista nie ma znaczenia. SELECT id_pracownika
, SELECT 1
, a nawet SELECT 1/0
- wszystkie takie same. Po prostu użyj pustego SELECT
lista. Liczy się tylko istnienie jakiegokolwiek kwalifikującego się wiersza. Zobacz:
- Co jest łatwiejsze do odczytania w podzapytaniach EXISTS?