我正在使用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来做这个,但我不知道从哪里开始。
任何帮助都会非常感激,因为我已经尝试了所有的东西。
答案 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