JSON_SCHEMA_VALIDATION_REPORT

La función JSON_SCHEMA_VALIDATION_REPORT es el complemento de JSON_SCHEMA_VALID. Mientras que JSON_SCHEMA_VALID solo dice si un documento pasa o no la validación, JSON_SCHEMA_VALIDATION_REPORT devuelve un informe detallado que explica exactamente qué regla del esquema se ha violado y en qué parte del documento. Esta información es fundamental para depurar datos inválidos, generar mensajes de error claros y auditar la calidad de los datos.

Sintaxis

JSON_SCHEMA_VALIDATION_REPORT(esquema, documento)

La función recibe los mismos argumentos que JSON_SCHEMA_VALID: un esquema JSON Schema y un documento JSON a validar. Devuelve un objeto JSON con el resultado del informe.

Comportamiento básico

Cuando un documento es válido, el informe es muy simple:

SET @esquema = '{
    "type": "object",
    "required": ["nombre", "precio"],
    "properties": {
        "nombre": {"type": "string"},
        "precio": {"type": "number", "minimum": 0}
    }
}';
 
SELECT JSON_PRETTY(
    JSON_SCHEMA_VALIDATION_REPORT(@esquema, '{"nombre": "iPhone 15 Pro", "precio": 1299.99}')
) AS informe;
{
  "valid": true
}

El informe solo contiene la propiedad "valid" con valor true. No hay errores que reportar.

Cuando el documento es inválido, el informe incluye detalles del error:

SELECT JSON_PRETTY(
    JSON_SCHEMA_VALIDATION_REPORT(@esquema, '{"nombre": "Cable USB-C", "precio": -5}')
) AS informe;
{
  "valid": false,
  "reason": "The JSON document location '#/precio' failed requirement 'minimum' at JSON Schema location '#/properties/precio'",
  "schema-location": "#/properties/precio",
  "document-location": "#/precio",
  "schema-failed-keyword": "minimum"
}

El informe proporciona cinco campos clave cuando la validación falla:

La propiedad valid indica false cuando el documento no cumple el esquema. La propiedad reason es un mensaje legible en inglés que describe el error. La propiedad schema-location indica en qué parte del esquema está la regla violada. La propiedad document-location señala qué parte del documento causó el error. La propiedad schema-failed-keyword identifica la palabra clave del esquema que falló (en este caso "minimum").

Estructura del informe de error

Veamos diferentes tipos de errores y cómo se reportan:

Propiedad requerida faltante

SELECT JSON_PRETTY(
    JSON_SCHEMA_VALIDATION_REPORT(@esquema, '{"nombre": "MacBook Air M3"}')
) AS informe;
{
  "valid": false,
  "reason": "The JSON document location '#' failed requirement 'required' at JSON Schema location '#'",
  "schema-location": "#",
  "document-location": "#",
  "schema-failed-keyword": "required"
}

El schema-failed-keyword es "required" y la ubicación apunta a la raíz del documento (#), indicando que al objeto raíz le falta una propiedad obligatoria.

Tipo de dato incorrecto

SELECT JSON_PRETTY(
    JSON_SCHEMA_VALIDATION_REPORT(@esquema, '{"nombre": 42, "precio": 100}')
) AS informe;
{
  "valid": false,
  "reason": "The JSON document location '#/nombre' failed requirement 'type' at JSON Schema location '#/properties/nombre'",
  "schema-location": "#/properties/nombre",
  "document-location": "#/nombre",
  "schema-failed-keyword": "type"
}

El nombre debería ser un string pero se proporcionó un número. La ubicación del documento señala exactamente la propiedad problemática: #/nombre.

Valor fuera de rango

SET @esquema_rango = '{
    "type": "object",
    "properties": {
        "edad": {"type": "integer", "minimum": 18, "maximum": 120},
        "descuento": {"type": "number", "minimum": 0, "maximum": 100}
    }
}';
 
SELECT JSON_PRETTY(
    JSON_SCHEMA_VALIDATION_REPORT(@esquema_rango, '{"edad": 15, "descuento": 50}')
) AS informe;
{
  "valid": false,
  "reason": "The JSON document location '#/edad' failed requirement 'minimum' at JSON Schema location '#/properties/edad'",
  "schema-location": "#/properties/edad",
  "document-location": "#/edad",
  "schema-failed-keyword": "minimum"
}

Es importante notar que MySQL reporta solo el primer error encontrado. Si el documento tiene múltiples errores, solo verás el primero en el informe.

Caso práctico: mensajes de error para usuarios

Puedes usar el informe de validación para generar mensajes de error comprensibles en tu aplicación:

