Assumindo
id_pracownika
é a PRIMARY KEY
da mesa. Ou pelo menos definido UNIQUE
. (Se não for NOT NULL
, NULL é um caso de canto.) SELECT
ou INSERT
Sua função é outra implementação de "SELECT ou INSERT" - uma variante do
UPSERT
problema, que é mais complexo em face da carga de gravação simultânea do que pode parecer. Ver:- O SELECT ou INSERT está em uma função propensa a condições de corrida?
Com UPSERT no Postgres 9.5 ou posterior
No Postgres 9.5 ou posterior use UPSERT (
INSERT ... ON CONFLICT ...
) Detalhes no Wiki do Postgres. Essa nova sintaxe faz um trabalho limpo :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$;
Nomes de coluna qualificados de tabela para desambiguar quando necessário. (Você também pode prefixar os parâmetros da função com o nome da função, mas isso fica complicado, facilmente.)
Mas os nomes das colunas na lista de destino de um
INSERT
pode não ser qualificado para mesa. (Nunca ambíguo de qualquer maneira.) Melhor evitar tais ambiguidades a priori, pois é menos propenso a erros. Alguns (inclusive eu) gostam de fazer isso prefixando todos os parâmetros e variáveis da função com um sublinhado.
Se você positivamente precisa um nome de coluna como nome de parâmetro de função também, uma maneira de evitar colisões de nomes é usar um
ALIAS
dentro da função. Um dos raros casos em que ALIAS
é realmente útil. Ou faça referência aos parâmetros da função por posição ordinal:
$1
para id_pracownika
nesse caso. Se tudo mais falhar, você pode decidir o que tem precedência definindo
#variable_conflict
. Ver:- Conflito de nomenclatura entre parâmetro de função e resultado de JOIN com cláusula USING
Há mais:
-
Existem complexidades noRETURNING
cláusula em um UPSERT. Ver:
- Como usar RETURNING com ON CONFLICT no PostgreSQL?
-
Literais de string (constantes de texto) devem ser colocados entre aspas simples:'OK', não. Ver:"OK"
- Inserir texto com aspas simples no PostgreSQL
-
A atribuição de variáveis é comparativamente mais cara do que em outras linguagens de programação. Mantenha as atribuições no mínimo para melhor desempenho em plpgsql. Faça o máximo possível em instruções SQL diretamente.
-
VOLATILE COST 100
são decoradores padrão para funções. Não há necessidade de soletrar aqueles.
Sem UPSERT no Postgres 9.4 ou anterior
...
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;
...
Em um
EXISTS
expressão, o SELECT
lista não importa. SELECT id_pracownika
, SELECT 1
, ou mesmo SELECT 1/0
- tudo o mesmo. Basta usar um SELECT
vazio Lista. Apenas a existência de qualquer linha de qualificação importa. Ver:- O que é mais fácil de ler nas subconsultas EXISTS?