Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/68.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql 如何在Oracle的XMLTABLE中包含对象列表?_Sql_Xml_Oracle_Xmltable - Fatal编程技术网

Sql 如何在Oracle的XMLTABLE中包含对象列表?

Sql 如何在Oracle的XMLTABLE中包含对象列表?,sql,xml,oracle,xmltable,Sql,Xml,Oracle,Xmltable,我有以下最小XML: <root> <person> <name>Miguel Martins</name> <age>32</age> <list_of_numbers> <number>1</number> <number>2</number> </list_of_numbers> &l

我有以下最小XML:

<root>
  <person>
    <name>Miguel Martins</name>
    <age>32</age>
    <list_of_numbers>
      <number>1</number>
      <number>2</number>
    </list_of_numbers>
  </person>

  <person>
    <name>Another Person</name>
    <age>19</age>
    <list_of_numbers>
      <number>3</number>
      <number>4</number>
    </list_of_numbers>
  </person>
</root>
到目前为止,一切顺利。现在,我想将这些数字添加到别名为T1的表中。也就是说,我希望得到以下输出:

+----------------+-----+
|      Name      | Age |
+----------------+-----+
| Miguel Martins |  32 |
| Another Person |  19 |
+----------------+-----+
+----------------+-----+-------------+
|      Name      | Age | Some_Number |
+----------------+-----+-------------+
| Miguel Martins |  32 |           1 |
| Miguel Martins |  32 |           2 |
| Another Person |  19 |           3 |
| Another Person |  19 |           4 |
+----------------+-----+-------------+
我已经尝试将some_number列添加到XMLTABLE中。即:

with my_with_clause as
 (select '
<root>
  <person>
    <name>Miguel Martins</name>
    <age>32</age>
    <list_of_numbers>
      <number>1</number>
      <number>2</number>
    </list_of_numbers>
  </person>

  <person>
    <name>Another Person</name>
    <age>19</age>
    <list_of_numbers>
      <number>3</number>
      <number>4</number>
    </list_of_numbers>
  </person>
</root>
' my_xml
    from dual)
select t1.*
  from my_with_clause,
       xmltable('/root/person' passing xmltype(my_with_clause.my_xml) columns name path 'name', age path 'age', some_number path 'list_of_numbers/number') t1;
但是,我没有得到所需的输出。相反,我得到了以下错误:

ORA-19025:EXTRACTVALUE只返回一个节点的值


我怎样才能达到预期的输出?如果需要,这里有一个供您尝试的方法。

您可以使用链式XMLTable调用:

select t1.name, t1.age, t2.some_number
from my_with_clause
cross join xmltable (
  '/root/person'
  passing xmltype(my_with_clause.my_xml)
  columns name varchar2(20) path 'name',
    age number path 'age',
    list_of_numbers xmltype path 'list_of_numbers/number'
) t1
cross join xmltable (
  '/number'
  passing t1.list_of_numbers
  columns some_number number path '.'
) t2;

NAME                        AGE SOME_NUMBER
-------------------- ---------- -----------
Miguel Martins               32           1
Miguel Martins               32           2
Another Person               19           3
Another Person               19           4
,但是,它在本地对11gR2有效。实际上

使用此XML,还可以使用一个XMLTable,方法是从数字开始,然后在节点上查找其他数据:

select t1.name, t1.age, t1.some_number
from my_with_clause
cross join xmltable (
  '/root/person/list_of_numbers/number'
  passing xmltype(my_with_clause.my_xml)
  columns name varchar2(20) path './../../name',
    age number path './../../age',
    some_number number path '.'
) t1;

NAME                        AGE SOME_NUMBER
-------------------- ---------- -----------
Miguel Martins               32           1
Miguel Martins               32           2
Another Person               19           3
Another Person               19           4

但您真正的非最小XML可能无法实现这一点

这也适用于具有多行的表,而不仅仅是CTE或具有单个XML值的表

如果有一个场景,其中名称列表缺失或为空,并且仍然希望显示名称/年龄,则可以使用外部联接而不是交叉联接,但它需要一个丑陋的on 1=1子句。显示这种数据的交叉连接和左连接,但是如果可以的话,我会避免使用左连接方法

如果你在12c或更高,你可以使用外部应用而不是左连接。。。1=1,这是相当少的攻击性。如果您不必担心丢失的数字,您可以使用交叉应用而不是交叉连接,正如@Lukasz所示——在这里似乎没有什么区别

ORA-19025很有趣。SQL Fiddle正在运行Oracle Database 11g Express Edition 11.2.0.2.0版。在Enterprise Edition 11.2.0.4中,您的代码

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

