Assumendo id_pracownika
è la PRIMARY KEY
della tavola. O almeno definito UNIQUE
. (Se non è NOT NULL
, NULL è un caso d'angolo.)
SELECT
o INSERT
La tua funzione è un'altra implementazione di "SELECT or INSERT", una variante di UPSERT
problema, che è più complesso di quanto potrebbe sembrare di fronte al carico di scrittura simultaneo. Vedi:
- SELEZIONA o INSERT in una funzione soggetta a condizioni di gara?
Con UPSERT in Postgres 9.5 o versioni successive
In Postgres 9.5 o versioni successive usa UPSERT (INSERT ... ON CONFLICT ...
) Dettagli nel Wiki di Postgres. Questa nuova sintassi fa un lavoro pulito :
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$;
Nomi di colonna qualificati per tabella per chiarire le ambiguità ove necessario. (Puoi anche anteporre i parametri della funzione con il nome della funzione, ma diventa imbarazzante, facilmente.)
Ma i nomi delle colonne nell'elenco di destinazione di un INSERT
potrebbe non essere qualificato al tavolo. (Comunque mai ambiguo.)
Meglio evitare tali ambiguità a priori, è meno soggetto a errori. Ad alcuni (me compreso) piace farlo anteponendo a tutti i parametri di funzione e variabile un carattere di sottolineatura.
Se ne hai necessità positivamente anche un nome di colonna come nome di parametro di funzione, un modo per evitare conflitti di denominazione è utilizzare un ALIAS
all'interno della funzione. Uno dei rari casi in cui ALIAS
è effettivamente utile.
Oppure fare riferimento ai parametri della funzione in base alla posizione ordinale:$1
per id_pracownika
in questo caso.
Se tutto il resto fallisce, puoi decidere cosa ha la precedenza impostando #variable_conflict
. Vedi:
- Conflitto di denominazione tra parametro di funzione e risultato di JOIN con clausola USING
C'è di più:
-
Ci sono complicazioni nel
RETURNING
clausola in un UPSERT. Vedi:- Come utilizzare RETURNING con ON CONFLICT in PostgreSQL?
-
Le stringhe letterali (costanti di testo) devono essere racchiuse tra virgolette singole:'OK', non
. Vedi:"OK"
- Inserisci testo con virgolette singole in PostgreSQL
-
L'assegnazione di variabili è relativamente più costosa rispetto ad altri linguaggi di programmazione. Mantieni le assegnazioni al minimo per ottenere le migliori prestazioni in plpgsql. Fai quanto più possibile direttamente nelle istruzioni SQL.
-
VOLATILE COST 100
sono decoratori predefiniti per le funzioni. Non c'è bisogno di scriverli.
Senza UPSERT in Postgres 9.4 o versioni precedenti
...
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 un EXISTS
espressione, il SELECT
elenco non importa. SELECT id_pracownika
, SELECT 1
o anche SELECT 1/0
- lo stesso. Basta usare un SELECT
vuoto elenco. Solo l'esistenza di qualsiasi riga qualificante è importante. Vedi:
- Cosa è più facile da leggere nelle sottoquery EXISTS?