Förutsatt id_pracownika
är PRIMARY KEY
av bordet. Eller åtminstone definierad UNIQUE
. (Om det inte är NOT NULL
, NULL är ett hörnfall.)
SELECT
eller INSERT
Din funktion är en annan implementering av "SELECT or INSERT" - en variant av UPSERT
problem, vilket är mer komplext inför samtidig skrivbelastning än det kan verka. Se:
- Är SELECT eller INSERT i en funktion utsatt för tävlingsförhållanden?
Med UPSERT i Postgres 9.5 eller senare
I Postgres 9.5 eller senare använd UPSERT (INSERT ... ON CONFLICT ...
) Detaljer i Postgres Wiki. Den här nya syntaxen gör ett rent jobb :
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$;
Tabellkvalificerar kolumnnamn för att disambiguera där det behövs. (Du kan också prefixa funktionsparametrar med funktionsnamnet, men det blir lätt besvärligt.)
Men kolumnnamn i mållistan för en INSERT
kanske inte är tabellkvalificerad. (Aldrig tvetydig i alla fall.)
Bäst att undvika sådana oklarheter a priori, det är mindre felbenäget. Vissa (inklusive jag) gillar att göra det genom att prefixa alla funktionsparametrar och variabler med ett understreck.
Om du verkligen behöver ett kolumnnamn som funktionsparameternamn också, ett sätt att undvika namnkollisioner är att använda en ALIAS
inne i funktionen. Ett av de sällsynta fallen där ALIAS
är faktiskt användbart.
Eller referera funktionsparametrar efter ordningsposition:$1
för id_pracownika
i det här fallet.
Om allt annat misslyckas kan du bestämma vad som ska ha företräde genom att ställa in #variable_conflict
. Se:
- Namnkonflikt mellan funktionsparameter och resultat av JOIN med USING-sats
Det finns mer:
-
Det finns krångligheter med
RETURNING
klausul i en UPSERT. Se:- Hur använder man RETURNING med ON CONFLICT i PostgreSQL?
-
Strängliteraler (textkonstanter) måste omges av enkla citattecken:'OK', inte
. Se:"OK"
- Infoga text med enkla citattecken i PostgreSQL
-
Att tilldela variabler är jämförelsevis dyrare än i andra programmeringsspråk. Håll uppdragen till ett minimum för bästa prestanda i plpgsql. Gör så mycket som möjligt i SQL-satser direkt.
-
VOLATILE COST 100
är standardinredare för funktioner. Du behöver inte skriva ut dem.
Utan UPSERT i Postgres 9.4 eller äldre
...
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;
...
I en EXISTS
uttryck, SELECT
listan spelar ingen roll. SELECT id_pracownika
, SELECT 1
, eller till och med SELECT 1/0
- alla likadana. Använd bara en tom SELECT
lista. Endast förekomsten av någon kvalificerande rad spelar roll. Se:
- Vad är lättare att läsa i EXISTS-underfrågor?