JSON_UNQUOTE

La función JSON_UNQUOTE toma un valor JSON de tipo string y devuelve su contenido como texto plano SQL, eliminando las comillas dobles que lo envuelven y desescapando los caracteres especiales. Es la operación complementaria de JSON_QUOTE y resulta esencial cuando extraes valores de documentos JSON y necesitas trabajar con ellos como cadenas de texto normales.

Sintaxis

JSON_UNQUOTE(valor_json)

La función recibe un valor JSON de tipo string (con comillas dobles) y devuelve una cadena SQL sin las comillas. Las secuencias de escape JSON se convierten a sus caracteres reales: \" se convierte en ", \\ en \, \n en un salto de línea real, \t en una tabulación, y \uXXXX en el carácter Unicode correspondiente.

Si el argumento no es un string JSON (por ejemplo, un número, booleano o null), la función devuelve el valor tal cual sin modificaciones.

Comportamiento básico

Veamos la diferencia entre un string JSON y su versión sin comillas:

SELECT
    JSON_EXTRACT('{"nombre": "María García"}', '$.nombre') AS con_comillas,
    JSON_UNQUOTE(JSON_EXTRACT('{"nombre": "María García"}', '$.nombre')) AS sin_comillas;
con_comillassin_comillas
"María García"María García

JSON_EXTRACT devuelve el valor tal como está en el JSON: una cadena entrecomillada. JSON_UNQUOTE elimina esas comillas y devuelve el texto plano. Esta diferencia es crucial cuando necesitas comparar, concatenar o mostrar el valor como texto normal.

Con secuencias de escape:

SELECT JSON_UNQUOTE('"Línea 1\\nLínea 2\\tTabulado"') AS resultado;
resultado
Línea 1\nLínea 2\tTabulado

Las secuencias de escape JSON \\n y \\t se convierten en los caracteres especiales correspondientes.

Equivalencia con el operador ->>

MySQL ofrece el operador ->> (también llamado operador de extracción sin comillas) como atajo para JSON_UNQUOTE(JSON_EXTRACT(...)). Las siguientes consultas producen exactamente el mismo resultado:

-- Forma larga
SELECT JSON_UNQUOTE(JSON_EXTRACT(atributos, '$.color')) AS color
FROM productos;
 
-- Forma abreviada equivalente
SELECT atributos->>'$.color' AS color
FROM productos;

Ambas extraen el valor de $.color y eliminan las comillas. El operador ->> es simplemente azúcar sintáctico que hace el código más legible. Compáralo con ->, que es equivalente a solo JSON_EXTRACT (mantiene las comillas):

CREATE TABLE productos (
    id INT AUTO_INCREMENT PRIMARY KEY,
    nombre VARCHAR(200),
    atributos JSON
);
 
INSERT INTO productos (nombre, atributos) VALUES
('iPhone 15 Pro', '{"color": "Titanio Natural", "almacenamiento": "256GB", "precio_original": 1299.99}'),
('MacBook Air M3', '{"color": "Medianoche", "almacenamiento": "512GB", "precio_original": 1399.00}');
SELECT
    nombre,
    atributos->'$.color' AS con_comillas,
    atributos->>'$.color' AS sin_comillas
FROM productos;
nombrecon_comillassin_comillas
iPhone 15 Pro"Titanio Natural"Titanio Natural
MacBook Air M3"Medianoche"Medianoche

En la práctica, ->> es la forma más habitual de extraer valores de texto de columnas JSON, ya que casi siempre necesitas el texto plano.

Cuándo es necesario JSON_UNQUOTE

No siempre necesitas JSON_UNQUOTE. Si extraes un valor numérico o booleano con JSON_EXTRACT, el resultado ya es utilizable sin comillas:

SELECT
    JSON_EXTRACT('{"precio": 1299.99}', '$.precio') AS precio_json,
    JSON_UNQUOTE(JSON_EXTRACT('{"precio": 1299.99}', '$.precio')) AS precio_unquote;
precio_jsonprecio_unquote
1299.991299.99

Para números, el resultado es idéntico. JSON_UNQUOTE es realmente necesario cuando trabajas con strings, ya que las comillas dobles pueden causar problemas al comparar, concatenar o mostrar valores:

-- Sin JSON_UNQUOTE, la comparación puede fallar
SELECT nombre FROM productos
WHERE JSON_EXTRACT(atributos, '$.color') = 'Titanio Natural';
-- No devuelve resultados porque compara '"Titanio Natural"' con 'Titanio Natural'
 
-- Con JSON_UNQUOTE funciona correctamente
SELECT nombre FROM productos
WHERE JSON_UNQUOTE(JSON_EXTRACT(atributos, '$.color')) = 'Titanio Natural';
nombre
iPhone 15 Pro

O de forma más concisa con ->>:

SELECT nombre FROM productos
WHERE atributos->>'$.color' = 'Titanio Natural';

Caso práctico: construir texto a partir de datos JSON

Cuando necesitas construir cadenas que incluyan valores extraídos de JSON, JSON_UNQUOTE (o ->>) es imprescindible:

