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?
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?
Respostas:
MySQL
tem 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 SET
instruçã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 NULL
cada 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.)
SELECT @@version;
por exemplo. Essa também é uma razão pela qual o uso DELIMITER @@
não é realmente uma boa ideia.
@
vs não?
:=
e =
, e isso :=
funciona como um operador de atribuição de variáveis em qualquer lugar, enquanto =
apenas funciona dessa maneira em SET
declaraçõ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.
No MySQL, @variable
indica 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.
SET @@a = 'test';
, cf. dev.mysql.com/doc/refman/5.1/en/set-statement.html
@@
. Por exemplo, set@@my_var=1
, set@@session.my_var=1
e set session my_var=1
não iria funcionar porque my_var
não é um sistema variável, enquanto que podemos fazer set@@big_tables=1
, set@@session.big_tables=1
e set session big_tables=1
porque big_tables
é uma variável do sistema.
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.
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.
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)?
@@GLOBAL
variáveis são ainda mais "globais" e insidiosas. Eles atravessam sessões! @variables
tê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.