DELIMITER
DELIMITER cambia el carácter que MySQL usa para marcar el final de una sentencia. Por defecto es el punto y coma ;, pero al crear procedimientos almacenados necesitas cambiarlo porque el cuerpo del procedimiento contiene puntos y coma internos.
Antes de escribir cualquier procedimiento almacenado, función almacenada o trigger, es imprescindible entender cómo funciona DELIMITER y por qué es necesario. Sin esta pieza, MySQL cortará tu código en el lugar equivocado y obtendrás errores de sintaxis que pueden resultar confusos si no conoces la causa.
El problema
Cuando trabajas con el cliente de línea de comandos de MySQL (o cualquier herramienta que envíe sentencias al servidor), el programa necesita saber dónde termina una sentencia y dónde empieza la siguiente. Por defecto, el punto y coma ; es ese marcador: cada vez que el cliente encuentra un ;, envía todo lo acumulado hasta ese punto al servidor para su ejecución.
Esto funciona perfectamente para sentencias individuales, pero se convierte en un problema cuando intentas crear un procedimiento almacenado. El cuerpo del procedimiento contiene sentencias SQL con sus propios puntos y coma, y el cliente no tiene forma de saber si un ; es parte del procedimiento o el final de la sentencia CREATE:
-- Esto FALLA porque MySQL corta en el primer ;
CREATE PROCEDURE test()
BEGIN
SELECT 1; -- MySQL piensa que aquí termina
SELECT 2;
END;El cliente envía CREATE PROCEDURE test() BEGIN SELECT 1 al servidor, que es una sentencia incompleta. El resultado es un error de sintaxis que no tiene nada que ver con tu código SQL, sino con cómo el cliente interpreta los delimitadores.
La solución: DELIMITER
La solución es decirle al cliente "temporalmente, deja de usar ; como fin de sentencia y usa otra cosa en su lugar". Eso es exactamente lo que hace DELIMITER:
-- Cambiar el delimitador a //
DELIMITER //
CREATE PROCEDURE test()
BEGIN
SELECT 1; -- Ahora ; no termina la sentencia
SELECT 2;
END //
-- Restaurar el delimitador original
DELIMITER ;Al cambiar el delimitador a //, el cliente ya no corta en los ; internos del procedimiento. Solo envía la sentencia completa al servidor cuando encuentra // después del END. Una vez creado el procedimiento, se restaura el delimitador original para poder seguir trabajando con normalidad.
Es un comando del cliente, no de SQL
Un detalle importante que genera confusión: DELIMITER no es una sentencia SQL. No la ejecuta el servidor MySQL, sino el programa cliente (mysql, MySQL Workbench, DBeaver, etc.). Esto tiene varias consecuencias prácticas:
- No puedes usar
DELIMITERdentro de un procedimiento almacenado. - No aparece en los dumps de
mysqldump(que usa su propia lógica de delimitadores). - Algunas herramientas gráficas como phpMyAdmin o MySQL Workbench tienen un campo separado para configurar el delimitador, y en esos casos puede que no necesites escribir
DELIMITERexplícitamente. - Si ejecutas SQL desde un archivo con
SOURCE, el delimitador del archivo se aplica correctamente.
Delimitadores comunes
Puedes usar cualquier secuencia de caracteres que no aparezca en el cuerpo del procedimiento. Las opciones más habituales son:
| Delimitador | Ejemplo |
|---|---|
// | Más común y legible |
$$ | Muy popular, especialmente en PostgreSQL |
;; | Doble punto y coma |
La convención más extendida en la comunidad MySQL es //. Es visualmente limpio, fácil de teclear y prácticamente imposible que aparezca en el cuerpo de un procedimiento. $$ es la segunda opción más popular y es la que encontrarás en muchos tutoriales y herramientas.
Evita usar delimitadores que puedan confundirse con operadores SQL o caracteres especiales. Por ejemplo, no uses | (operador OR a nivel de bits), # (inicio de comentario en MySQL) o -- (inicio de comentario en SQL estándar).
Ejemplo práctico
DELIMITER //
CREATE PROCEDURE productos_por_categoria(IN cat_id INT)
BEGIN
SELECT nombre, precio
FROM productos
WHERE categoria_id = cat_id
ORDER BY precio DESC;
END //
DELIMITER ;-- Llamar al procedimiento
CALL productos_por_categoria(6);| nombre | precio |
|---|---|
| iPhone 15 Pro | 1299.99 |
| Samsung Galaxy S24 | 899.99 |
| Google Pixel 8 | 699.00 |
| Xiaomi 14 | 599.99 |
Observa el flujo: primero cambias el delimitador, luego defines el procedimiento usando // para terminar la sentencia, y finalmente restauras el ; para que las siguientes sentencias (como el CALL) funcionen con normalidad.
Reglas importantes
Siempre restaura el delimitador. Si olvidas el DELIMITER ; final, todas las sentencias que escribas después seguirán usando // como delimitador, lo que provocará errores inesperados. Es un error frecuente en principiantes y puede ser difícil de diagnosticar si no lo tienes en mente.
No dejes espacio extra después de END. El delimitador debe ir pegado o con un solo espacio después de END. Es decir, END // o END//, pero no END ; // (que MySQL interpretaría como dos sentencias separadas).
El delimitador es por sesión. Cada conexión al servidor tiene su propio delimitador. Si cambias el delimitador en una ventana de tu cliente, no afecta a otras ventanas o conexiones.
En herramientas gráficas, verifica la configuración. MySQL Workbench, por ejemplo, tiene una opción en las preferencias para configurar el delimitador de scripts. phpMyAdmin tiene un campo "Delimiter" debajo del área de texto SQL. En estos casos, puede que no necesites el comando DELIMITER en tu script.
Múltiples procedimientos
Cuando necesitas crear varios procedimientos en un mismo script, no es necesario cambiar el delimitador para cada uno. Puedes envolver todos los CREATE dentro de un solo bloque DELIMITER:
DELIMITER //
CREATE PROCEDURE proc_a()
BEGIN
SELECT 'Procedimiento A';
END //
CREATE PROCEDURE proc_b()
BEGIN
SELECT 'Procedimiento B';
END //
DELIMITER ;Esto es habitual en scripts de migración o de inicialización de base de datos, donde se crean decenas de procedimientos de una vez. Un solo DELIMITER // al inicio y un solo DELIMITER ; al final.
Limpieza
DROP PROCEDURE IF EXISTS test;
DROP PROCEDURE IF EXISTS productos_por_categoria;
DROP PROCEDURE IF EXISTS proc_a;
DROP PROCEDURE IF EXISTS proc_b;En el siguiente artículo veremos la sintaxis completa de CREATE PROCEDURE con todas sus opciones.
Escrito por Eduardo Lázaro
