Как выбрать из предыдущего результата XML-запроса - PullRequest
3 голосов
/ 30 июня 2011

Я работаю с базой данных 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>

Теперь я хочу иметь возможность извлечь название компакт-диска, заданного определенному исполнителю. Так, например, если художник «Боб Дилан», тогда название должно быть «империя бурлеск»

Теперь я создал таблицу XMLType в Oracle следующим образом:

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 разные строки, поэтому я должен иметь возможность выбрать где и выбрать заголовок в зависимости от исполнителя.

Однако именно здесь у меня возникают проблемы, я пытался буквально часами, но я не могу понять, как использовать результаты вышеупомянутого запроса в моем следующем. Поэтому я попытался использовать 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 Ответ

1 голос
/ 19 октября 2011

Это должно работать:

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 скорее разбирает только содержимое элемента title чем отображение всего узла.

Вывод:

TITLE
----------------
Empire Burlesque
...