Oracle查询以重命名XMLTYPE中的标记

kxkpmulp  于 2023-06-05  发布在  Oracle
关注(0)|答案(2)|浏览(390)

我有一个表(Table 1),它有一个XMLType字段(PROPERTIES),还有一个表(Table 2),它有两个字段:

  • 标签名称
  • TAG_RENAME

每个XMLType记录可以有不同的标记名。我需要得到的选择输出,与标签重命名的XMLType字段(我不需要更新字段)。
这里有一个例子:
表1:
| ID|产品展示|
| - -----|- -----|
| 1| </Fields><TAG1>123</TAG1><TAG2>345</TAG2></Fields>|
| 2| </Fields><TAG1>999</TAG1><TAG3>XXX</TAG3></Fields>|
表2:
| 标签名称|TAG_RENAME|
| - -----|- -----|
| TAG1|新闻_TAG1|
| TAG2|新闻_TAG2|
| TAG3|新闻_TAG3|
所需输出:
| ID|新_属性|
| - -----|- -----|
| 1| </Fields><NEW_TAG1>123</NEW_TAG1><NEW_TAG2>345</NEW_TAG2></Fields>|
| 3| </Fields><NEW_TAG1>999</NEW_TAG1><NEW_TAG3>XXX</NEW_TAG3></Fields>|
我用这种方式尝试了XQuery(左连接,因为一些PROPERTIES字段可以是NULL):

select t.ID, t.tag_name, t.value FROM Table1 t
left join  XMLTable ('for $i in fn:collection("oradb:/MY_USER/TABLE2"), $x in //descendant::*
where $i/ROW/TAG_NAME=local-name($x)
return element r {
           element tag_name  {$i/ROW/TAG_RENAME/text()}
        , element tag_value {$x/text()}
         }'
passing case when t.properties is null then null else xmltype ('<?xml version="1.0" encoding="iso-8859-1" ?>'||t.properties)end
columns tag_name varchar2(30) path 'tag_name',
                tag_value varchar2(30) path 'tag_value'                
)x on 1=1 and x.tag_value is not null;

我得到的输出
| ID|标签名称|标签值|
| - -----|- -----|- -----|
| 1|新闻_TAG1|一百二十三|
| 1|新闻_TAG2|三百四十五|
| 2|新闻_TAG1|九九九|
| 2|新闻_TAG3| XXX|
所以它几乎起作用了。问题是我希望每个ID都在一行上。我试过listagg,它的工作,但它的速度很慢。有没有办法直接在XQuery中重命名TAG?

dzhpxtsq

dzhpxtsq1#

您可以使用XQuery来修改XML。

create table sample (id, val) as
  select 1, '<Fields><TAG1>123</TAG1><TAG2>345</TAG2></Fields>' from dual
  union all
  select 2, '<Fields><TAG1>999</TAG1><TAG3>XXX</TAG3></Fields>' from dual
create table renaming(tag, renamed) as
  select 'TAG1','NEW_TAG1' from dual union all
  select 'TAG2','NEW_TAG2' from dual union all
  select 'TAG3','NEW_TAG3' from dual
select
  s.*
  , xmlserialize(document xmlquery(
    'copy $res := $x modify (
      for $r in $ren/ROWSET/ROW
      for $i in $res/Fields/*[name(.) = $r/TAG]
      return rename node $i as $r/RENAMED
    ) return $res'
    passing
      xmltype(s.val) as "x",
      /*Mapping XML*/
      dbms_xmlgen.getxmltype('select * from renaming') as "ren"
    returning content
  ) as clob) as renamed
from sample s

| ID|瓦尔|重新命名|
| - -----|- -----|- -----|
| 1|123345|<NEW_TAG1>123345</NEW_TAG1><NEW_TAG2></NEW_TAG2>|
| 2|小行星999|小<NEW_TAG1></NEW_TAG1><NEW_TAG3>行星999</NEW_TAG3>|
fiddle

UPD:如果要删除不匹配的标签或没有值的标签,可以使用多次修改。

select
  s.*
  , xmlserialize(document xmlquery(
    'copy $res := $x modify (
      (
        for $i in $res/Fields/*
        return (
          delete node $i[not($ren/ROWSET/ROW/TAG[text() = name($i)])],
          delete node $i[not(text())]
        )
      ),
      (
        for $renaming in $ren/ROWSET/ROW
        for $i in $res/Fields/*[name(.) = $renaming/TAG]
        return rename node $i as $renaming/RENAMED/text()
      )
    ) return $res'
    passing
      xmltype(s.val) as "x",
      /*Mapping XML*/
      dbms_xmlgen.getxmltype('select * from renaming') as "ren"
    returning content
  ) as clob) as renamed
from sample s

对于这个样本数据

create table sample (id, val) as
  select 1, '<Fields><TAG1>123</TAG1><TAG2>345</TAG2><TAG_WITH_NO_VALUE/></Fields>' from dual
  union all
  select 2, '<Fields><TAG1>999</TAG1><TAG3>XXX</TAG3></Fields>' from dual
create table renaming(tag, renamed) as
  select 'TAG_WITH_NO_VALUE','TAG_WITH_NO_VALUE__2' from dual union all
  select 'TAG2','NEW_TAG2' from dual union all
  select 'TAG3','NEW_TAG3' from dual

退货
| ID|瓦尔|重新命名|
| - -----|- -----|- -----|
| 1|123345<TAG_WITH_NO_VALUE/>|三百<NEW_TAG2>四十五</NEW_TAG2>|
| 2|小行星999|<NEW_TAG3>XXX</NEW_TAG3>|
fiddle

dzjeubhm

dzjeubhm2#

您可以通过生成XSLT来实现:

with data(xml) as (
    select xmltype(q'{<Fields><TAG1>123</TAG1><TAG2>345</TAG2></Fields>}') from dual union all
    select xmltype(q'{<Fields><TAG1>999</TAG1><TAG3>XXX</TAG3></Fields>}') from dual -- union all
),
mapping(oldtag, newtag) as (
    select 'TAG1', 'NEW_TAG1' from dual union all
    select 'TAG2', 'NEW_TAG2' from dual union all
    select 'TAG3', 'NEW_TAG3' from dual -- union all
),
xslt(xsl) as (
    select q'{<?xml version="1.0" encoding="UTF-8"?>
    <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    <xsl:template match="/">
    <Fields>}' || listagg(tr,chr(10)) within group(order by rn)
    || '</Fields>' || q'{</xsl:template>
    </xsl:stylesheet>}' as xlst from (
        select rownum as rn, '<xsl:if test="/Fields/' || oldtag || '">' 
            || '<' || newtag || '><xsl:value-of select="/Fields/' || oldtag || '"/></' || newtag || '>' 
            || '</xsl:if>' 
            as tr
        from mapping
    )
)
select xmltransform(xml,xsl)
from data, xslt
;

相关问题