MySQL: @ variável vs. variável. Qual é a diferença?

501

Em outra pergunta, eu postei alguém me disse que há uma diferença entre:

@variable

e:

variable

no MySQL. Ele também mencionou como o MSSQL tem escopo em lote e o MySQL possui escopo de sessão. Alguém pode elaborar isso para mim?

aarona
fonte
1
Eu estou familiarizado com o MsSQL e, portanto, nunca me ocorreu a ideia de fazer uma pergunta dessas. As respostas fornecidas aqui me deram uma pista sobre algo sobre o qual eu não tinha IDÉIA !! Thx ..
Ken

Respostas:

624

MySQLtem o conceito de variáveis ​​definidas pelo usuário .

São variáveis ​​de tipo vagamente digitado que podem ser inicializadas em algum lugar da sessão e mantêm seu valor até o término da sessão.

Eles são anexados com um @sinal, assim:@var

Você pode inicializar essa variável com uma SETinstrução ou dentro de uma consulta:

SET @var = 1

SELECT @var2 := 2

Ao desenvolver um procedimento armazenado MySQL, você pode passar os parâmetros de entrada e declarar as variáveis ​​locais:

DELIMITER //

CREATE PROCEDURE prc_test (var INT)
BEGIN
    DECLARE  var2 INT;
    SET var2 = 1;
    SELECT  var2;
END;
//

DELIMITER ;

Essas variáveis ​​não são anexadas a nenhum prefixo.

A diferença entre uma variável de procedimento e uma variável definida pelo usuário específica da sessão é que a variável do procedimento é reinicializada a NULLcada vez que o procedimento é chamado, enquanto a variável específica da sessão não é:

CREATE PROCEDURE prc_test ()
BEGIN
    DECLARE var2 INT DEFAULT 1;
    SET var2 = var2 + 1;
    SET @var2 = @var2 + 1;
    SELECT  var2, @var2;
END;

SET @var2 = 1;

CALL prc_test();

var2  @var2
---   ---
2     2


CALL prc_test();

var2  @var2
---   ---
2     3


CALL prc_test();

var2  @var2
---   ---
2     4

Como você pode ver, var2(variável de procedimento) é reinicializada cada vez que o procedimento é chamado, enquanto @var2(variável específica da sessão) não é.

(Além das variáveis ​​definidas pelo usuário, o MySQL também possui algumas "variáveis ​​de sistema" predefinidas, que podem ser "variáveis ​​globais", como @@global.port"variáveis ​​de sessão", como@@session.sql_mode ; variáveis.)

Quassnoi
fonte
43
Observe também que existem variáveis ​​globais disponíveis: veja, SELECT @@version;por exemplo. Essa também é uma razão pela qual o uso DELIMITER @@não é realmente uma boa ideia.
Mchl
13
faz novas perguntas para novidades ... existe alguma diferença entre "var = var" e "var: = var" como no seu exemplo?
Confiq # 13/12
13
@confiq: não há nenhum.
Quassnoi
10
Outra pergunta para um recém-chegado. Quando é recomendado usar @vs não?
pixelfreak
73
@confiq, @Quassnoi: existe uma diferença significativa entre :=e =, e isso :=funciona como um operador de atribuição de variáveis ​​em qualquer lugar, enquanto =apenas funciona dessa maneira em SETdeclarações e é um operador de comparação em qualquer outro lugar. Então SELECT @var = 1 + 1;vai deixar @var inalterado e retornar um booleano (1 ou 0 dependendo do valor atual de @var), enquanto SELECT @var := 1 + 1;vai mudar @var a 2, e voltar 2.
Dewi Morgan
71

No MySQL, @variableindica uma variável definida pelo usuário . Você pode definir o seu próprio.

SET @a = 'test';
SELECT @a;

Fora dos programas armazenados, a variable, without @, é uma variável do sistema que você não pode definir por si mesmo.

O escopo desta variável é a sessão inteira. Isso significa que, embora exista sua conexão com o banco de dados, a variável ainda pode ser usada.

Isso contrasta com o MSSQL, onde a variável estará disponível apenas no lote atual de consultas (procedimento armazenado, script ou outro). Não estará disponível em um lote diferente na mesma sessão.

molf
fonte
2
Não se confunda com variáveis ​​de sessão, que possuem a abreviação SET @@a = 'test';, cf. dev.mysql.com/doc/refman/5.1/en/set-statement.html
RobM
@ RobM, Eles são chamados de variáveis ​​do sistema , não variáveis ​​de sessão.
Pacerier
1
@ Pacerier: Estou lendo os documentos errado? "" "Para indicar explicitamente que uma variável é uma variável de sessão, anteceda seu nome por SESSION, @@ session. Ou @@." ""
RobM
5
@ RobM, você está lendo errado. Leia o parágrafo inteiro, não apenas o parágrafo no marcador. Simplificando, existem dois tipos de variáveis ​​de sessão: 1) variáveis ​​de sessão definidas pelo usuário e 2)  variáveis ​​de sessão definidas pelo sistema . Você não pode definir uma variável de sessão definida pelo usuário usando @@. Por exemplo, set@@my_var=1, set@@session.my_var=1e set session my_var=1não iria funcionar porque my_varnão é um sistema variável, enquanto que podemos fazer set@@big_tables=1, set@@session.big_tables=1e set session big_tables=1porque big_tablesé uma variável do sistema.
Pacerier
1
@GovindRai: Na resposta de Quassnoi, var2é uma variável sem @prefixo, mas não é uma variável do sistema: é uma variável de procedimento. Isso é permitido porque está em um procedimento armazenado (também conhecido como programa armazenado). Fora dos procedimentos armazenados, uma variável sem @é uma variável do sistema.
LarsH # 14/16
10

