PostgreSQL
 sql >> Database >  >> RDS >> PostgreSQL

Il nome della colonna PL/pgSQL è uguale alla variabile

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 "OK" . Vedi:

    • 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?