XML en la base de datos Oracle: XMLType y XMLTABLE
Guardar XML en un CLOB es enterrarlo; tratarlo como tipo nativo permite consultarlo con SQL. XMLType, XMLTABLE y el delicado tránsito hacia JSON.
Hubo una época —digamos, la de los servicios SOAP— en que XML lo era todo: facturas electrónicas, mensajería entre bancos, configuración. Oracle apostó fuerte por aquellos años y convirtió XML en un ciudadano de primera clase de la base de datos con el tipo XMLType, able de almacenarse, indexarse y consultarse con SQL. Los formatos han girado hacia JSON, pero el XML no se ha ido: la factura electrónica de medio mundo sigue siendo XML firmado, y las bases heredadas están llenas de él. Saber interrogarlo sigue pagando la factura.
Columnas XMLType, no CLOB
La decisión estructural: guardar el documento en un CLOB o en una columna XMLType. En CLOB, el documento es una caja cerrada que solo puedes abrir fuera de la base. Con XMLType, el contenido es consultable:
CREATE TABLE pedidos (
id NUMBER PRIMARY KEY,
recibido DATE DEFAULT SYSDATE,
documento XMLType
) XMLTYPE COLUMN documento
STORE AS BINARY XML;
INSERT INTO pedidos (id, documento) VALUES (1, XMLType(
'<pedido><cliente>ACME</cliente>
<linea sku="A-1" cant="2" precio="80"/>
<linea sku="B-7" cant="1" precio="24"/>
</pedido>'));BINARY XML (11g+) es el almacenamiento recomendado: XML comprimido y post-parseado, más compacto y rápido de consultar que el CLOB clásico. La diferencia práctica frente a CLOB es abismal: sobre el XML binario se pueden crear índices estructurados; sobre texto plano, cualquier XPath es un escaneo con parseo por fila.
XMLTABLE: el puente hacia SQL relacional
La función XMLTABLE proyecta nodos del documento como si fueran columnas de una tabla. Es el corazón práctico del XML en SQL:
SELECT p.id,
x.cliente,
x.sku,
x.cantidad,
x.precio
FROM pedidos p,
XMLTABLE('/pedido' PASSING p.documento
COLUMNS cliente VARCHAR2(30) PATH 'cliente',
sku VARCHAR2(10) PATH 'linea/@sku',
cantidad NUMBER PATH 'linea/@cant',
precio NUMBER(10,2) PATH 'linea/@precio') x;La cláusula PASSING entrega el documento y COLUMNS mapea rutas XPath a columnas: los @ acceden a atributos. Nótese que el join lateral contra pedidos expande cada documento en tantas filas como líneas tenga —basta con variar la ruta base a /pedido/linea para iterar por líneas directamente.
Extraer valores sueltos: EXTRACTVALUE y sus herederos
SELECT XMLQuery('/pedido/cliente/text()'
PASSING documento RETURNING CONTENT) AS cliente
FROM pedidos WHERE id = 1;
SELECT XMLExists('/pedido/linea[@sku = "A-1"]'
PASSING documento) AS tiene_a1
FROM pedidos WHERE id = 1;XMLQuery devuelve fragmentos y XMLExists actúa como predicado —su equivalente antiguo, EXTRACTVALUE, sigue apareciendo en código heredado y solo soporta un nodo escalar por llamada. Para la salida en la otra dirección, generar XML desde SQL, existe XMLELEMENT/XMLAGG, que componen documentos fila a fila; la combinación con MERGE permite sincronizar tablas relacionales con documentos recibidos.
Índices: la diferencia entre segundos y horas
Sin índice, cada XMLExists examina todos los documentos. Con documentos grandes y consultas frecuentes por un nodo concreto, el índice XML:
CREATE INDEX ix_pedidos_sku ON pedidos (documento)
INDEXTYPE IS XDB.BINARY XML
XMLINDEX XMLTABLE '/pedido/linea'
COLUMNS sku VARCHAR2(10) PATH '@sku';La sintaxis exacta varía entre versiones —en 12c el XMLIndex admite tablas de índice estructuradas y mantenimiento asíncrono—, pero la idea es constante: el índice materializa los XPath calientes y las consultas dejan de parsear.
¿Y JSON? La historia se repite
El giro del ecosistema hacia JSON no borró el patrón, solo la sintaxis: JSON_TABLE es a los documentos JSON lo que XMLTABLE era al XML, con la misma lógica de columnas mapeadas por ruta y el mismo debate CLOB contra nativo. Las bases modernas tratan ambos formatos como tipos consultables, y conviven sin drama: la factura sigue llegando en XML firmado mientras la aplicación interna habla JSON.
- Para volcar documentos legibles desde SQL*Plus, un
SET LONG 100000yLONGCHUNKSIZEdecentes evitan el clásico corte a 80 caracteres: detalles en el comando SET. - El tamaño real de los documentos almacenados se vigila con
USER_SEGMENTS, entre las consultas útiles del diccionario.
XML en la base de datos dejó de ser noticia, pero sigue siendo infraestructura: saber extraer datos de él con una sola sentencia convierte integraciones viejas en trabajo de minutos.