PostgreSQL
 sql >> Base de Dados >  >> RDS >> PostgreSQL

XMLTABLE no PostgreSQL


Acabei de enviar um patch de Pavel Stěhule que adiciona o XMLTABLE funcionalidade para o PostgreSQL 10.  XMLTABLE é um recurso muito útil ditado pelo padrão SQL/XML, que permite transformar seus dados XML em formato relacional, para que você possa misturá-los com o restante de seus dados relacionais. Esse recurso tem muitos usos; continue lendo para alguns detalhes sobre ele.

Provavelmente o caso de uso mais interessante de XMLTABLE é extrair dados de algum documento XML para inserir em uma tabela relacional, durante o processamento ETL no banco de dados. No entanto, XMLTABLE pode ser usado dinamicamente em dados armazenados em colunas XML, de modo que, uma vez que os dados estejam no formato relacional, você possa aplicar quaisquer operações padrão que desejar, como adicionar WHERE cláusulas, fazendo agregações, juntando-se a outras tabelas e assim por diante.

Um exemplo simples


Como exemplo, vamos supor que você administre uma rede hoteleira, e que os dados sejam armazenados assim:
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;

Com XMLTABLE , você pode transformar isso em uma tabela formatada de forma relacional que consiste em números de quartos e capacidade, anotando para cada hotel da sua rede:
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 hotel_name room_id capacidade comentário
1 La Mancha 201 3 Excelente vista do Canal
2 La Mancha 202 5 Uma sala normal
3 Valparaíso 201 2 Muito barulhento
4 Valparaíso 202 2 Uma sala normal

Explicando a sintaxe


Vamos estudar a consulta acima. A XMLTABLE cláusula deve ir no FROM parte da consulta. Também temos dados do hotel no DE , que é o que alimenta os dados em XMLTABLE .

Primeiro, o PASSANDO cláusula é onde especificamos os dados XML que queremos processar. Nesse caso, os dados vêm dos hotéis coluna nos hoteldata tabela. Chamamos isso de expressão do documento .

Pouco antes do PASSANDO cláusula você vê uma expressão XPath '/hotels/hotel/rooms/room' . Chamamos isso de expressão geradora de linha ou apenas a expressão de linha .

Temos as COLUNAS cláusula a seguir, declarando algumas colunas. Para cada coluna, indicamos um tipo de dados e um PATH opcional cláusula, que chamamos de expressão de coluna .

XMLTABLE a teoria de operação de é que a expressão de linha é aplicada à expressão do documento, cortando o documento em pedaços para gerar linhas; para cada linha assim gerada, as várias expressões de coluna são aplicadas para obter os valores de cada coluna.

A expressão de coluna é uma expressão XPath que obtém um valor a partir do XML para a linha atual. Se não houver PATH for especificado, o próprio nome da coluna será usado como a expressão XPath. Observe que na coluna hotel_name usamos um caminho com “../ ", que significa "subir" no documento XML para obter valores dos objetos "contêiner" no documento. Também podemos usar xml PATH '.' em uma linha, o que nos fornece o XML de origem completo para essa linha.

Uma coluna pode ser marcada como FOR ORDINALITY . A coluna é então do tipo INTEGER , e é numerado sequencialmente para cada linha obtida do documento. (Se houver vários documentos de entrada, como quando você tem várias linhas em uma tabela, o contador começa em 1 para cada novo documento).

Há também um DEFAULT cláusula. Se o XPath de uma coluna não corresponder a um valor para uma determinada linha, o DEFAULT valor é usado.

Algumas dessas colunas foram marcadas como NOT NULL . Se não houver correspondência e nenhum DEFAULT cláusula é especificada (ou o DEFAULT também avalia como NULL ), um erro é lançado.

Não entrarei em mais detalhes do XPath, que é uma linguagem poderosa, mas posso oferecer o artigo XPath na Wikipedia e o documento de recomendação oficial do W3C como recursos úteis.

A sintaxe XMLTABLE completa


A sinopse de sintaxe documentada é:
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 } [, ...] )

Observe que a expressão do documento pode ser uma referência a alguma tabela que você tem na cláusula FROM ou pode ser um documento XML completo como um literal de string. As cláusulas BY REF não têm efeito; eles existem para compatibilidade com o padrão e com outros sistemas de banco de dados.

Não abordei os XMLNAMESPACES cláusula neste post; Deixo isso para um próximo capítulo.

Aplicando SQL no topo


Como mencionado, uma vez que XMLTABLE tenha processado os dados em formato relacional, você pode fazer o que quiser usando ferramentas conhecidas. Por exemplo, se você tivesse outro documento XML com mais funcionários em cada 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>$$);

É fácil obter o total de salários para cada moeda que você precisa pagar em cada 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 moeda soma
Valparaíso CLP 1200000
Valparaíso EUR 80.000
La Mancha PTA 80.000

Conclusão


Neste artigo, abordei o novo recurso XMLTABLE para aparecer no PostgreSQL versão 10. Acho que XMLTABLE é um ótimo recurso para integrar dados externos e espero que você também o ache valioso. Por favor, teste-o e relate quaisquer problemas, para que possamos resolvê-los antes do lançamento final. Se você gosta de XMLTABLE , não se esqueça de nos informar deixando um comentário!