相反,这是同一个问题;每个person下有多个number节点,它不知道如何处理这些节点,因为它们是默认的数据类型-因为您没有指定数据类型,所以所有内容都以字符串的形式返回。在我的第一个版本中,我使用相同的路径,但将该列声明为XMLType,因此在第一个版本中,您可以将数字作为XML片段获得,如下所示:

<number>1</number><number>2</number>
或者在第二种情况下:

<list_of_numbers><number>1</number><number>2</number></list_of_numbers>

然后,链接的XMLTable调用可以使用这些调用。

您可以使用链接的XMLTable调用:

select t1.name, t1.age, t2.some_number
from my_with_clause
cross join xmltable (
  '/root/person'
  passing xmltype(my_with_clause.my_xml)
  columns name varchar2(20) path 'name',
    age number path 'age',
    list_of_numbers xmltype path 'list_of_numbers/number'
) t1
cross join xmltable (
  '/number'
  passing t1.list_of_numbers
  columns some_number number path '.'
) t2;

NAME                        AGE SOME_NUMBER
-------------------- ---------- -----------
Miguel Martins               32           1
Miguel Martins               32           2
Another Person               19           3
Another Person               19           4
,但是,它在本地对11gR2有效。实际上

使用此XML,还可以使用一个XMLTable,方法是从数字开始,然后在节点上查找其他数据:

select t1.name, t1.age, t1.some_number
from my_with_clause
cross join xmltable (
  '/root/person/list_of_numbers/number'
  passing xmltype(my_with_clause.my_xml)
  columns name varchar2(20) path './../../name',
    age number path './../../age',
    some_number number path '.'
) t1;

NAME                        AGE SOME_NUMBER
-------------------- ---------- -----------
Miguel Martins               32           1
Miguel Martins               32           2
Another Person               19           3
Another Person               19           4

但您真正的非最小XML可能无法实现这一点

这也适用于具有多行的表,而不仅仅是CTE或具有单个XML值的表

如果有一个场景,其中名称列表缺失或为空,并且仍然希望显示名称/年龄,则可以使用外部联接而不是交叉联接,但它需要一个丑陋的on 1=1子句。显示这种数据的交叉连接和左连接,但是如果可以的话,我会避免使用左连接方法

如果你在12c或更高,你可以使用外部应用而不是左连接。。。1=1,这是相当少的攻击性。如果您不必担心丢失的数字,您可以使用交叉应用而不是交叉连接,正如@Lukasz所示——在这里似乎没有什么区别

ORA-19025很有趣。SQL Fiddle正在运行Oracle Database 11g Express Edition 11.2.0.2.0版。在Enterprise Edition 11.2.0.4中,您的代码

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

相反,这是同一个问题;每个person下有多个number节点,它不知道如何处理这些节点,因为它们是默认的数据类型-因为您没有指定数据类型,所以所有内容都以字符串的形式返回。在我的第一个版本中,我使用相同的路径,但将该列声明为XMLType,因此在第一个版本中,您可以将数字作为XML片段获得,如下所示:

<number>1</number><number>2</number>
或者在第二种情况下:

<list_of_numbers><number>1</number><number>2</number></list_of_numbers>

然后,链接的XMLTable调用可以使用这些数据。

如果您有多行,可以轻松地使用CROSS/OUTER APPLY链接XMLTable:

主表是t,t1表示使用xmltypet.my_xml,t2表示使用t1.list_of_数字解析的xml

增编:

当所有XMLTABLE产生行时,交叉应用和交叉连接是等效的:

declare
  x VARCHAR2(2000);
begin
 dbms_utility.expand_sql_text(
        input_sql_text => q'{
          select t.id, t1.Name, t1.Age, t2."number"
from t
CROSS JOIN xmltable('/root/person' passing xmltype(t.my_xml) columns name path 'name', age path 'age', list_of_numbers xmltype path 'list_of_numbers/number') t1
CROSS JOIN xmltable('/number' passing t1.list_of_numbers columns  "number" number path '.') t2
}',
        output_sql_text => x);

  dbms_output.put_line(x);
end;
/

declare
  x VARCHAR2(2000);
begin
 dbms_utility.expand_sql_text(
        input_sql_text => q'{
          select t.id, t1.Name, t1.Age, t2."number"
from t
CROSS APPLY xmltable('/root/person' passing xmltype(t.my_xml) columns name path 'name', age path 'age', list_of_numbers xmltype path 'list_of_numbers/number') t1
CROSS APPLY xmltable('/number' passing t1.list_of_numbers columns  "number" number path '.') t2
}',
        output_sql_text => x);

  dbms_output.put_line(x);
end;
/
当我们使用XML时,差异是显而易见的,如:

<root>
  <person>
    <name>XXXX</name>
    <age>32</age>
  </person>
</root>

