从嵌套的XML PostgreSQL中提取数据

问题描述

我有一个XML,需要将其插入表中。 XML看起来像

<?xml version="1.0" encoding="UTF-8"?>
<root>
   <pats>
      <pat>
         <id>1</id>
         <pat_maps>
            <pat_map>
               <pgid>100</pgid>
               <pgname>test</pgname>
            </pat_map>
            <pat_map>
               <pgid>101</pgid>
               <pgname>test1</pgname>
            </pat_map>
         </pat_maps>
      </pat>
      <pat>
         <id>2</id>
         <pat_maps>
            <pat_map>
               <pgid>102</pgid>
               <pgname>test2</pgname>
            </pat_map>
         </pat_maps>
      </pat>
      <pat>
         <id>3</id>
         <pat_maps>
            <pat_map>
               <pgid>104</pgid>
               <pgname>test6</pgname>
            </pat_map>
            <pat_map>
               <pgid>105</pgid>
               <pgname>test7</pgname>
            </pat_map>
         </pat_maps>
      </pat>
   </pats>
</root> 

我想通过以下方式插入数据

ID  pgid    pgname
1   100     test
1   101     test1
2   102     test2
3   104     test6
3   105     test7

在下面尝试过,但是正在应用交叉联接

with x(t) as (select '<?xml version="1.0" encoding="UTF-8"?>
<root>
   <pats>
..............
..........
      </pat>
   </pats>
</root>'::xml AS t
),base_id as (SELECT 
    unnest(xpath('/root/pats/pat/id/text()',t)) AS id
from x
),nested_rec as ( select 
    unnest(xpath('pgid/text()',cat_assn_list)) AS pgid,unnest(xpath('pgname/text()',cat_assn_list)) AS pgname
from (select unnest(xpath('/root/pats/pat/pat_maps/pat_map',t)) cat_assn_list from x) q
) 
select base_id.*,nested_rec.* from base_id,nested_rec;

******* output *********
ID  PGID    PGNAME  
"1" "100"   "test"
"1" "101"   "test1"
"1" "102"   "test2"
"1" "104"   "test6"
"1" "105"   "test7"
"2" "100"   "test"
"2" "101"   "test1"
"2" "102"   "test2"
"2" "104"   "test6"
"2" "105"   "test7"
"3" "100"   "test"
"3" "101"   "test1"
"3" "102"   "test2"
"3" "104"   "test6"
"3" "105"   "test7"

我还没有找到一种方法,如何明智地嵌套XML ID并准备结果集? 还有没有其他方法可以在不使用Postgresql中的XPath函数的情况下将xml数据转换为表? 预先感谢。

解决方法

以下内容可以满足您的要求,并且简短一些:

select (xpath('/pat/id/text()',d.pat))[1]::text::int as id,(xpath('/pat_map/pgid/text()',m.map))[1]::text::int as pgid,(xpath('/pat_map/pgname/text()',m.map))[1]::text as pgname
from x 
  cross join unnest(xpath('/root/pats/pat',x.t)) as d(pat)
  cross join unnest(xpath('/pat/pat_maps/pat_map',d.pat)) as m(map)
;

Online example

使用更现代的Postgres版本,您可以使用xmltable()

select d.*
from x
  cross join xmltable ('/root/pats/pat/pat_maps/pat_map' 
                       passing t 
                       columns 
                        id integer path '../../id',pgid integer path 'pgid',pgname text path 'pgname') as d