如何从以前的xml查询结果中进行选择

时间:2011-06-30 04:29:48

标签: sql xml subquery oracle11g xmltype

我正在使用oracle 11g r2数据库,基本上需要能够解析并从中选择一些节点。我花了几个小时搜索网络并阅读oracle xml db手册试图为我的问题找到合适的解决方案,但我似乎无法确定这样做的正确方法。我有相当多的编程经验,但一般都没有xml,sql或oracle数据库,所以请原谅我这是一个微不足道的问题。

好的问题:

我有一个非常简单的XML文件保存为catalog.xml,它如下:

<catalog>
    <cd>
        <title>Hide your heart</title>
        <artist>Bonnie Tyler</artist>
        <country>UK</country>
        <company>CBS Records</company>
        <price>9.90</price>
        <year>1988</year>
    </cd>
    <cd>
        <title>Empire Burlesque</title>
        <artist>Bob Dylan</artist>
        <country>USA</country>
        <company>Columbia</company>
        <price>10.90</price>
        <year>1985</year>
    </cd>
</catalog>

现在我希望能够在给定某位艺术家的情况下提取CD的标题。例如,如果艺术家是'bob dylan',那么标题应该是'empire burlesque'

现在我在Oracle中创建了一个XMLType表,如下所示:

CREATE TABLE BINARY OF XMLType XMLTYPE STORE AS BINARY XML;

然后我继续通过以下方式将我的xml文件加载到oracle中:

insert into BINARY values (XMLTYPE(BFILENAME ('XML_DIR','catalog.xml'),nls_charset_id('AL32UTF8')));

到目前为止一切顺利。

现在提取部分:

首先我尝试了:

SELECT extract(b.object_value, '/catalog/cd/title')
FROM binary b
WHERE existsNode(b.object_value,'/catalog/cd[artist="Bob Dylan"]') = 1;

EXTRACT(B.OBJECT_VALUE,'/CATALOG/CD/TITLE')
--------------------------------------------------------------------------------

<Title>Hide your heart</Title>
<Title>Empire Burlesque</Title>

1 row selected.

这不起作用,因为xml文件全部在一行中,所以我意识到我必须将我的xml拆分成单独的行。这样做,我必须使用XMLSequence()和table()函数将节点转换为虚拟表。这些函数将extract()重新调整的两个标题节点转换为由两个XMLType对象组成的虚拟表,每个对象包含一个标题元素。

第二次尝试:

SELECT value(d)
FROM binary b,
table (xmlsequence(extract(b.object_value,'/catalog/cd'))) d
WHERE existsNode(b.object_value,'/catalog/cd[artist="Bob Dylan"]') = 1;

VALUE(D)
--------------------------------------------------------------------------------

<cd>
    <title>Hide your heart</title>
    <artist>Bonnie Tyler</artist>
    <country>UK</country>
    <company>CBS Records</company>
    <price>9.90</price>
    <year>1988</year>
</cd>

<cd>
    <title>Empire Burlesque</title>
    <artist>Bob Dylan</artist>
    <country>USA</country>
    <company>Columbia</company>
    <price>10.90</price>
    <year>1985</year>
</cd>

2 rows selected.

这是更好的,因为它现在被拆分为2个不同的行,所以我应该能够做一个select-where并根据艺术家选择标题。

然而,这是我遇到问题的地方,我已经尝试了几个小时,但我无法弄清楚如何在下一个查询中使用上述查询的结果。所以我试图通过这样做来使用一个suquery:

select extract(sub1, 'cd/title')
from
(
    SELECT value(d)
    FROM binary b,
    table (xmlsequence(extract(b.object_value,'/catalog/cd'))) d
) sub1
WHERE existsNode(sub1,'/cd[artist="Bob Dylan"]') = 1;

但是,sql * plus显示错误:

ORA-00904: "SUB1": invalid identifier.

我尝试了几十种尝试使用子查询的变体,但我似乎无法正确使用。

我听说你也可以使用变量或pl / sql来做这个,但我不知道从哪里开始。

任何帮助都会非常感激,因为我已经尝试了所有的东西。

1 个答案:

答案 0 :(得分:1)

这应该有效:

SELECT EXTRACTVALUE (VALUE(xml), '*/title') title
  FROM TABLE (XMLSEQUENCE (EXTRACT (XMLTYPE ('
        <catalog>
        <cd>
            <title>Hide your heart</title>
            <artist>Bonnie Tyler</artist>
            <country>UK</country>
            <company>CBS Records</company>
            <price>9.90</price>
            <year>1988</year>
        </cd>
        <cd>
            <title>Empire Burlesque</title>
            <artist>Bob Dylan</artist>
            <country>USA</country>
            <company>Columbia</company>
            <price>10.90</price>
            <year>1985</year>
        </cd>
        </catalog>'), '/catalog/cd'))) xml
WHERE EXTRACTVALUE (VALUE(xml), '*/artist') = 'Bob Dylan';

或使用你的桌子:

SELECT EXTRACTVALUE (VALUE(xml), '*/title') title
  FROM binary b,
       TABLE (XMLSEQUENCE (EXTRACT (b.object_value, '/catalog/cd'))) xml
 WHERE EXTRACTVALUE (VALUE(xml), '*/artist') = 'Bob Dylan';

这样做是将所有cd个节点提取到虚拟表xml中,为每个存在的cd节点返回一个结果行。然后 WHERE 子句通过查看子元素artist ='Bob Dylan'并且 SELECT 语句仅解析{的内容来限制结果{1}}元素,而不是显示整个节点。

输出结果为:

title