O MSSQL exige que as variáveis ​​dentro dos procedimentos sejam DECLAREd e as pessoas usem a sintaxe @Variable (DECLARE @TEXT VARCHAR (25) = 'texto'). Além disso, o MS permite declarações dentro de qualquer bloco do procedimento, ao contrário do mySQL, que requer todos os DECLAREs na parte superior.

Embora seja bom na linha de comando, acho que usar o "set = @variable" nos procedimentos armazenados no mySQL é arriscado. Não há escopo e variáveis ​​vivem além dos limites do escopo. É semelhante às variáveis ​​declaradas no JavaScript sem o prefixo "var", que são o espaço de nomes global e criam colisões e substituições inesperadas.

Espero que as pessoas boas do mySQL permitam DECLARE @Variable em vários níveis de bloco dentro de um procedimento armazenado. Observe o @ (no sinal). O prefixo do sinal @ ajuda a separar os nomes das variáveis ​​dos nomes das colunas da tabela - pois geralmente são os mesmos. Obviamente, sempre é possível adicionar um prefixo "v" ou "l_", mas o sinal @ é uma maneira prática e sucinta de fazer com que o nome da variável corresponda à coluna da qual você pode extrair os dados sem atrapalhá-los.

O MySQL é novo nos procedimentos armazenados e eles fizeram um bom trabalho em sua primeira versão. Será um prazer ver onde eles assumem a forma aqui e observar os aspectos do idioma do servidor amadurecerem.

Xybo
fonte
3

Em princípio, eu uso UserDefinedVariables (anexado com @) em Procedimentos armazenados. Isso facilita a vida, especialmente quando eu preciso dessas variáveis ​​em dois ou mais procedimentos armazenados. Apenas quando eu preciso de uma variável apenas dentro do ONE Stored Procedure, utilizo uma variável de sistema (sem o prefixo @).

@ Xybo: Não entendo por que o uso de variáveis ​​em StoredProcedures deve ser arriscado. Você poderia explicar um pouco mais o "escopo" e os "limites" (para mim como um novato)?

Pedro
fonte
3
Isso viola os princípios básicos de engenharia de software. Por favor, não escreva outra linha de código até saber exatamente o que é escopo, e por que usar variáveis ​​globais geralmente é uma péssima idéia. Quando participei de 101 aulas de programação, lembro-me de usar um global para praticamente qualquer coisa que resultaria em um "F" automático. Existem exceções especiais, mas como regra geral - simplesmente não faça isso!
precisa saber é o seguinte
Por quê? - Variáveis ​​@ são absolutamente comuns em todos os livros do MySQL.
Peter Peter
Claro, em um script "simples" sem chamadas de funções, procedimentos, gatilhos, etc. e se você estiver executando apenas esse script simples ou um conjunto limitado de comandos e finalizando a sessão (destruindo assim os seus globais). Nesse caso, vá em frente e use-os, se quiser. Mas NÃO os use dentro de uma função! Se você simplesmente pesquisar no Google variáveis ​​globais ou escopo, encontrará instantaneamente um amplo suporte à ideia de que elas são universalmente desaprovadas. Aqui está um ponto de partida: wiki.c2.com/?GlobalVariablesAreBad ou para uma explicação mais geral: en.wikipedia.org/wiki/Global_variable
BuvinJ
2
No MySQL, as variáveis ​​@ são globais. Isto é facilmente confirmado. Defina um fora de uma função e avalie-o dentro de um. Por outro lado, defina um dentro de uma função e avalie-o fora dela. Você verá que a função não protege o escopo de tal. Eles pisam nos dedos um do outro.
precisa saber é o seguinte
1
Usando a terminologia do MySQL, as @@GLOBALvariáveis ​​são ainda mais "globais" e insidiosas. Eles atravessam sessões! @variablestêm "escopo de sessão", portanto, pelo menos eles permanecem confinados dessa maneira. No entanto, em qualquer idioma normal, é o que você chama de escopo "global" (quando eles cruzam funções, etc.). O conceito MySQL de "global" talvez deva ser chamado de "universal", na medida em que se estende além dos limites do processo que o executa. Um "global" normalmente não pode fazer isso em uma linguagem padrão, pois os processos não compartilham espaço de memória. Isso decorre da tendência persistente (vs volátil) do SQL.
precisa saber é o seguinte