Właśnie zatwierdziłem łatkę autorstwa Pavela Stěhule, która dodaje XMLTABLE funkcjonalność do PostgreSQL 10. XMLTABLE to bardzo przydatna funkcja podyktowana standardem SQL/XML, która umożliwia przekształcenie danych XML w formę relacyjną, dzięki czemu można je mieszać z resztą danych relacyjnych. Ta funkcja ma wiele zastosowań; czytaj dalej, aby uzyskać więcej informacji na ten temat.
Prawdopodobnie najciekawszy przypadek użycia XMLTABLE jest wyodrębnienie danych z jakiegoś dokumentu XML w celu wstawienia do tabeli relacyjnej podczas przetwarzania ETL w bazie danych. Jednak XMLTABLE mogą być używane w locie na danych przechowywanych w kolumnach XML, dzięki czemu gdy dane są w formie relacyjnej, można zastosować dowolne standardowe operacje, takie jak dodanie GDZIE klauzule, wykonywanie agregacji, dołączanie do innych tabel itd.
Prosty przykład
Jako przykład załóżmy, że zarządzasz siecią hoteli i że dane są przechowywane w ten sposób:
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;
Z XMLTABLE , możesz to zmienić w relacyjnie sformatowaną tabelę składającą się z numerów pokoi i pojemności, z adnotacjami dla każdego hotelu w Twojej sieci:
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 | nazwa_hotelu | room_id | pojemność | komentarz |
---|---|---|---|---|
1 | La Mancha | 201 | 3 | Wspaniały widok na kanał |
2 | La Mancha | 202 | 5 | Zwykły pokój |
3 | Valparaíso | 201 | 2 | Bardzo głośno |
4 | Valparaíso | 202 | 2 | Zwykły pokój |
Objaśnienie składni
Przeanalizujmy powyższe zapytanie. TABELA XML klauzula musi znajdować się w FROM część zapytania. Mamy również dane hoteli w OD , który dostarcza dane do XMLTABLE .
Po pierwsze, PRZECHODZENIE Klauzula to miejsce, w którym określamy dane XML, które chcemy przetworzyć. W tym przypadku dane pochodzą z hoteli kolumna w hoteldata stół. Nazywamy to wyrażeniem dokumentu .
Tuż przed PASSING klauzula widzisz wyrażenie XPath '/hotels/hotel/rooms/room' . Nazywamy to wyrażeniem generującym wiersze lub po prostu wyrażenie wiersza .
Mamy KOLUMNY następną klauzulę, deklarując kilka kolumn. Dla każdej kolumny wskazujemy typ danych, a także opcjonalną PATH klauzulę, którą nazywamy wyrażeniem kolumny .
TABELA XML Teoria działania polega na tym, że wyrażenie wiersza jest stosowane do wyrażenia dokumentu, dzieląc dokument na kawałki w celu wygenerowania wierszy; dla każdego tak wygenerowanego wiersza różne wyrażenia kolumn są stosowane w celu uzyskania wartości dla każdej kolumny.
Wyrażenie kolumny to wyrażenie XPath, które uzyskuje wartość z kodu XML bieżącego wiersza. Jeśli nie PATH jest określony, to sama nazwa kolumny jest używana jako wyrażenie XPath. Zwróć uwagę, że w kolumnie nazwa_hotelu użyliśmy ścieżki zawierającej „../ „, co oznacza „przejście w górę” w dokumencie XML, aby pobrać wartości z obiektów „kontenera” w dokumencie. Możemy również użyć xml PATH '.' z rzędu, co daje nam pełny kod XML źródłowy dla tego wiersza.
Jedna kolumna może być oznaczona jako PORZĄDKOŚĆ . Kolumna jest wtedy typu INTEGER , i jest numerowany kolejno dla każdego wiersza uzyskanego z dokumentu. (Jeśli istnieje wiele dokumentów wejściowych, na przykład gdy masz wiele wierszy w tabeli, licznik zaczyna się od 1 dla każdego nowego dokumentu).
Istnieje również DOMYŚLNE klauzula. Jeśli ścieżka XPath dla kolumny nie pasuje do wartości w określonym wierszu, to DEFAULT używana jest wartość.
Niektóre z tych kolumn zostały oznaczone jako NOT NULL . Jeśli nie ma dopasowania i nie ma DOMYŚLNEGO podano klauzulę (lub DEFAULT również zwraca się do NULL ), zgłaszany jest błąd.
Nie będę wchodzić w szczegóły XPath, który jest potężnym językiem, ale mogę zaoferować artykuł XPath w Wikipedii oraz oficjalny dokument rekomendacji W3C jako przydatne zasoby.
Pełna składnia XMLTABLE
Udokumentowane streszczenie składni to:
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 } [, ...] )
Zauważ, że wyrażenie dokumentu może być odwołaniem do jakiejś tabeli, którą masz w klauzuli FROM, lub może być kompletnym dokumentem XML jako literałem ciągu. Klauzule BY REF nie mają żadnego efektu; są tam, aby zapewnić zgodność ze standardem i innymi systemami baz danych.
Nie omówiłem XMLNAMESPACES klauzula w tym poście; Zostawiam to na przyszłą ratę.
Stosowanie SQL na wierzchu
Jak wspomniano, gdy XMLTABLE przetworzy dane do postaci relacyjnej, możesz zrobić, co chcesz, używając dobrze znanych narzędzi. Na przykład, jeśli masz inny dokument XML z większą liczbą pracowników w każdym hotelu,
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>$$);
Łatwo jest uzyskać łączną pensję dla każdej waluty, którą musisz zapłacić w każdym hotelu,
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 | waluta | suma |
---|---|---|
Walparais | CLP | 1200000 |
Walparais | EUR | 80000 |
La Mancha | PTA | 80000 |
Wniosek
W tym artykule omówiłem nową funkcję XMLTABLE do pojawienia się w PostgreSQL w wersji 10. Myślę, że XMLTABLE to świetna funkcja do integracji danych zewnętrznych i mam nadzieję, że również uznasz ją za wartościową. Przetestuj go i zgłaszaj wszelkie problemy, abyśmy mogli rozwiązać je przed ostatecznym wydaniem. Jeśli lubisz XMLTABLE , daj nam znać, zostawiając komentarz!