CREATE TABLE pedidos (
    id INT AUTO_INCREMENT PRIMARY KEY,
    datos JSON
);
 
INSERT INTO pedidos (datos) VALUES
('{"cliente": "María García", "producto": "iPhone 15 Pro", "cantidad": 2, "direccion": {"ciudad": "Madrid", "cp": "28013"}}'),
('{"cliente": "Carlos López", "producto": "MacBook Air M3", "cantidad": 1, "direccion": {"ciudad": "Barcelona", "cp": "08006"}}');
SELECT CONCAT(
    'Pedido para ',
    datos->>'$.cliente',
    ': ',
    datos->>'$.cantidad',
    'x ',
    datos->>'$.producto',
    ' - Envío a ',
    datos->>'$.direccion.ciudad'
) AS resumen
FROM pedidos;
resumen
Pedido para María García: 2x iPhone 15 Pro - Envío a Madrid
Pedido para Carlos López: 1x MacBook Air M3 - Envío a Barcelona

Si hubieras usado -> en lugar de ->>, el resumen incluiría comillas dobles alrededor de cada valor, produciendo un resultado como Pedido para "María García": 2x "iPhone 15 Pro", que no es lo deseado.

Caso práctico: filtros dinámicos con datos JSON

En aplicaciones donde los filtros de búsqueda se comparan con valores JSON, JSON_UNQUOTE asegura comparaciones correctas:

CREATE TABLE configuracion_usuario (
    usuario_id INT PRIMARY KEY,
    nombre VARCHAR(100),
    preferencias JSON
);
 
INSERT INTO configuracion_usuario VALUES
(1, 'María García', '{"idioma": "es", "zona_horaria": "Europe/Madrid", "tema": "oscuro", "moneda": "EUR"}'),
(2, 'John Smith', '{"idioma": "en", "zona_horaria": "America/New_York", "tema": "claro", "moneda": "USD"}'),
(3, 'Carlos López', '{"idioma": "es", "zona_horaria": "America/Mexico_City", "tema": "oscuro", "moneda": "MXN"}');
SELECT nombre, preferencias->>'$.zona_horaria' AS zona
FROM configuracion_usuario
WHERE preferencias->>'$.idioma' = 'es'
  AND preferencias->>'$.tema' = 'oscuro';
nombrezona
María GarcíaEurope/Madrid
Carlos LópezAmerica/Mexico_City

El operador ->> extrae y descomilla los valores, permitiendo compararlos directamente con cadenas SQL normales.

Caso práctico: exportar datos JSON a formato plano

Cuando necesitas generar reportes o exportar datos de columnas JSON a CSV u otros formatos planos, JSON_UNQUOTE asegura que los valores no contengan comillas innecesarias:

SELECT
    p.nombre,
    p.atributos->>'$.color' AS color,
    p.atributos->>'$.almacenamiento' AS almacenamiento,
    CAST(p.atributos->'$.precio_original' AS DECIMAL(10,2)) AS precio
FROM productos p;
nombrecoloralmacenamientoprecio
iPhone 15 ProTitanio Natural256GB1299.99
MacBook Air M3Medianoche512GB1399.00

El resultado tiene columnas con valores limpios, sin comillas JSON, listos para exportar.

Manejo de NULL

Si el argumento es SQL NULL, JSON_UNQUOTE devuelve NULL:

SELECT JSON_UNQUOTE(NULL) AS resultado;
resultado
NULL

Si el valor JSON es el literal null (diferente de SQL NULL), la función devuelve la cadena "null":

SELECT JSON_UNQUOTE('null') AS resultado;
resultado
null

Para valores no string (números, booleanos), la función devuelve la representación en texto del valor:

SELECT
    JSON_UNQUOTE('42') AS numero,
    JSON_UNQUOTE('true') AS booleano,
    JSON_UNQUOTE('null') AS nulo;
numerobooleanonulo
42truenull

En estos casos, JSON_UNQUOTE no tiene efecto visible porque los valores no tienen comillas que eliminar.

Combinación con otras funciones

JSON_UNQUOTE se combina frecuentemente con funciones de cadena para procesar valores extraídos de JSON:

SELECT
    UPPER(datos->>'$.cliente') AS cliente_mayusculas,
    SUBSTRING(datos->>'$.direccion.cp', 1, 2) AS provincia,
    LENGTH(datos->>'$.producto') AS longitud_nombre
FROM pedidos;
cliente_mayusculasprovincialongitud_nombre
MARÍA GARCÍA2813
CARLOS LÓPEZ0814

Las funciones de cadena como UPPER, SUBSTRING y LENGTH trabajan correctamente con los valores descomillados. Si usaras -> en lugar de ->>, LENGTH contaría los caracteres de las comillas como parte de la longitud.

También es habitual combinar JSON_UNQUOTE con LIKE para búsquedas parciales:

SELECT nombre
FROM productos
WHERE atributos->>'$.color' LIKE '%Titanio%';
nombre
iPhone 15 Pro

En el siguiente artículo veremos JSON_SCHEMA_VALID para validar documentos JSON contra un esquema.

Escrito por Eduardo Lázaro