CREATE TABLE productos (
    id INT AUTO_INCREMENT PRIMARY KEY,
    nombre VARCHAR(200),
    especificaciones JSON
);
 
SET @esquema_producto = '{
    "type": "object",
    "required": ["color", "peso"],
    "properties": {
        "color": {"type": "string", "minLength": 1},
        "peso": {"type": "number", "minimum": 0.001},
        "garantia_meses": {"type": "integer", "minimum": 0, "maximum": 120},
        "dimensiones": {
            "type": "object",
            "properties": {
                "alto": {"type": "number", "minimum": 0},
                "ancho": {"type": "number", "minimum": 0},
                "profundidad": {"type": "number", "minimum": 0}
            }
        }
    }
}';
SELECT
    doc AS documento_enviado,
    JSON_SCHEMA_VALIDATION_REPORT(@esquema_producto, doc)->>'$.valid' AS valido,
    JSON_SCHEMA_VALIDATION_REPORT(@esquema_producto, doc)->>'$.schema-failed-keyword' AS regla_violada,
    JSON_SCHEMA_VALIDATION_REPORT(@esquema_producto, doc)->>'$.document-location' AS campo_problematico
FROM (
    SELECT '{"color": "Rojo", "peso": 0.5, "garantia_meses": 24}' AS doc
    UNION ALL SELECT '{"peso": 0.3}'
    UNION ALL SELECT '{"color": "Azul", "peso": -1}'
    UNION ALL SELECT '{"color": "", "peso": 0.1}'
    UNION ALL SELECT '{"color": "Negro", "peso": 0.2, "garantia_meses": 200}'
) datos;
documento_enviadovalidoregla_violadacampo_problematico
{"color": "Rojo", "peso": 0.5, "garantia_meses": 24}trueNULLNULL
{"peso": 0.3}falserequired#
{"color": "Azul", "peso": -1}falseminimum#/peso
{"color": "", "peso": 0.1}falseminLength#/color
{"color": "Negro", "peso": 0.2, "garantia_meses": 200}falsemaximum#/garantia_meses

Cada fila muestra la regla específica que se violó y el campo exacto del documento. Tu aplicación puede traducir estos códigos a mensajes en español: required en # significa "faltan campos obligatorios", minimum en #/peso significa "el peso debe ser positivo", etc.

Caso práctico: auditoría de datos existentes

Cuando migras datos o importas información de fuentes externas, JSON_SCHEMA_VALIDATION_REPORT te ayuda a identificar y categorizar los problemas:

CREATE TABLE importacion_proveedores (
    id INT AUTO_INCREMENT PRIMARY KEY,
    proveedor VARCHAR(100),
    datos_producto JSON
);
 
INSERT INTO importacion_proveedores (proveedor, datos_producto) VALUES
('Proveedor A', '{"sku": "A001", "nombre": "Monitor 27 4K", "precio": 449.99, "stock": 25}'),
('Proveedor A', '{"sku": "A002", "nombre": "Teclado", "precio": 0, "stock": 80}'),
('Proveedor B', '{"sku": "B001", "nombre": "", "precio": 79.99, "stock": 120}'),
('Proveedor B', '{"sku": "B002", "precio": 129.99, "stock": -5}'),
('Proveedor C', '{"sku": "C001", "nombre": "Ratón", "precio": 59.99, "stock": 200}');
SET @esquema_importacion = '{
    "type": "object",
    "required": ["sku", "nombre", "precio", "stock"],
    "properties": {
        "sku": {"type": "string", "minLength": 1},
        "nombre": {"type": "string", "minLength": 1},
        "precio": {"type": "number", "minimum": 0.01},
        "stock": {"type": "integer", "minimum": 0}
    }
}';
 
SELECT
    id,
    proveedor,
    datos_producto->>'$.sku' AS sku,
    CASE
        WHEN JSON_SCHEMA_VALID(@esquema_importacion, datos_producto) = 1 THEN 'OK'
        ELSE CONCAT(
            'Error en ',
            COALESCE(
                JSON_SCHEMA_VALIDATION_REPORT(@esquema_importacion, datos_producto)->>'$.document-location',
                'documento'
            ),
            ' (',
            COALESCE(
                JSON_SCHEMA_VALIDATION_REPORT(@esquema_importacion, datos_producto)->>'$.schema-failed-keyword',
                'desconocido'
            ),
            ')'
        )
    END AS estado_validacion
FROM importacion_proveedores;
idproveedorskuestado_validacion
1Proveedor AA001OK
2Proveedor AA002Error en #/precio (minimum)
3Proveedor BB001Error en #/nombre (minLength)
4Proveedor BB002Error en # (required)
5Proveedor CC001OK

