Ho appena eseguito il commit di una patch di Pavel Stěhule che aggiunge l'XMLTABLE funzionalità a PostgreSQL 10. XMLTABLE è una funzionalità molto utile dettata dallo standard SQL/XML, che ti consente di trasformare i tuoi dati XML in una forma relazionale, in modo da poterli combinare con il resto dei tuoi dati relazionali. Questa funzione ha molti usi; continua a leggere per alcuni dettagli a riguardo.
Probabilmente il caso d'uso più interessante di XMLTABLE consiste nell'estrarre dati da un documento XML da inserire in una tabella relazionale, durante l'elaborazione ETL nel database. Tuttavia, XMLTABLE può essere utilizzato al volo su dati archiviati in colonne XML, in modo che una volta che i dati sono in forma relazionale, puoi applicare qualsiasi operazione standard desideri, come aggiungere WHERE clausole, fare aggregazioni, unirsi ad altre tabelle e così via.
Un semplice esempio
Ad esempio, supponiamo che tu amministri una catena di hotel e che i dati siano archiviati in questo modo:
CREATE TABLE hoteldata AS SELECT xml
$$<hotels>
<hotel id="mancha">
<name>La Mancha</name>
<rooms>
<room id="201"><capacity>3</capacity><comment>Great view of the Channel</comment></room>
<room id="202"><capacity>5</capacity></room>
</rooms>
<personnel>
<person id="1025">
<name>Ferdinando Quijana</name><salary currency="PTA">45000</salary>
</person>
</personnel>
</hotel>
<hotel id="valpo">
<name>Valparaíso</name>
<rooms>
<room id="201"><capacity>2</capacity><comment>Very noisy</comment></room>
<room id="202"><capacity>2</capacity></room>
</rooms>
<personnel>
<person id="1026"><name>Katharina Wuntz</name><salary currency="EUR">50000</salary></person>
<person id="1027"><name>Diego Velázquez</name><salary currency="CLP">1200000</salary></person>
</personnel>
</hotel>
</hotels>$$ AS hotels;
Con XMLTABLE , puoi trasformarlo in una tabella con formattazione relazionale composta da numero di camere e capacità, annotando per ogni hotel della tua catena:
SELECT xmltable.*
FROM hoteldata,
XMLTABLE ('/hotels/hotel/rooms/room' PASSING hotels
COLUMNS
id FOR ORDINALITY,
hotel_name text PATH '../../name' NOT NULL,
room_id int PATH '@id' NOT NULL,
capacity int,
comment text PATH 'comment' DEFAULT 'A regular room'
);
id | nome_hotel | ID_stanza | capacità | commento |
---|---|---|---|---|
1 | La Mancia | 201 | 3 | Ottima vista del canale |
2 | La Mancia | 202 | 5 | Una stanza normale |
3 | Valparaiso | 201 | 2 | Molto rumoroso |
4 | Valparaiso | 202 | 2 | Una stanza normale |
Spiegazione della sintassi
Studiamo la query sopra. XMLTABLE la clausola deve essere inserita nel DA parte della domanda. Abbiamo anche hoteldata nel DA , che è ciò che alimenta i dati in XMLTABLE .
Innanzitutto, il PASSING La clausola è dove specifichiamo i dati XML che vogliamo elaborare. In questo caso, i dati provengono dagli hotel colonna in hoteldata tavolo. Chiamiamo questo l'espressione del documento .
Poco prima del PASSAGGIO clausola viene visualizzata un'espressione XPath '/hotels/hotel/rooms/room' . Chiamiamo questa l'espressione generatrice di righe o semplicemente l'espressione di riga .
Abbiamo le COLONNE clausola successiva, dichiarando alcune colonne. Per ogni colonna indichiamo un tipo di dati oltre a un PERCORSO facoltativo clausola, che chiamiamo l'espressione di colonna .
XMLTABLE La teoria dell'operazione è che l'espressione di riga viene applicata all'espressione del documento, tagliando il documento in pezzi per generare righe; per ogni riga così generata vengono applicate le varie espressioni di colonna per ottenere i valori per ciascuna colonna.
L'espressione di colonna è un'espressione XPath che ottiene un valore a partire dall'XML per la riga corrente. Se nessun PERCORSO viene specificato, il nome della colonna stesso viene utilizzato come espressione XPath. Nota che nella colonna nome_hotel abbiamo usato un percorso con “../ ", che significa "salire" nel documento XML per acquisire valori dagli oggetti "contenitore" nel documento. Possiamo anche usare xml PATH '.' in una riga, che ci fornisce l'XML di origine completo per quella riga.
Una colonna può essere contrassegnata PER ORDINALITÀ . La colonna è quindi di tipo INTEGER , ed è numerato in sequenza per ogni riga ottenuta dal documento. (Se ci sono più documenti di input, ad esempio quando hai più righe in una tabella, il contatore parte da 1 per ogni nuovo documento).
C'è anche un DEFAULT clausola. Se XPath per una colonna non corrisponde a un valore per una determinata riga, allora DEFAULT viene utilizzato il valore.
Alcune di queste colonne sono state contrassegnate come NON NULL . Se non c'è corrispondenza e nessun DEFAULT è specificata la clausola (o la clausola DEFAULT restituisce anche NULL ), viene generato un errore.
Non entrerò nei dettagli di XPath, che è un linguaggio potente, ma posso offrire l'articolo di XPath su Wikipedia e il documento di raccomandazione ufficiale del W3C come risorse utili.
La sintassi completa di XMLTABLE
La sinossi della sintassi documentata è:
xmltable
( [XMLNAMESPACES(namespace uri
ASnamespace name
[, ...])]row_expression
PASSING [BY REF]document_expression
[BY REF] COLUMNSname
{type
[PATHcolumn_expression
] [DEFAULTexpr
] [NOT NULL | NULL] | FOR ORDINALITY } [, ...] )
Nota che l'espressione del documento può essere un riferimento ad alcune tabelle che hai nella clausola FROM, oppure può essere un documento XML completo come una stringa letterale. Le clausole BY REF non hanno alcun effetto; sono disponibili per la compatibilità con lo standard e con altri sistemi di database.
Non ho coperto gli XMLNAMESPACES clausola in questo post; Lo lascio per una puntata futura.
Applicazione SQL in primo piano
Come accennato, una volta che XMLTABLE ha elaborato i dati in forma relazionale, puoi fare quello che vuoi usando strumenti ben noti. Ad esempio, se hai un altro documento XML con più personale in ogni hotel,
INSERT INTO hoteldata VALUES (xml $$<hotels> <hotel id="mancha"> <name>La Mancha</name> <personnel> <person id="1028"> <name>Sancho Panza</name><salary currency="PTA">35000</salary> </person> </personnel> </hotel> <hotel id="valpo"> <name>Valparaíso</name> <personnel> <person id="1029"><name>Kurt Werner</name><salary currency="EUR">30000</salary></person> </personnel> </hotel> </hotels>$$);
È facile ottenere gli stipendi totali per ciascuna valuta che devi pagare in ogni hotel,
SELECT hotel, currency, sum(salary) FROM hoteldata, XMLTABLE ('/hotels/hotel/personnel/person' PASSING hotels COLUMNS hotel text PATH '../../name' NOT NULL, salary integer PATH 'salary' NOT NULL, currency text PATH 'salary/@currency' NOT NULL ) GROUP BY hotel, currency;
hotel | valuta | somma |
---|---|---|
Valparaíso | CLP | 1200000 |
Valparaíso | EUR | 80000 |
La Mancia | PTA | 80000 |
Conclusione
In questo articolo, ho trattato la nuova funzionalità XMLTABLE per apparire in PostgreSQL versione 10. Penso XMLTABLE è un'ottima funzionalità per l'integrazione di dati esterni e spero che anche tu la trovi preziosa. Si prega di testarlo e segnalare eventuali problemi, in modo che possiamo risolverli prima del rilascio finale. Se ti piace XMLTABLE , assicurati di farcelo sapere lasciando un commento!