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_comillas | sin_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;| nombre | con_comillas | sin_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_json | precio_unquote |
|---|---|
| 1299.99 | 1299.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';| nombre | zona |
|---|---|
| María García | Europe/Madrid |
| Carlos López | America/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;| nombre | color | almacenamiento | precio |
|---|---|---|---|
| iPhone 15 Pro | Titanio Natural | 256GB | 1299.99 |
| MacBook Air M3 | Medianoche | 512GB | 1399.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;| numero | booleano | nulo |
|---|---|---|
| 42 | true | null |
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_mayusculas | provincia | longitud_nombre |
|---|---|---|
| MARÍA GARCÍA | 28 | 13 |
| CARLOS LÓPEZ | 08 | 14 |
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
