MySQL: @variable vs. variable. ¿Cual es la diferencia?

501

En otra pregunta que publiqué, alguien me dijo que hay una diferencia entre:

@variable

y:

variable

en MySQL También mencionó cómo MSSQL tiene alcance por lotes y MySQL tiene alcance de sesión. ¿Alguien puede dar más detalles sobre esto por mí?

aarona
fuente
1
Estoy familiarizado con MsSQL, por lo que nunca pensé en hacer esa pregunta. ¡Las respuestas proporcionadas aquí me dieron pistas sobre algo sobre lo que no tenía IDEA! Thx ..
Ken

Respuestas:

624

MySQLtiene el concepto de variables definidas por el usuario .

Son variables poco escritas que pueden inicializarse en algún lugar de una sesión y mantener su valor hasta que finalice la sesión.

Están antepuestos con un @signo, como este:@var

Puede inicializar esta variable con una SETdeclaración o dentro de una consulta:

SET @var = 1

SELECT @var2 := 2

Cuando desarrolla un procedimiento almacenado en MySQL, puede pasar los parámetros de entrada y declarar las variables locales:

DELIMITER //

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

DELIMITER ;

Estas variables no se anteponen con ningún prefijo.

La diferencia entre una variable de procedimiento y una variable definida por el usuario específica de sesión es que la variable de procedimiento se reinicia NULLcada vez que se llama al procedimiento, mientras que la variable específica de sesión no es:

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 puede ver, var2(variable de procedimiento) se reinicia cada vez que se llama al procedimiento, mientras que @var2(variable específica de la sesión) no.

(Además de las variables definidas por el usuario, MySQL también tiene algunas "variables del sistema" predefinidas, que pueden ser "variables globales" como @@global.port"variables de sesión" como @@session.sql_mode; estas "variables de sesión" no están relacionadas con las definidas por el usuario específicas de la sesión variables.)

Quassnoi
fuente
43
También tenga en cuenta que hay variables globales disponibles: consulte, SELECT @@version;por ejemplo. Esta es también una razón por la cual usar DELIMITER @@no es realmente una buena idea.
Mchl
13
hace nuevas preguntas para los recién llegados ... ¿hay alguna diferencia entre "var = var" y "var: = var" como en su ejemplo?
confiq
13
@confiq: no hay ninguno.
Quassnoi
10
Otra pregunta para un recién llegado. ¿Cuándo se recomienda usar @vs no?
pixelfreak
73
@confiq, @Quassnoi: hay una diferencia significativa entre :=y =, y es que :=funciona como un operador de asignación variable en todas partes, mientras que =solo funciona de esa manera en las SETdeclaraciones, y es un operador de comparación en todas partes. Por SELECT @var = 1 + 1;lo tanto , dejará @var sin cambios y devolverá un valor booleano (1 o 0 según el valor actual de @var), mientras SELECT @var := 1 + 1;que cambiará @var a 2 y devolverá 2.
Dewi Morgan
71

En MySQL, @variableindica una variable definida por el usuario . Puedes definir el tuyo.

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

Fuera de los programas almacenados, a variable, sin @, es una variable del sistema , que no puede definir usted mismo.

El alcance de esta variable es toda la sesión. Eso significa que mientras exista su conexión con la base de datos, la variable aún puede usarse.

Esto está en contraste con MSSQL, donde la variable solo estará disponible en el lote actual de consultas (procedimiento almacenado, secuencia de comandos u otro). No estará disponible en un lote diferente en la misma sesión.

molf
fuente
2
No debe confundirse con las variables de sesión, que tienen la abreviatura SET @@a = 'test';, cf. dev.mysql.com/doc/refman/5.1/en/set-statement.html
RobM
@RobM, se denominan variables del sistema , no variables de sesión.
Pacerier
1
@Pacerier: ¿Estoy leyendo mal los documentos? "" "Para indicar explícitamente que una variable es una variable de sesión, preceda su nombre por SESSION, @@ session. O @@." ""
RobM
55
@RobM, lo estás leyendo mal. Lea todo el párrafo, no solo el párrafo dentro de la viñeta. En pocas palabras, hay dos tipos de variables de sesión: 1) variables de sesión definidas por el usuario y 2)  variables de sesión definidas por el sistema . No puede establecer una variable de sesión definida por el usuario mediante @@. Por ejemplo, set@@my_var=1, set@@session.my_var=1, y set session my_var=1que no funciona porque my_varno es un sistema de variables, mientras que nosotros podemos hacer set@@big_tables=1, set@@session.big_tables=1y set session big_tables=1porque big_tableses una variable del sistema.
Pacerier
1
@GovindRai: En la respuesta de Quassnoi, var2es una variable sin @prefijo, pero no es una variable del sistema: es una variable de procedimiento. Esto está permitido porque está en un procedimiento almacenado (también conocido como programa almacenado). Fuera de los procedimientos almacenados, una variable sin @es una variable del sistema.
LarsH
10

