JSON_VALID
La función JSON_VALID verifica si una cadena de texto constituye un documento JSON válido según la especificación del estándar. Devuelve 1 si la cadena es JSON válido y 0 si no lo es. Esta función es esencial en situaciones donde recibes datos de fuentes externas (formularios web, APIs, archivos de importación) y necesitas asegurarte de que el contenido es JSON bien formado antes de almacenarlo o procesarlo. También se utiliza frecuentemente en restricciones CHECK para garantizar la integridad de los datos a nivel de la base de datos.
Sintaxis
JSON_VALID(cadena)La función recibe un único argumento, que puede ser una cadena de texto, un valor JSON nativo, o cualquier expresión que produzca un valor de texto. Devuelve 1 si el argumento es JSON válido, 0 si no lo es, y NULL si el argumento es NULL.
Comportamiento básico
Todos los tipos de valores JSON válidos son reconocidos por JSON_VALID:
SELECT
JSON_VALID('{"nombre": "iPhone", "precio": 1299}') AS objeto,
JSON_VALID('[1, 2, 3]') AS array_val,
JSON_VALID('"texto"') AS cadena,
JSON_VALID('42') AS numero,
JSON_VALID('true') AS booleano,
JSON_VALID('null') AS nulo;| objeto | array_val | cadena | numero | booleano | nulo |
|---|---|---|---|---|---|
| 1 | 1 | 1 | 1 | 1 | 1 |
Todos devuelven 1 porque son valores JSON válidos. Ahora veamos cadenas que no son JSON válido:
SELECT
JSON_VALID('esto no es json') AS texto_plano,
JSON_VALID('{nombre: "iPhone"}') AS sin_comillas_clave,
JSON_VALID("{'nombre': 'iPhone'}") AS comillas_simples,
JSON_VALID('{"nombre": "iPhone",}') AS coma_final,
JSON_VALID('') AS cadena_vacia;| texto_plano | sin_comillas_clave | comillas_simples | coma_final | cadena_vacia |
|---|---|---|---|---|
| 0 | 0 | 0 | 0 | 0 |
Cada uno de estos casos falla por una razón diferente. El texto plano no tiene estructura JSON. Las claves sin comillas dobles violan la especificación JSON. Las comillas simples no están permitidas en JSON (solo comillas dobles). Una coma al final de una lista de pares es un error sintáctico. Y una cadena vacía no es un valor JSON válido.
Un error frecuente es confundir una cadena de texto normal con una cadena JSON. En JSON, las cadenas deben estar entre comillas dobles:
SELECT
JSON_VALID('iPhone') AS sin_comillas,
JSON_VALID('"iPhone"') AS con_comillas;| sin_comillas | con_comillas |
|---|---|
| 0 | 1 |
Caso práctico: validación antes de insertar
Cuando recibes datos JSON desde una aplicación externa, es prudente validarlos antes de insertarlos en la base de datos. Imagina un sistema que recibe configuraciones de dispositivos:
CREATE TABLE dispositivos (
id INT PRIMARY KEY AUTO_INCREMENT,
nombre VARCHAR(100),
configuracion JSON
);Supón que recibes estas cadenas desde una API y quieres verificar cuáles son válidas antes de procesarlas:
SELECT
dato,
JSON_VALID(dato) AS es_valido
FROM (
SELECT '{"wifi": true, "bluetooth": true, "brillo": 80}' AS dato
UNION ALL SELECT '{"wifi": true, bluetooth: false}'
UNION ALL SELECT '{"volumen": 75, "modo": "silencio"}'
UNION ALL SELECT '{wifi: true}'
UNION ALL SELECT '{"gps": true, "precisión": "alta"}'
) AS entradas;| dato | es_valido |
|---|---|
| {"wifi": true, "bluetooth": true, "brillo": 80} | 1 |
| {"wifi": true, bluetooth: false} | 0 |
| {"volumen": 75, "modo": "silencio"} | 1 |
| {wifi: true} | 0 |
| {"gps": true, "precisión": "alta"} | 1 |
Solo las tres entradas válidas deberían procesarse. Las otras dos tienen claves sin comillas, un error típico cuando alguien confunde la sintaxis de objetos de JavaScript con JSON estricto.
Caso práctico: restricciones CHECK en tablas
Una de las aplicaciones más potentes de JSON_VALID es su uso en restricciones CHECK para garantizar que los datos insertados o actualizados sean siempre JSON válido. Esto es especialmente relevante cuando la columna es de tipo TEXT o VARCHAR en lugar de JSON:
CREATE TABLE configuraciones (
id INT PRIMARY KEY AUTO_INCREMENT,
clave VARCHAR(100) NOT NULL,
valor TEXT NOT NULL,
CONSTRAINT chk_valor_json CHECK (JSON_VALID(valor))
);Con esta restricción, cualquier intento de insertar un valor que no sea JSON válido será rechazado:
-- Esto funciona correctamente
INSERT INTO configuraciones (clave, valor)
VALUES ('tema', '{"modo": "oscuro", "acento": "#0077b6"}');
-- Esto produce un error por la restricción CHECK
INSERT INTO configuraciones (clave, valor)
VALUES ('idioma', 'español');
-- ERROR 3819 (HY000): Check constraint 'chk_valor_json' is violatedSi usas el tipo de dato JSON nativo en lugar de TEXT, MySQL ya realiza esta validación automáticamente. Sin embargo, la restricción CHECK es útil cuando migras de un sistema que usaba TEXT y quieres añadir la validación sin cambiar el tipo de columna.
Caso práctico: limpieza de datos importados
Cuando importas datos desde archivos CSV o migraciones de otras bases de datos, es habitual que algunos registros tengan datos JSON mal formados. Puedes usar JSON_VALID para identificar y aislar los registros problemáticos:
CREATE TABLE productos_importados (
id INT PRIMARY KEY AUTO_INCREMENT,
nombre VARCHAR(100),
atributos_raw TEXT
);
INSERT INTO productos_importados (nombre, atributos_raw) VALUES
('iPhone 15 Pro', '{"marca": "Apple", "precio": 1299}'),
('Samsung Galaxy S24', '{"marca": "Samsung", precio: 899}'),
('MacBook Air M3', '{"marca": "Apple", "precio": 1399}'),
('Xiaomi 14', '{marca: Xiaomi, precio: 599}'),
('Google Pixel 8', '{"marca": "Google", "precio": 699}');Para separar los registros válidos de los problemáticos:
SELECT
nombre,
atributos_raw,
CASE
WHEN JSON_VALID(atributos_raw) THEN 'Listo para migrar'
ELSE 'Requiere corrección manual'
END AS estado
FROM productos_importados;| nombre | atributos_raw | estado |
|---|---|---|
| iPhone 15 Pro | {"marca": "Apple", "precio": 1299} | Listo para migrar |
| Samsung Galaxy S24 | {"marca": "Samsung", precio: 899} | Requiere corrección manual |
| MacBook Air M3 | {"marca": "Apple", "precio": 1399} | Listo para migrar |
| Xiaomi 14 | {marca: Xiaomi, precio: 599} | Requiere corrección manual |
| Google Pixel 8 | {"marca": "Google", "precio": 699} | Listo para migrar |
Para contar cuántos registros necesitan atención:
SELECT
SUM(JSON_VALID(atributos_raw)) AS validos,
SUM(1 - JSON_VALID(atributos_raw)) AS invalidos,
COUNT(*) AS total
FROM productos_importados;| validos | invalidos | total |
|---|---|---|
| 3 | 2 | 5 |
Y para migrar solo los registros válidos a la tabla definitiva:
INSERT INTO dispositivos (nombre, configuracion)
SELECT nombre, atributos_raw
FROM productos_importados
WHERE JSON_VALID(atributos_raw);Manejo de NULL
Cuando el argumento es NULL, JSON_VALID devuelve NULL, no 0:
SELECT JSON_VALID(NULL) AS resultado;| resultado |
|---|
| NULL |
Esta distinción es importante. Un valor NULL no es lo mismo que un JSON inválido. Si necesitas tratar ambos casos como no válidos, puedes usar COALESCE:
SELECT
COALESCE(JSON_VALID(NULL), 0) AS null_como_invalido,
COALESCE(JSON_VALID('no json'), 0) AS texto_invalido;| null_como_invalido | texto_invalido |
|---|---|
| 0 | 0 |
Combinación con otras funciones
JSON_VALID es el primer paso antes de usar cualquier otra función JSON. Si pasas una cadena no válida a funciones como JSON_EXTRACT o JSON_TYPE, MySQL lanzará un error. Usar JSON_VALID como guarda te permite evitar esos errores:
SELECT
nombre,
CASE
WHEN JSON_VALID(atributos_raw)
THEN JSON_EXTRACT(atributos_raw, '$.marca')
ELSE 'JSON inválido'
END AS marca
FROM productos_importados;| nombre | marca |
|---|---|
| iPhone 15 Pro | "Apple" |
| Samsung Galaxy S24 | JSON inválido |
| MacBook Air M3 | "Apple" |
| Xiaomi 14 | JSON inválido |
| Google Pixel 8 | "Google" |
También puedes combinar JSON_VALID con triggers para registrar intentos de inserción con datos inválidos, o con procedimientos almacenados para implementar lógica de reintento y corrección automática. Validar los datos es siempre el primer paso antes de procesarlos. En el siguiente artículo veremos JSON_MERGE_PATCH para combinar documentos JSON.
Escrito por Eduardo Lázaro
