HOWTO · MySQL
Declarar e usar variáveis no MySQL
Saiba quando usar variáveis de sessão do MySQL, variáveis locais DECLARE ou variáveis do sistema, com SET, SELECT ... INTO, regras de escopo e exemplos testados.
Nesta página
O MySQL tem três mecanismos de variáveis. Use uma variável de sessão definida pelo utilizador, como @limit, quando várias instruções na mesma ligação precisam de partilhar um valor. Use uma variável local sem @ numa procedure, função, trigger ou evento armazenado. Use uma variável do sistema como @@SESSION.sql_mode para consultar ou configurar o servidor ou uma ligação.
A distinção principal é que DECLARE não é uma instrução geral para uma janela SQL. Só é permitida dentro de um bloco BEGIN ... END e deve aparecer antes das outras instruções desse bloco. Para um script rápido, comece com SET @name = value;. As palavras-chave DECLARE, SET, SELECT ... INTO, BEGIN ... END, SESSION e GLOBAL permanecem iguais no SQL.
Escolher a variável MySQL correta
| Necessidade | Sintaxe | Escopo |
|---|---|---|
| Reutilizar um valor entre instruções SQL normais | SET @name = value; |
Sessão do cliente atual |
| Guardar um valor num programa armazenado | DECLARE name type [DEFAULT value]; |
Bloco BEGIN ... END |
| Ler ou alterar uma configuração do servidor | @@SESSION.name ou @@GLOBAL.name |
Uma sessão ou o servidor |
Estas formas não são intercambiáveis. DECLARE @name INT não é a sintaxe de uma variável local, e DECLARE name INT falha como instrução isolada fora de um programa armazenado.
Usar uma variável definida pelo utilizador numa sessão SQL
As variáveis definidas pelo utilizador começam por @. Não é necessário declará-las antes de as utilizar. Atribua um valor ou expressão com SET e use a variável numa instrução posterior:
SET @low = 2, @high = 4;
SELECT n FROM demo_numbers WHERE n BETWEEN @low AND @high ORDER BY n;
As variáveis pertencem à ligação atual. Outra ligação não as pode utilizar e elas desaparecem quando a ligação termina. Uma variável não inicializada resulta em NULL; inicialize-a no início de um script reutilizável.
SET é a forma de atribuição mais clara. O MySQL também aceita := numa instrução SET:
SET @total = 10;
SET @total := @total + 5;
SELECT @total;
O tipo depende do valor atribuído, não de uma declaração de tipo. A variável pode conter números, decimais, cadeias, cadeias binárias ou NULL; use valores compatíveis e conversões explícitas quando o tipo mudar.
Carregar um resultado com SELECT ... INTO
Use SELECT ... INTO quando o valor vem de uma consulta. O número de variáveis de destino deve corresponder ao número de expressões selecionadas:
SELECT COUNT(*) INTO @number_of_rows
FROM demo_numbers;
SELECT @number_of_rows;
A consulta deve ser concebida para devolver uma linha. COUNT(*) faz isso naturalmente e uma pesquisa por chave única também é adequada. Se forem possíveis várias linhas, escolha uma linha de modo determinístico com ORDER BY e LIMIT 1.
Uma variável não substitui um nome de tabela ou de coluna. SET @table_name = 'demo_numbers'; SELECT * FROM @table_name; não substitui o nome da tabela. Para SQL dinâmico, crie uma instrução para PREPARE e valide os identificadores fornecidos pela aplicação.
O MySQL 9.7 ainda permite atribuições fora de SET por compatibilidade, mas indica que esse comportamento será removido. Prefira SET e SELECT ... INTO a expressões como SELECT @n := n.
Declarar uma variável local num programa armazenado
As variáveis locais usam DECLARE sem @ e precisam de um tipo de dados MySQL. Pode indicar DEFAULT; caso contrário, o valor inicial é NULL. Coloque as declarações no início do bloco BEGIN ... END, antes das instruções executáveis. Elas são visíveis nesse bloco e nos blocos aninhados, mas não depois dele.
O procedimento seguinte usa um parâmetro de entrada, uma variável local e um parâmetro de saída. Os comandos DELIMITER pertencem ao cliente mysql e permitem enviar o corpo, que contém ponto e vírgula, como uma única instrução CREATE PROCEDURE.
DROP PROCEDURE IF EXISTS count_numbers;
DELIMITER //
CREATE PROCEDURE count_numbers(IN p_min INT, OUT p_count INT)
BEGIN
DECLARE local_count INT DEFAULT 0;
SELECT COUNT(*) INTO local_count
FROM demo_numbers
WHERE n >= p_min;
SET p_count = local_count;
END//
DELIMITER ;
CALL count_numbers(3, @result);
SELECT @result;
local_count existe apenas enquanto o procedimento é executado. O parâmetro OUT é devolvido através da variável de sessão fornecida ao CALL. Se uma consulta devolver várias colunas, forneça um destino por expressão e trate o caso sem correspondências.
Pode declarar várias variáveis do mesmo tipo numa instrução, mas declarações separadas costumam ser mais fáceis de manter:
DECLARE quantity, retries INT DEFAULT 0;
DECLARE label VARCHAR(100) DEFAULT 'pending';
DECLARE também define condições, cursores e handlers. A ordem é importante: variáveis e condições antes dos cursores, e cursores antes dos handlers. Por isso, uma declaração depois de SELECT ou SET provoca um erro de sintaxe.
Entender o limite de linhas de SELECT ... INTO
Um destino escalar armazena um valor, não um conjunto de resultados arbitrário. A consulta seguinte devolve intencionalmente três linhas e falha com o erro 1172:
SET @selected = 99;
SELECT n INTO @selected FROM demo_numbers ORDER BY n;
ERROR 1172 (42000) at line 6: Result consisted of more than one row
Limite a consulta a uma linha conhecida, agregue o resultado ou mantenha-o como um conjunto de linhas. LIMIT 1 só é adequado com uma ordenação intencional:
SELECT n INTO @selected
FROM demo_numbers
ORDER BY n DESC
LIMIT 1;
A mesma regra de uma linha aplica-se a uma variável local. Se uma rotina puder não encontrar nenhuma linha, inicialize a variável de propósito e use um handler NOT FOUND ou uma verificação de existência quando necessário.
Consultar ou definir uma variável do sistema do MySQL
As variáveis do sistema configuram o servidor ou uma ligação de cliente. Consulte-as com SHOW VARIABLES ou com @@:
SHOW SESSION VARIABLES LIKE 'sql_mode';
SELECT @@SESSION.sql_mode, @@GLOBAL.sql_mode;
Sem uma palavra de escopo, SHOW VARIABLES usa a sessão atual. Um valor de sessão afeta apenas essa ligação; um valor global normalmente inicializa novas ligações. Alterar uma variável global exige o privilégio adequado e uma variável modificável.
SET SESSION sql_mode = 'STRICT_TRANS_TABLES';
-- A privileged server administrator may use an appropriate GLOBAL setting.
-- SET GLOBAL sql_mode = 'STRICT_TRANS_TABLES';
A instrução GLOBAL comentada não faz parte da fixture executável: o sucesso depende dos privilégios e do escopo e da possibilidade de alteração da variável.
Resolver uma variável que não funciona
- Se
DECLAREfor rejeitado, confirme que está dentro deBEGIN ... ENDe antes de todas as instruções executáveis. Num script normal, useSET @name = value. - Se surgir
NULLinesperadamente, inicialize a variável e verifique a expressão ou a consulta de origem. - Se
SELECT ... INTOder o erro 1172, faça a consulta devolver exatamente uma linha ou mantenha o resultado como linhas. - É esperado que outra ligação não veja
@name, porque as variáveis são específicas da sessão. - Se
@@GLOBAL.namefalhar, verifique a possibilidade de alteração da variável e os seus privilégios administrativos.
A fixture de sucesso atribui variáveis de sessão, reutiliza-as num filtro, declara uma variável local numa procedure e devolve o parâmetro de saída. A fixture de limite verifica o diagnóstico de várias linhas de SELECT ... INTO; ambas usam um servidor MySQL temporário.
Consulte a referência de variáveis definidas pelo utilizador do MySQL, a referência de DECLARE local e a referência de atribuição com SET.