Em artigos anteriores, abordamos os perigos de usar palavras-chave SQL e nomes cíclicos ao nomear variáveis em rotinas armazenadas no PostgreSQL. Mas os desafios da nomeação no PL/pgSQL não param por aí. Há um terceiro problema que pode complicar ainda mais o seu código: a ambiguidade quando as variáveis de uma função têm o mesmo nome que as colunas do seu banco de dados.
Ilustrando o Problema com um Exemplo Prático
Suponha que temos a seguinte tabela employees
:
CREATE TABLE employees (
employee_id INTEGER,
name TEXT,
salary INTEGER
);
E agora você está criando uma função PL/pgSQL que calcula um aumento salarial, e você escolhe chamar sua variável de salary
, igual à coluna da tabela:
CREATE OR REPLACE FUNCTION raise_salary(employee_id INTEGER, increase INTEGER)
RETURNS VOID AS $$
DECLARE
salary INTEGER;
BEGIN
SELECT salary + increase INTO salary
FROM employees WHERE employee_id = employee_id;
UPDATE employees SET salary = salary
WHERE employee_id = employee_id;
END;
$$ LANGUAGE plpgsql;
Parece correto, certo? No entanto, essa função não funcionará como esperado. O problema é que o PostgreSQL não consegue distinguir entre a variável salary
e a coluna salary
da tabela employees
. O mesmo vale para employee_id
.
Se você tentar executar essa função, a atualização não afetará a coluna salary
da tabela, como pretendido. Em vez disso, ela alterará apenas a variável salary
na função. Além disso, a cláusula WHERE se torna ambígua porque não está claro a qual employee_id
ela se refere: o parâmetro ou a coluna?
Como Resolver Variáveis Ambíguas
Uma das melhores maneiras de evitar essa confusão é nunca usar o mesmo nome para uma variável de função e uma coluna de tabela. Por exemplo, poderíamos chamar a variável de new_salary
em vez de salary
:
CREATE OR REPLACE FUNCTION raise_salary(p_employee_id INTEGER, increase INTEGER)
RETURNS VOID AS $$
DECLARE
new_salary INTEGER;
BEGIN
SELECT salary + increase INTO new_salary
FROM employees WHERE employee_id = p_employee_id;
UPDATE employees SET salary = new_salary
WHERE employee_id = p_employee_id;
END;
$$ LANGUAGE plpgsql;
Agora, está claro que a variável new_salary
contém o novo salário, e p_employee_id
é o parâmetro passado para a função. Isso resolve a ambiguidade.