ORA-19279:XPTY0004 - XQuery动态类型不匹配:预期的单例序列

时间:2017-02-22 12:31:50

标签: sql xml oracle oracle11g

我对XML很陌生,我希望在此列出所有相关信息。如果没有,请不要发送负面反馈。如果您告诉我您缺少哪些信息,我将不胜感激。

我无法在Oracle Database 11g上的XML视图中的多个元素上正确运行查询。

我有多个XML文件,结构如下:

<Qualitaetsbericht>
    <Organisationseinheiten_Fachabteilungen>
         <Organisationseinheiten_Fachabteilung>
               <Fachabteilungsschluessel>
               <Prozeduren>
                  <Freiwillig>
                  <Verpflichtend>
                      <Prozedur>
                         <OPS_301>
                         <Anzahl>

我通常得到以下查询的正确结果:

SELECT id, 
       d."FA_SCHLUESSEL",d."OPS_301",
       CASE WHEN d."ANZAHL" IS NULL THEN '4' ELSE d."ANZAHL" END AS ANZAHL,
       d."GLIEDERUNGSNUMMER",d."NAME"
FROM   XMLDocs x,
XMLTable(
'/Data'
PASSING XMLQuery(
'for $i in /Qualitaetsbericht./Organisationseinheiten_Fachabteilungen/Organisationseinheit_Fachabteilung/Prozeduren/Verpflichtend/Prozedur
return <Data>
                 {$i/OPS_301}
                 {$i/Anzahl}
                 {$i/../../../Fachabteilungsschluessel/FA_Schluessel}
                 {$i/../../../Gliederungsnummer}
{$i/../../../Name}
</Data>'
PASSING doc
RETURNING CONTENT
)
COLUMNS FA_Schluessel varchar2(12) path 'FA_Schluessel',
        OPS_301      varchar2(12) path 'OPS_301',
        Anzahl        varchar2(40) path 'Anzahl',
        Gliederungsnummer varchar2(10) path 'Gliederungsnummer',
        Name varchar2(600) path 'Name'
) d

但是还有一个可能发生的元素     

如果在XML中给出了此元素,则上面的查询会遇到动态类型不匹配错误。

我想出了

<Fachabteilungsschluessel> 

承担这种结构

<Fachabteilungsschluessel>
   <FA_Schluessel>

<Fachabteilungsschluessel>
   <Sonstiger>
       <FA_Sonstiger_Schluessel>

每当

<Fachabteilungsschluessel>
   <Sonstiger>
       <FA_Sonstiger_Schluessel>

出现在XML文档中我收到错误代码:

ORA-19279: XPTY0004 - XQuery dynamic type mismatch: expected singleton sequence - got multi-item sequence

我希望这是一个容易解决的问题。目前我的想法已经不多了。有人可以帮忙吗? - 提前谢谢。

此处的示例文件:
file

1 个答案:

答案 0 :(得分:2)

问题在于重复的节点。在您的第二个Organisationseinheit_Fachabteilung节点(其中Gliederungsnummer为2)中,有两个 Fachabteilungsschluessel个节点,每个节点都有FA_Schluessel - 0193和0300。

在您的XMLQuery中,您将从Prozedur个节点开始,然后引用该结构以查找../../../Fachabteilungsschluessel/FA_Schluessel。在这种情况下,它会找到两个匹配项 - 即预期单个项目的多个项目。

您可以调整XMLQuery的XPath以使用嵌套循环,但它有点乱,难以理解,而且在使用2.5MB文件进行测试时速度也很慢:

...
PASSING XMLQuery(
'for $i in /Qualitaetsbericht/Organisationseinheiten_Fachabteilungen/Organisationseinheit_Fachabteilung
for $j in $i/Prozeduren/Verpflichtend/Prozedur
return <Data>
                 {$j/OPS_301}
                 {$j/Anzahl}
                 {$i/Fachabteilungsschluessel/FA_Schluessel}
                 {$i/Gliederungsnummer}
                 {$i/Name}
</Data>'
PASSING doc
RETURNING CONTENT
)
...

虽然你不需要单独的XMLQuery,但XMLTable的XPath可以自己完成所有这些。

您可以使用多个级别的XMLTable:

SELECT xd.id, 
       x3.fa_schluessel,
       x2.ops_301,
       CASE WHEN x2.anzahl IS NULL THEN '4' ELSE x2.anzahl END AS anzahl,
       x1.gliederungsnummer,
       x1.name
FROM   XMLDocs xd
CROSS JOIN XMLTable(
  '/Qualitaetsbericht/Organisationseinheiten_Fachabteilungen/Organisationseinheit_Fachabteilung'
  PASSING doc
  COLUMNS gliederungsnummer varchar2(10) path 'Gliederungsnummer',
          name varchar2(600) path 'Name',
          prozeduren XMLType path 'Prozeduren',
          fa_schluessel XMLType path 'Fachabteilungsschluessel/FA_Schluessel'
) x1
CROSS JOIN XMLTable(
  '/Prozeduren/Verpflichtend/Prozedur'
  PASSING x1.prozeduren
  COLUMNS ops_301 varchar2(12) path 'OPS_301',
          anzahl varchar2(40) path 'Anzahl'
) x2
CROSS JOIN XMLTable(
  '/FA_Schluessel'
  PASSING x1.fa_schluessel
  COLUMNS fa_schluessel varchar2(12) path '.'
) x3
/

与您的示例数据文件一起获取:

        ID FA_SCHLUESSE OPS_301      ANZAHL                                   GLIEDERUNG NAME                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    
---------- ------------ ------------ ---------------------------------------- ---------- ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
        42 0100         1-204.2      4                                        1          Notfallmedizin                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          
        42 0100         1-207.0      5                                        1          Notfallmedizin                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          
        42 0100         1-208.3      4                                        1          Notfallmedizin                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          
        42 0100         1-208.6      4                                        1          Notfallmedizin                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          
        42 0100         1-266.0      4                                        1          Notfallmedizin                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          
        42 0100         1-610.2      4                                        1          Notfallmedizin                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          
        42 0100         1-844        4                                        1          Notfallmedizin                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          
        42 0100         3-052        5                                        1          Notfallmedizin                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          
        42 0100         3-200        67                                       1          Notfallmedizin                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          
...

第一个XMLTable直接在Organisationseinheit_Fachabteilun节点下获取数据,并且还将每个节点的子Prozeduren和'Fachabteilungsschluessel / FA_Schluessel`片段作为单独的XMLTypes获取,这些XMLType可以具有多个节点。然后将这些片段传递给第二个和第三个XMLTables,它们提取较低级别的数据。

使用此模型,可以有多个父节点,每个节点都有多个子节点。

如果你有另一个repeatng节点,你可以将其作为另一个XMLType片段提取,并添加第四个XMLTable:

...
  COLUMNS gliederungsnummer varchar2(10) path 'Gliederungsnummer',
          name varchar2(600) path 'Name',
          prozeduren XMLType path 'Prozeduren',
          fa_schluessel XMLType path 'Fachabteilungsschluessel/FA_Schluessel',
          fa_sonstiger_schluessel XMLType
            path 'Fachabteilungsschluessel/Sonstiger/FA_Sonstiger_Schluessel'
) x1
...
CROSS JOIN XMLTable(
  '/FA_Sonstiger_Schluessel'
  PASSING x1.fa_sonstiger_schluessel
  COLUMNS fa_sonstiger_schluessel varchar2(12) path '.'
) x4

...然后可以在主选择列表中使用x4.fa_sonstiger_schluessel

当您添加更多交叉联接时,性能可能会受到影响。