Angenommen id_pracownika
ist der PRIMARY KEY
des Tisches. Oder zumindest UNIQUE
definiert . (Wenn es nicht NOT NULL
ist , NULL ist ein Eckfall.)
SELECT
oder INSERT
Ihre Funktion ist eine weitere Implementierung von "SELECT or INSERT" - eine Variante von UPSERT
Problem, das angesichts der gleichzeitigen Schreiblast komplexer ist, als es scheinen mag. Siehe:
- Ist SELECT oder INSERT in einer Funktion anfällig für Race-Conditions?
Mit UPSERT in Postgres 9.5 oder höher
Verwenden Sie in Postgres 9.5 oder höher UPSERT (INSERT ... ON CONFLICT ...
) Details im Postgres-Wiki. Diese neue Syntax macht einen sauberen Job :
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$;
Tabellenqualifizieren Sie Spaltennamen, um sie bei Bedarf zu disambiguieren. (Sie können Funktionsparametern auch den Funktionsnamen voranstellen, aber das wird leicht umständlich.)
Aber Spaltennamen in der Zielliste eines INSERT
möglicherweise nicht tabellenqualifiziert. (Jedenfalls nie mehrdeutig.)
Vermeiden Sie solche Mehrdeutigkeiten am besten a priori, das ist weniger fehleranfällig. Einige (mich eingeschlossen) machen das gerne, indem sie allen Funktionsparametern und Variablen einen Unterstrich voranstellen.
Wenn Sie unbedingt brauchen auch ein Spaltenname als Funktionsparametername, eine Möglichkeit, Namenskollisionen zu vermeiden, ist die Verwendung eines ALIAS
innerhalb der Funktion. Einer der seltenen Fälle, in denen ALIAS
ist tatsächlich nützlich.
Oder referenzieren Sie Funktionsparameter nach Ordnungsposition:$1
für id_pracownika
in diesem Fall.
Wenn alles andere fehlschlägt, können Sie entscheiden, was Vorrang hat, indem Sie #variable_conflict
setzen . Siehe:
- Namenskonflikt zwischen Funktionsparameter und Ergebnis von JOIN mit USING-Klausel
Es gibt noch mehr:
-
Es gibt Feinheiten beim
RETURNING
Klausel in einem UPSERT. Siehe:- Wie verwendet man RETURNING mit ON CONFLICT in PostgreSQL?
-
Zeichenfolgenliterale (Textkonstanten) müssen in einfache Anführungszeichen gesetzt werden:'OK', nicht
. Siehe:"OK"
- Text mit einfachen Anführungszeichen in PostgreSQL einfügen
-
Die Zuweisung von Variablen ist vergleichsweise aufwendiger als in anderen Programmiersprachen. Beschränken Sie die Zuweisungen auf ein Minimum, um die beste Leistung in plpgsql zu erzielen. Machen Sie so viel wie möglich direkt in SQL-Anweisungen.
-
VOLATILE COST 100
sind Standarddekorateure für Funktionen. Sie müssen diese nicht buchstabieren.
Ohne UPSERT in Postgres 9.4 oder älter
...
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;
...
In einem EXISTS
Ausdruck, der SELECT
Liste spielt keine Rolle. SELECT id_pracownika
, SELECT 1
, oder sogar SELECT 1/0
- alles das selbe. Verwenden Sie einfach ein leeres SELECT
aufführen. Nur das Vorhandensein einer qualifizierenden Zeile ist von Bedeutung. Siehe:
- Was ist in EXISTS-Unterabfragen einfacher zu lesen?