select t.id, t1.Name, t1.Age, t2."number"
from t
OUTER APPLY xmltable('/root/person' passing xmltype(t.my_xml) columns name path 'name', age path 'age', list_of_numbers xmltype path 'list_of_numbers/number') t1
OUTER APPLY xmltable('/number' passing t1.list_of_numbers columns  "number" number path '.') t2
交叉连接-0行


外部应用-1行

如果您有多行,您可以轻松地使用交叉/外部应用链接XMLTABLE:

主表是t,t1表示使用xmltypet.my_xml,t2表示使用t1.list_of_数字解析的xml

增编:

当所有XMLTABLE产生行时,交叉应用和交叉连接是等效的:

declare
  x VARCHAR2(2000);
begin
 dbms_utility.expand_sql_text(
        input_sql_text => q'{
          select t.id, t1.Name, t1.Age, t2."number"
from t
CROSS JOIN xmltable('/root/person' passing xmltype(t.my_xml) columns name path 'name', age path 'age', list_of_numbers xmltype path 'list_of_numbers/number') t1
CROSS JOIN xmltable('/number' passing t1.list_of_numbers columns  "number" number path '.') t2
}',
        output_sql_text => x);

  dbms_output.put_line(x);
end;
/

declare
  x VARCHAR2(2000);
begin
 dbms_utility.expand_sql_text(
        input_sql_text => q'{
          select t.id, t1.Name, t1.Age, t2."number"
from t
CROSS APPLY xmltable('/root/person' passing xmltype(t.my_xml) columns name path 'name', age path 'age', list_of_numbers xmltype path 'list_of_numbers/number') t1
CROSS APPLY xmltable('/number' passing t1.list_of_numbers columns  "number" number path '.') t2
}',
        output_sql_text => x);

  dbms_output.put_line(x);
end;
/
当我们使用XML时,差异是显而易见的,如:

<root>
  <person>
    <name>XXXX</name>
    <age>32</age>
  </person>
</root>

select t.id, t1.Name, t1.Age, t2."number"
from t
OUTER APPLY xmltable('/root/person' passing xmltype(t.my_xml) columns name path 'name', age path 'age', list_of_numbers xmltype path 'list_of_numbers/number') t1
OUTER APPLY xmltable('/number' passing t1.list_of_numbers columns  "number" number path '.') t2
交叉连接-0行

外部应用-1行

谢谢
谢谢你的回答。我可能会使用链接XMLTable调用的第一种方法。谢谢你的回答。我可能会使用链接XMLTable调用的第一种方法。很好。你总是将单个XML作为文本,还是需要一种支持多行XML的方法?@LukaszSzozda我不太理解你的问题。。。我会说是后者,但再一次,我对你的问题不是100%确定。你总是将单个XML作为文本,还是需要一种支持多行XML的方法?@LukaszSzozda我不太理解你的问题。。。我会说是后者,但我对你的问题不是100%肯定。交叉应用与交叉连接的优势是什么?它们都处理一个表中的多行-不确定何时会给出不同的结果?我得到了一份考虑到缺失号码列表的外部申请…@AlexPoole-Hmmm,你是对的,在这种情况下,它们似乎是等价的。外部应用很简单当XML在@AlexPoole没有产生结果时,交叉连接/交叉应用都使用横向连接,所以它们是相同的。横向和交叉应用是同义词,所以对我来说很明显,我有点惊讶它也能与交叉连接一起工作。是的,我通常使用交叉连接,我可能会重新考虑并使用交叉应用,至少对于不适用于11g的答案。我不确定我是否错过了什么;似乎不是,但我现在想起来,申请似乎更自然了。也许交叉连接在这里是这样工作的,因为11g没有应用程序?我在回答中放了一小段关于使用外部联接的内容,但它很难看,所以没有包含该代码,建议不要使用;并参考您的答案进行交叉/外部应用。谢谢。交叉应用与交叉连接的优势是什么?它们都处理一个表中的多行-不确定何时会给出不同的结果?我得到了一份考虑到缺失号码列表的外部申请…@AlexPoole-Hmmm,你是对的,在这种情况下,它们似乎是等价的。外部应用很简单当XML在@AlexPoole没有产生结果时,交叉连接/交叉应用都使用横向连接,所以它们是相同的。横向和交叉应用是同义词,所以对我来说很明显,我有点惊讶它也能与交叉连接一起工作。是的,我通常使用交叉连接,我可能会重新考虑并使用交叉应用,至少对于不适用于11g的答案。我不确定我是否错过了什么;似乎不是,但我现在想起来,申请似乎更自然了。也许交叉连接在这里是这样工作的,因为11g没有应用程序?我在回答中放了一小段关于使用外部联接的内容,但它很难看,所以没有包含该代码,建议不要使用;并参考您的答案进行交叉/外部应用。谢谢