HOWTO · MySQL
Cómo declarar y usar variables en MySQL
Aprende cuándo usar variables de sesión, variables locales DECLARE o variables del sistema en MySQL, con SET, SELECT ... INTO, reglas de ámbito y ejemplos probados.
En esta página
MySQL tiene tres mecanismos de variables. Usa una variable de sesión definida por el usuario, como @limit, cuando varias sentencias de una conexión necesitan compartir un valor. Usa una variable local sin @ en un procedimiento, función, trigger o evento almacenado. Usa una variable del sistema como @@SESSION.sql_mode para inspeccionar o configurar el servidor o una conexión.
La diferencia principal es que DECLARE no es una sentencia general para una ventana SQL. Solo se permite dentro de un bloque BEGIN ... END y debe aparecer antes de las demás sentencias de ese bloque. Para un script rápido, empieza con SET @name = value;. Las palabras clave DECLARE, SET, SELECT ... INTO, BEGIN ... END, SESSION y GLOBAL se mantienen sin traducir en el SQL.
Elegir la variable de MySQL correcta
| Necesidad | Sintaxis | Ámbito |
|---|---|---|
| Reutilizar un valor entre sentencias SQL normales | SET @name = value; |
Sesión del cliente actual |
| Guardar un valor dentro de un programa almacenado | DECLARE name type [DEFAULT value]; |
Bloque BEGIN ... END |
| Leer o cambiar una configuración del servidor | @@SESSION.name o @@GLOBAL.name |
Una sesión o el servidor |
Estas formas no son intercambiables. En particular, DECLARE @name INT no es la sintaxis de una variable local, y DECLARE name INT falla como sentencia independiente fuera de un programa almacenado.
Usar una variable definida por el usuario en una sesión SQL
Las variables definidas por el usuario comienzan con @. No necesitas declararlas antes de usarlas. Asígnales un literal o una expresión con SET y úsalas después:
SET @low = 2, @high = 4;
SELECT n FROM demo_numbers WHERE n BETWEEN @low AND @high ORDER BY n;
Las variables son privadas de la conexión actual. Otra conexión no puede usarlas y desaparecen cuando termina la conexión. Una variable no inicializada produce NULL, así que inicialízala al principio de un script reutilizable.
SET es la forma más clara de asignar valores. MySQL también acepta := dentro de una sentencia SET:
SET @total = 10;
SET @total := @total + 5;
SELECT @total;
El tipo de la variable depende del valor asignado, no de una cláusula de tipo. Puede contener números, decimales, cadenas, cadenas binarias o NULL; usa valores compatibles y conversiones explícitas cuando cambie el tipo.
Cargar un resultado con SELECT ... INTO
Usa SELECT ... INTO cuando el valor proviene de una consulta. El número de variables destino debe coincidir con el número de expresiones seleccionadas:
SELECT COUNT(*) INTO @number_of_rows
FROM demo_numbers;
SELECT @number_of_rows;
La consulta debe estar diseñada para devolver una fila. COUNT(*) lo hace de forma natural; una búsqueda por clave única también es adecuada. Si puede devolver varias filas, elige una fila de forma determinista con ORDER BY y LIMIT 1.
Una variable no puede sustituir un nombre de tabla o columna. SET @table_name = 'demo_numbers'; SELECT * FROM @table_name; no sustituye el nombre de la tabla. Para SQL dinámico, construye una sentencia para PREPARE y valida los identificadores proporcionados por la aplicación.
MySQL 9.7 todavía permite asignar variables fuera de SET por compatibilidad, pero marca ese comportamiento para eliminarlo en el futuro. Prefiere SET y SELECT ... INTO a expresiones como SELECT @n := n.
Declarar una variable local en un programa almacenado
Las variables locales usan DECLARE sin @ y necesitan un tipo de datos de MySQL. Puedes indicar DEFAULT; de lo contrario, el valor inicial es NULL. Coloca las declaraciones al principio del bloque BEGIN ... END, antes de cualquier sentencia ejecutable. Son visibles en ese bloque y en bloques anidados, pero no después.
El siguiente procedimiento usa un parámetro de entrada, una variable local y un parámetro de salida. Los comandos DELIMITER son del cliente mysql: permiten enviar el cuerpo, que contiene punto y coma, como una sola sentencia 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 solo existe mientras se ejecuta el procedimiento. El parámetro OUT vuelve a través de la variable de sesión suministrada a CALL. Si una consulta devuelve varias columnas, usa un destino por expresión y trata explícitamente el caso sin coincidencias.
Puedes declarar varias variables del mismo tipo en una sentencia, aunque las declaraciones separadas suelen ser más fáciles de mantener:
DECLARE quantity, retries INT DEFAULT 0;
DECLARE label VARCHAR(100) DEFAULT 'pending';
DECLARE también define condiciones, cursores y manejadores. El orden importa: variables y condiciones antes que cursores, y cursores antes que manejadores. Por eso una declaración después de SELECT o SET produce un error de sintaxis.
Entender el límite de filas de SELECT ... INTO
Un destino escalar almacena un valor, no un conjunto de resultados arbitrario. La siguiente consulta devuelve intencionadamente tres filas y falla con el error 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
Limita la consulta a una fila conocida, agrega el resultado o deja que siga siendo un conjunto de filas. LIMIT 1 solo es correcto con un orden intencionado:
SELECT n INTO @selected
FROM demo_numbers
ORDER BY n DESC
LIMIT 1;
La misma regla de una fila se aplica a una variable local. Si una rutina puede no encontrar filas, inicializa la variable deliberadamente y usa un manejador NOT FOUND o una comprobación de existencia cuando sea necesario.
Inspeccionar o establecer una variable del sistema de MySQL
Las variables del sistema configuran el servidor o una conexión. Inspecciónalas con SHOW VARIABLES o con @@:
SHOW SESSION VARIABLES LIKE 'sql_mode';
SELECT @@SESSION.sql_mode, @@GLOBAL.sql_mode;
Sin una palabra de ámbito, SHOW VARIABLES usa la sesión actual. Un valor de sesión afecta solo a esa conexión; un valor global suele inicializar conexiones nuevas. Cambiar una variable global requiere el privilegio adecuado y que la variable sea modificable.
SET SESSION sql_mode = 'STRICT_TRANS_TABLES';
-- A privileged server administrator may use an appropriate GLOBAL setting.
-- SET GLOBAL sql_mode = 'STRICT_TRANS_TABLES';
La sentencia global comentada no forma parte de la fixture ejecutable: su éxito depende de los privilegios y de la visibilidad y mutabilidad de la variable.
Solucionar una variable que no funciona
- Si se rechaza
DECLARE, comprueba que esté dentro deBEGIN ... ENDy antes de todas las sentencias ejecutables. En un script normal, usaSET @name = value. - Si aparece
NULLinesperadamente, inicializa la variable y revisa la expresión o la búsqueda de origen. - Si
SELECT ... INTOinforma del error 1172, haz que devuelva exactamente una fila o conserva el resultado como filas. - Que otra conexión no vea
@namees normal: las variables son específicas de la sesión. - Si falla
@@GLOBAL.name, comprueba la mutabilidad de la variable y tus privilegios administrativos.
La fixture de éxito asigna variables de sesión, las usa en un filtro, declara una variable local en un procedimiento y devuelve su parámetro de salida. La fixture de límite verifica el diagnóstico de varias filas de SELECT ... INTO; ambas usan un servidor MySQL temporal.
Consulta la referencia de variables definidas por el usuario de MySQL, la referencia de DECLARE local y la referencia de asignación con SET para la sintaxis completa.