Este informe te permite saber exactamente qué registros tienen problemas y cuál es la naturaleza de cada error, facilitando la comunicación con los proveedores para que corrijan sus datos.

Caso práctico: resumen de errores por tipo

Para tablas grandes, puedes agrupar los errores por tipo para obtener una vista general de la calidad de los datos:

SELECT
    JSON_SCHEMA_VALIDATION_REPORT(@esquema_importacion, datos_producto)->>'$.schema-failed-keyword' AS tipo_error,
    COUNT(*) AS cantidad
FROM importacion_proveedores
WHERE JSON_SCHEMA_VALID(@esquema_importacion, datos_producto) = 0
GROUP BY tipo_error;
tipo_errorcantidad
minimum1
minLength1
required1

Este resumen indica que hay un registro con valor por debajo del mínimo, uno con texto demasiado corto y uno al que le faltan campos obligatorios. En una tabla con miles de registros, este tipo de análisis te permite priorizar las correcciones.

Caso práctico: validación con objetos anidados

El informe señala correctamente la ubicación dentro de estructuras anidadas:

SET @esquema_pedido = '{
    "type": "object",
    "required": ["cliente", "direccion"],
    "properties": {
        "cliente": {"type": "string"},
        "direccion": {
            "type": "object",
            "required": ["calle", "ciudad", "cp"],
            "properties": {
                "calle": {"type": "string", "minLength": 1},
                "ciudad": {"type": "string"},
                "cp": {"type": "string", "minLength": 5, "maxLength": 5}
            }
        }
    }
}';
 
SELECT JSON_PRETTY(
    JSON_SCHEMA_VALIDATION_REPORT(@esquema_pedido, '{
        "cliente": "María García",
        "direccion": {"calle": "Gran Vía 28", "ciudad": "Madrid", "cp": "123"}
    }')
) AS informe;
{
  "valid": false,
  "reason": "The JSON document location '#/direccion/cp' failed requirement 'minLength' at JSON Schema location '#/properties/direccion/properties/cp'",
  "schema-location": "#/properties/direccion/properties/cp",
  "document-location": "#/direccion/cp",
  "schema-failed-keyword": "minLength"
}

La ubicación #/direccion/cp señala exactamente que el campo cp dentro del objeto direccion tiene un valor demasiado corto (3 caracteres cuando el mínimo es 5). La ruta del esquema también es precisa, apuntando a la definición de cp dentro de direccion.

Manejo de NULL

Si cualquiera de los argumentos es NULL, la función devuelve NULL:

SELECT
    JSON_SCHEMA_VALIDATION_REPORT(NULL, '{"clave": "valor"}') AS esquema_null,
    JSON_SCHEMA_VALIDATION_REPORT('{"type": "object"}', NULL) AS documento_null;
esquema_nulldocumento_null
NULLNULL

Si el documento es válido contra un esquema vacío, el informe siempre es positivo:

SELECT JSON_SCHEMA_VALIDATION_REPORT('{}', '{"cualquier": "cosa"}') AS informe;
informe
{"valid": true}

Combinación con otras funciones

Puedes extraer campos específicos del informe para crear reportes más estructurados:

SELECT
    id,
    proveedor,
    CASE
        WHEN r->>'$.valid' = 'true' THEN 'Valido'
        ELSE 'Invalido'
    END AS estado,
    r->>'$.schema-failed-keyword' AS keyword,
    REPLACE(r->>'$.document-location', '#/', '') AS campo
FROM (
    SELECT
        id,
        proveedor,
        JSON_SCHEMA_VALIDATION_REPORT(@esquema_importacion, datos_producto) AS r
    FROM importacion_proveedores
) validacion
WHERE r->>'$.valid' = 'false';
idproveedorestadokeywordcampo
2Proveedor AInvalidominimumprecio
3Proveedor BInvalidominLengthnombre
4Proveedor BInvalidorequired

La columna campo se obtiene eliminando el prefijo #/ de la ubicación del documento, produciendo nombres de campo legibles. Para el error required, el campo queda vacío porque la ubicación apunta a la raíz del documento.

Es importante recordar que JSON_SCHEMA_VALIDATION_REPORT reporta solo el primer error encontrado. Si un documento tiene múltiples problemas, necesitarás corregir el primer error y volver a validar para descubrir los siguientes. Esto es por diseño: el informe identifica un problema a la vez para que puedas resolverlo de forma iterativa.

Con esto completamos la sección de funciones JSON de MySQL. En la siguiente sección veremos cómo importar y exportar datos.

Escrito por Eduardo Lázaro