MSSQL requiere que las variables dentro de los procedimientos se DECLAREn y la gente use la sintaxis @Variable (DECLARE @TEXT VARCHAR (25) = 'text'). Además, MS permite declaraciones dentro de cualquier bloque en el procedimiento, a diferencia de mySQL que requiere todos los DECLAROS en la parte superior.

Si bien es bueno en la línea de comandos, creo que usar el "set = @variable" dentro de los procedimientos almacenados en mySQL es arriesgado. No hay alcance y las variables viven a través de los límites del alcance. Esto es similar a las variables en JavaScript que se declaran sin el prefijo "var", que luego son el espacio de nombres global y crean colisiones y sobrescrituras inesperadas.

Espero que las buenas personas en mySQL permitan DECLARE @Variable en varios niveles de bloque dentro de un procedimiento almacenado. Observe la @ (en el signo). El prefijo de signo @ ayuda a separar los nombres de las variables de los nombres de las columnas de la tabla, ya que a menudo son los mismos. Por supuesto, siempre se puede agregar un prefijo "v" o "l_", pero el signo @ es una forma práctica y sucinta de hacer que el nombre de la variable coincida con la columna de la que podría estar extrayendo los datos sin bloquearla.

MySQL es nuevo en los procedimientos almacenados y han hecho un buen trabajo para su primera versión. Será un placer ver dónde lo toman aquí y ver cómo maduran los aspectos del lenguaje del lado del servidor.

Xybo
fuente
3

En principio, uso UserDefinedVariables (antepuesto con @) dentro de Procedimientos almacenados. Esto facilita la vida, especialmente cuando necesito estas variables en dos o más procedimientos almacenados. Justo cuando necesito una variable solo dentro de UN procedimiento almacenado, entonces uso una variable del sistema (sin anteponer @).

@Xybo: No entiendo por qué usar @variables en StoredProcedures debería ser riesgoso. ¿Podría explicar un poco más el "alcance" y los "límites" (para mí como un novato)?

Peter
fuente
3
Esto viola los principios básicos de ingeniería de software. No escriba otra línea de código hasta que sepa exactamente cuál es el alcance, y por qué usar variables globales es generalmente una idea terrible. Cuando tomé 101 clases de programación, como recuerdo, usar un global para casi cualquier cosa resultaría en una "F" automática. Hay excepciones especiales, pero como regla general, ¡simplemente no lo hagas!
BuvinJ
¿Por qué? - @Variables son absolutamente comunes en cada MySQL-Book.
Peter
Claro, en un script "plano" sin llamadas a funciones, procedimientos, disparadores, etc. y si solo va a ejecutar ese simple script o un conjunto limitado de comandos y luego finalizar la sesión (destruyendo así sus globales). En ese caso, adelante y úsalos si quieres. ¡Pero NO los use dentro de una función! Si simplemente busca en Google las variables globales o el alcance, encontrará instantáneamente un amplio respaldo para la idea de que están universalmente mal vistas. Aquí hay un punto de partida: wiki.c2.com/?GlobalVariablesAreBad o para una explicación más general: en.wikipedia.org/wiki/Global_variable
BuvinJ
2
En MySQL, @variables son globales. Esto se confirma fácilmente. Establecer uno fuera de una función y luego evaluarlo dentro de una. Por el contrario, establezca uno dentro de una función y evalúelo fuera de ella. Verá que la función no protege el alcance de la misma. Se pisan los pies el uno al otro.
BuvinJ
1
Usando la terminología de MySQL, las @@GLOBALvariables son aún más "globales" e insidiosas. ¡Cruzan sesiones! @variablestienen "alcance de sesión", por lo que al menos permanecen confinados de esa manera. Sin embargo, en cualquier lenguaje normal, eso es lo que usted llama alcance "global" (cuando cruzan funciones, etc.). El concepto MySQL de "global" quizás debería llamarse "universal", ya que se extiende más allá de los límites del proceso que lo ejecuta. Un "global" normalmente no puede hacer eso en un lenguaje estándar, ya que los procesos no comparten espacio de memoria. Esto se deriva de la tendencia persistente (vs volátil) de SQL.
BuvinJ