sql >> Database >  >> RDS >> PostgreSQL

XMLTABLE in PostgreSQL

Ik heb zojuist een patch van Pavel Stěhule uitgevoerd die de XMLTABLE toevoegt functionaliteit naar PostgreSQL 10.  XMLTABLE is een zeer handige functie die wordt gedicteerd door de SQL/XML-standaard, waarmee u uw XML-gegevens in relationele vorm kunt omzetten, zodat u ze kunt combineren met de rest van uw relationele gegevens. Deze functie heeft veel toepassingen; blijf lezen voor wat details erover.

Waarschijnlijk de meest interessante use case van XMLTABLE is om gegevens uit een XML-document te extraheren om in een relationele tabel in te voegen tijdens ETL-verwerking in de database. Echter, XMLTABLE kan on-the-fly worden gebruikt op gegevens die zijn opgeslagen in XML-kolommen, zodat zodra de gegevens in relationele vorm zijn, u alle gewenste standaardbewerkingen kunt toepassen, zoals het toevoegen van WHERE clausules, aggregaties doen, deelnemen aan andere tabellen, enzovoort.

Een eenvoudig voorbeeld

Stel dat u als voorbeeld een hotelketen beheert en dat de gegevens als volgt worden opgeslagen:

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;

Met XMLTABLE , kunt u dit omzetten in een relationeel opgemaakte tabel bestaande uit kamernummers en capaciteit, met aantekeningen voor elk hotel in uw keten:

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 hotelnaam room_id capaciteit commentaar
1 La Mancha 201 3 Prachtig uitzicht op het kanaal
2 La Mancha 202 5 Een gewone kamer
3 Valparaíso 201 2 Zeer luidruchtig
4 Valparaíso 202 2 Een gewone kamer

De syntaxis uitleggen

Laten we de bovenstaande zoekopdracht eens bekijken. De XMLTABLE clausule moet in de FROM . staan onderdeel van de vraag. We hebben ook hoteldata in de VAN , wat de gegevens invoert in XMLTABLE .

Eerst de PASSING clausule is waar we de XML-gegevens specificeren die we willen verwerken. In dit geval zijn de gegevens afkomstig van de hotels kolom in de hotelgegevens tafel. We noemen dit de documentuitdrukking .

Net voor de PASSING clausule ziet u een XPath-expressie '/hotels/hotel/rooms/room' . We noemen dit de rijgenererende uitdrukking of gewoon de rij-uitdrukking .

We hebben de KOLOMMEN clausule vervolgens, het declareren van een paar kolommen. Voor elke kolom geven we een gegevenstype aan, evenals een optioneel PATH clausule, die we de kolomuitdrukking . noemen .

XML-TABEL De werkingstheorie is dat de rij-uitdrukking wordt toegepast op de documentuitdrukking, waarbij het document in stukken wordt gesneden om rijen te genereren; voor elke zo gegenereerde rij worden de verschillende kolomuitdrukkingen toegepast om de waarden voor elke kolom te verkrijgen.

De kolomexpressie is een XPath-expressie die een waarde verkrijgt die begint met de XML voor de huidige rij. Indien geen PATH is opgegeven, wordt de kolomnaam zelf gebruikt als de XPath-expressie. Merk op dat in de kolom hotel_name we gebruikten een pad met "../ ', wat betekent 'omhoog gaan' in het XML-document om waarden uit de 'container'-objecten in het document te halen. We kunnen ook xml PATH '.' . gebruiken in een rij, wat ons de volledige bron-XML voor die rij geeft.

Eén kolom kan worden gemarkeerd als VOOR ORDINALITEIT . De kolom is dan van het type INTEGER , en is opeenvolgend genummerd voor elke rij verkregen uit het document. (Als er meerdere invoerdocumenten zijn, zoals wanneer u meerdere rijen in een tabel heeft, begint de teller bij 1 voor elk nieuw document).

Er is ook een DEFAULT clausule. Als het XPath voor een kolom niet overeenkomt met een waarde voor een bepaalde rij, dan is de DEFAULT waarde wordt gebruikt.

Sommige van deze kolommen zijn gemarkeerd als NIET NULL . Als er geen overeenkomst is en geen DEFAULT clausule is opgegeven (of de DEFAULT evalueert ook tot NULL ), wordt een fout gegenereerd.

Ik zal niet dieper ingaan op XPath, wat een krachtige taal is, maar ik kan het XPath-artikel op Wikipedia en het officiële aanbevelingsdocument van W3C als nuttige bronnen aanbieden.

De volledige XMLTABLE-syntaxis

De gedocumenteerde syntaxissynopsis is:

xmltable( [XMLNAMESPACES(namespace uri AS namespace name[, ...])] row_expression PASSING [BY REF] document_expression [BY REF] COLUMNS name { type [PATH column_expression] [DEFAULT expr] [NOT NULL | NULL] | FOR ORDINALITY } [, ...] )

Merk op dat de documentuitdrukking een verwijzing kan zijn naar een tabel die u in de FROM-component hebt, of dat het een volledig XML-document kan zijn als een letterlijke tekenreeks. De BY REF-clausules hebben geen effect; ze zijn er voor compatibiliteit met de standaard en met andere databasesystemen.

Ik heb de XMLNAMESPACES niet behandeld clausule in dit bericht; Ik laat dat voor een toekomstige aflevering.

SQL bovenaan toepassen

Zoals gezegd, zodra XMLTABLE de gegevens in relationele vorm heeft verwerkt, kunt u doen wat u wilt met behulp van bekende tools. Als u bijvoorbeeld een ander XML-document had met meer personeel in elk 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>$$);

Het is gemakkelijk om de totale salarissen te zien voor elke valuta die u in elk hotel moet betalen,

  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 som
Valparaíso CLP 1200000
Valparaíso EUR 80000
La Mancha PTA 80000

Conclusie

In dit artikel heb ik de nieuwe functie XMLTABLE . behandeld om te verschijnen in PostgreSQL versie 10. Ik denk dat XMLTABLE is een geweldige functie voor het integreren van externe gegevens, en ik hoop dat u het ook waardevol vindt. Test het en meld eventuele problemen, zodat we ze kunnen oplossen voor de definitieve release. Als je van XMLTABLE houdt , laat het ons weten door een reactie achter te laten!


  1. Hoe specificeer je de IN-component in een dynamische query met behulp van een variabele?

  2. Hoe PERIOD_DIFF() werkt in MariaDB

  3. oci_connect verbinding mislukt

  4. Hoe verander ik de KARAKTERSET (en COLLATION) in een database?