Запрос XML-данных при помощи языка XQuery (исходники)Источник: IBM developerWorks Россия Дон Чамберлин (Don Chamberlin), Синтия M. Саракко (Cynthia M. Saracco)
Возможно, вы уже слышали о новой архитектуре DB2 Viper, поддерживающей как табличную, так и иерархическую структуры данных. Действительно, в предыдущих статьях мы рассматривали новые функции DB2 для работы с XML-данными, рассказывали, как создавать объекты базы данных и заполнять их XML-данными и объясняли, как работать с XML-данными при помощи языков запросов SQL и SQL/XML. В этой статье мы продолжим изучение возможностей работы с XML-данными в программе DB2, фокусируясь, главным образом, на новой особенности программы - поддержке языка запросов XQuery. В DB2 язык XQuery рассматривается как полноценный язык, что позволяет пользователям сразу записывать выражения XQuery, не требуя внедрения или встраивания выражений XQuery в оболочку предложений SQL. Более того, механизм запросов DB2 обрабатывает запросы XQuery в свойственной этому языку системе команд, это означает, что выражения XQuery анализируются, оцениваются и оптимизируются без скрытой от пользователя трансляции на язык SQL. Конечно, если вы захотите написать "двуязычный" запрос, который содержит одновременно выражения XQuery и SQL, DB2 обработает и оптимизирует и такие запросы. Как и в статье по SQL/XML "Запрос XML-данных в среде DB2 при помощи языка SQL": в этой статье вы найдете обзор нескольких обычных для запросов задач и увидите, как можно использовать язык XQuery для решения этих задач. Но сначала вкратце рассмотрим отличия языка XQuery от SQL. Язык XQueryXQuery во многом отличается от SQL, главным образом, потому, что эти языки разрабатывались для работы с различными моделями данных, имеющими разную структуру. Документ в формате XML содержит иерархии, для него характерен внутренний порядок. Табличные структуры данных, поддерживаемые СУБД на базе SQL, являются однородными и линейными, строки, как таковые, неупорядочены. Различия между этими моделями данных привели к нескольким принципиальным отличиям в соответствующих им языках запросов. Например, XQuery поддерживает выражения пути, что позволяет программистам перемещаться по иерархической структуре документа XML, в то время как "чистый" SQL (без расширений XML) не допускает такой возможности. XQuery поддерживает как типизированные, так и не типизированные данные, а для данных SQL всегда определен конкретный тип. В XQuery нет нулевых значений, поскольку в документах XML недостающие или неизвестные данные пропускаются, а SQL, как известно, использует нули для представления недостающих или неизвестных значений данных. XQuery возвращает последовательности данных XML; SQL возвращает наборы результатов, состоящие из различных типов данных SQL. Это только некоторые из принципиальных различий между XQuery и SQL. В рамках этой вводной статьи не приводится исчерпывающий список таких отличий, но они будут подробно рассматриваться в следующем номере журнала IBM Systems Journal. А сейчас давайте перейдем к изучению некоторых основных аспектов языка XQuery и способов его использования для запроса XML-данных в программе DB2 Viper. База данных для упражненийЗапросы, описанные в этой статье, обращаются к примерам таблиц, создание которых описано в статье "Начинаем работать с программой DB2 Viper". Коротко: листинг 1 определяет примеры таблиц "items" и "clients".
Примеры XML-данных, включенных в столбец "items comments", показаны на рисунке 1, а примеры XML- данных, включенных в столбец "clients contactinfo" - на рисунке 2. Последующие примеры запросов будут ссылаться на конкретные элементы одного или сразу обоих документов XML. Рисунок 1. Пример документа XML сохранен в столбце "comments" таблицы "items"
Рисунок 2. Пример документа XML сохранен в столбце "contactinfo" таблицы "clients"
Среда запросаВсе запросы в этой статье разработаны для того, чтобы вы могли повторить их на своем компьютере. Это можно сделать через обработчик командной строки программы DB2 или редактор команд DB2 Command Editor модуля DB2 Control Center. Изображения снимков экрана и инструкции в данной статье относятся ко второму варианту (DB2 Viper поставляется со средой разработчика Developer Workbench на базе платформы Eclipse, что может помочь программисту конструировать запросы наглядным способом. В этой статье проблемы разработки приложений в среде разработки Developer Workbench не рассматриваются). Для использования редактора команд DB2 Command Editor, откройте Control Center и выберите команду Tools -> Command Editor. На экране появится окно, показанное на рисунке 3 . В верхней панели введите запрос, затем нажмите зеленую стрелку в верхнем левом углу, чтобы выполнить его, и просмотрите полученные результаты в нижней панели или на отдельной вкладке "Query Results". Рисунок 3. Окно DB2 Command Editor, которое может быть вызвано из DB2 Control Center
Примеры запросов XQueryКак и в статье "Запрос XML-данных в среде DB2 при помощи языка SQL": здесь мы рассмотрим несколько распространенных бизнес-сценариев и продемонстрируем, как использовать язык XQuery, чтобы запрос соответствовал требованиям для XML-данных. В статье будут также рассмотрены более сложные ситуации, которые потребуют внедрения в запрос XQuery кода SQL. В XQuery существует несколько различных видов выражений, которые можно комбинировать в любых сочетаниях. Каждое выражение возвращает список значений, которые могут быть использованы как исходные данные для других выражений. Результат того выражения, в которое вложены все остальные выражения, является результатом всего запроса в целом. В этой статье описываются два важных типа выражений XQuery: это выражения "FLWOR" и выражения пути. Выражения FLWOR подобны выражениям Подобно выражению
Выражение пути в XQuery состоит из серии "шагов", разделенных символом "косой черты". В простейшей форме, каждый шаг ведет вниз по иерархии XML, чтобы найти потомка для элемента, возвращенного на предыдущем шаге. Каждый шаг в выражении пути может также содержать предикат, который фильтрует элементы, возвращенные на этом шаге, оставляя только те из них, которые удовлетворяют некоторым условиям. Например, представим, что переменная В большинстве случаев можно написать запрос, используя одно из двух выражений - либо выражение FLWOR, либо выражение пути. Использование в DB2 XQuery в качестве основного языка запросов Для выполнения запросов XQuery непосредственно в среде DB2 Viper (в отличие от внедрения их в предложения SQL) следует предпослать запросу ключевое слово При выполнении в качестве основного языка запросов, XQuery требуется источник данных для ввода. Один из методов, который XQuery может использовать, чтобы получить данные для ввода, это вызов функции Листинг 2. Простой запрос XQuery, возвращающий контактные данные
Вспомните нашу схему базы данных (см. раздел "База данных для упражнений" ): мы сохраняли такие XML-документы в столбце "contactinfo" таблицы "clients". Обратите внимание, что имена столбца и таблицы в данном случае отображаются в верхнем регистре. Это объясняется тем, что имена таблицы и столбца перед записью во внутренний каталог DB2 обычно переводятся в верхний регистр. Язык XQuery является регистрозависимым, поэтому имена таблиц и столбцов, записанные в нижнем регистре, не соответствовали бы именам в каталоге DB2, записанным в верхнем регистре. Извлечение определенных элементов XML Давайте начнем с основной задачи. Предположим, необходимо извлечь номера факсов всех клиентов, предоставивших эту информацию. листинга 3 описывается один из возможных способов составления такого запроса: Листинг 3. Поиск данных о номере факса клиента при помощи выражения FLWOR
В первой строке листинга содержится указание для DB2 о необходимости вызова анализатора языка XQuery. В следующей строке DB2 получает указание выполнить итерацию на вложенных элементах элементов Client, содержащимся в столбце CLIENTS.CONTACTINFO. Каждый элемент fax по очереди связывается с переменной $y. Третья строка показывает, что для каждой итерации возвращается значение переменной $y. Результат представляет собой последовательность элементов XML, показанную в листинге 4: Листинг 4. Пример вывода данных для предыдущего запроса
Отступив от темы, заметим, что вывод может также содержать некоторую информацию, не представляющую большого интереса для данной статьи: версия XML и кодировка данных, например, Запрос из листинга 3 мог бы выглядеть чуть более лаконичным, если бы был решен в форме трехшагового выражения пути, как показано в листинге 5: Листинг 5. Поиск данных о номере факса клиента при помощи выражения пути
Первым шагом выражения пути осуществляется вызов функции Если вы не заинтересованы в получении по запросу кода XML-фрагментов, и вам нужно только текстовое представление выбранных значений элемента XML, то вы можете включить в предложение Листинг 6. Два запроса на выборку текстового представления данных о номере факса клиента
Вывод этих запросов может быть примерно таким, как показано в листинге 7: Листинг 7. Пример вывода возвращаемых данных для предыдущего запроса
Результаты этих учебных запросов относительно просты, потому что элемент fax имеет в основе примитивный тип данных. Безусловно, в основе элементов могут быть и сложные типы, то есть, элементы могут содержать вложенные элементы (или вложенные иерархии). Элемент Address из контактной информации нашего клиента - один из примеров таких данных. В соответствии со схемой, которая приводится в статье "Начинаем работать с программой DB2 Viper", этот элемент может содержать название улицы, номер дома и квартиры, название города, штата и почтовый индекс. Подумаем, какие данные возвращает запрос XQuery в (листинг 8) : Листинг 8. Запрос на выборку сложного типа данных XML при помощи выражения FLWOR
Если вы решили, что правильный ответ - это последовательность фрагментов XML-данных, содержащая элементы Address и все вложенные элементы, то вы не ошиблись В листинге 9 - пример такого вывода данных: Листинг 9. Пример вывода возвращаемых данных для предыдущего запроса
Примечание: Данный пример представлен в форматированном виде, чтобы облегчить его чтение. Редактор команд DB2 Command Editor отображает каждую запись адреса клиента отдельной строкой. Фильтрация значений элементов XMLПредыдущие примеры запросов XQuery можно сделать более избирательными. Для примера давайте проанализируем, как можно получить результат, который содержит почтовые адреса, соответствующие почтовому индексу 95116, для всех клиентов. Можно предположить, что предложение Листинг 10. Выражение FLWOR с новым предложением "where"
Добавленное выражение Такой же результат можно получить, добавив к выражению пути предикат, как показано в листинге 11: Листинг 11. Выражение пути, в которое добавлен фильтрующий предикат
Конечно, вы можете указать в качестве условия фильтрации значение почтового индекса, и тогда будут возвращены элементы независимо от названия улицы и номера дома. Более того, вы также можете выполнить фильтрацию по нескольким значениям элементов XML в одном запросе. Следующий запрос возвращает информацию об адресах электронной почты тех клиентов, чей адрес соответствует конкретному почтовому индексу Нью-Йорка (10011) или любых клиентов проживающих в городе Сан-Хосе. Листинг 12. Фильтрация результатов запроса по нескольким элементам XML при помощи выражения FLWOR
Обратите внимание, что мы изменили предложение Этот же запрос можно сделать более лаконичным, используя выражение пути: Листинг 13. Фильтрация результатов запроса по нескольким элементам XML при помощи выражения пути
При рассмотрении этих двух форм запросов не так очевидно то, что любая из них возвращает результаты, которые по двум направлениям существенно отличаются от тех, которые мог бы ожидать программист SQL:
Любая из двух ситуаций может быть желательной при одних обстоятельствах и нежелательной при других. Например, если вам нужно отправить по электронной почте уведомление каждому соответствующему критериям запроса зарегистрированному клиенту, то итерация по списку адресов электронной почты клиентов в формате XML может быть выполнена в любом приложении. Однако, если вы хотите послать строго одно уведомление каждому клиенту, включая и тех, кто предоставил вам только почтовый адрес, в этом случае описанный ранее запрос XQuery не обеспечит нужного результата. Существует несколько способов переделать запрос таким образом, чтобы он возвратил результаты, представляющие собой смешанную информацию в одной форме, c указанием тех случаев, когда несколько адресов электронной почты были извлечены из одной записи о клиенте (то есть, из одного документа XML). Давайте ознакомимся с одним из способов. Но если все, чего вы хотите - это получить список, содержащий один адрес электронной почты для каждого соответствующего критериям запроса клиента, вам следует лишь слегка изменить предложение Листинг 14. Извлечение только первого элемента email для каждого клиента
Этот запрос вынуждает DB2 возвратить первый из адресов электронной почты, который она обнаружит внутри каждого соответствующего критериям поиска XML-документа (записи о контактных данных клиента). Если адрес электронной почты для клиента, соответствующего критериям запроса, не будет обнаружен, то для этого пользователя в результате запроса не будет содержаться никакой информации. Преобразование вывода XMLЗамечательная особенность XQuery - это возможность преобразовать XML-результат запроса из одной формы XML в другую. Например, вы можете использовать запрос XQuery для выборки всех или части хранимых документов XML и преобразовать вывод в формат HTML, который можно просмотреть в веб-браузере. Следующий запрос (листинг 15) осуществляет выборку адресов клиентов с сортировкой результатов по почтовому индексу, и преобразует результат в элементы XML, являющиеся частью неупорядоченного списка HTML: Листинг 15. Выполнение запроса к DB2 на выборку XML-данных и возвращение результата в формате HTML
Запрос начинается достаточно просто с ключевого слова Третья строка выполняет итерацию на последовательности адресов клиентов, связывая переменную $y по очереди с каждым элементом address. Четвертая строка включает новое предложение Вывод будет отображен так, как показано в листинге 16: Листинг 16. Пример HTML-вывода для предыдущего запроса
Давайте обдумаем тему, которая обсуждалась раньше: как написать запрос XQuery, чтобы в возвращенных результатах были показаны пропущенные значения и отмечены случаи, когда один XML-документ (например, одна запись о клиенте) содержит повторяющиеся элементы (такие, как несколько адресов электронной почты). Один из способов - включить возвращаемые данные в новый элемент XML, как показано в следующем запросе в листинге 17: Листинг 17. Отображение недостающих значений и повторяющихся элементов в результатах запроса XQuery
Выполнив этот запрос, мы получим возвращенные данные в виде последовательности элементов "emailList", причем один элемент будет соответствовать одной записи о клиенте. Каждый элемент emailList будет содержать адрес электронной почты. Если DB2 обнаружит в записи клиента единственный адрес электронной почты, то будет возвращен этот элемент и его значение. При обнаружении несколько адресов будут возвращены все элементы e-mail вместе с их значениями. Наконец, если не будет найдено ни одного адреса электронной почты, то будет возвращен пустой элемент emailList. Таким образом, вывод может выглядеть следующим образом: Листинг 18. Пример вывода для предыдущего запроса
Использование условной логикиСпособность XQuery трансформировать результаты запроса XML можно для снижения сложности кода приложения комбинировать с встроенной в язык поддержкой условной логики . Давайте рассмотрим простой пример. Таблица "items" содержит столбцы XML с комментариями, сделанными клиентами по поводу продукции. Для клиента, который запросил ответ на свои комментарии, вам, возможно, захочется создать новые элементы "action", содержащие идентификатор продукта, идентификатор клиента и сообщение, чтобы эту информацию можно было отправить соответствующему лицу для обработки. Однако комментарии, не требующие ответа, тем не менее, имеют значение для бизнеса, и вы не хотели бы просто игнорировать их. Для этих комментариев создайте элемент "info", включающий только идентификатор продукта и сообщение. В следующем листинге показано, как можно для решения этой задачи использовать выражение XQuery Листинг 19. Использование выражения "if-then-else" в запросе XQuery
Большая часть аспектов этого запроса должна быть понятна вам уже сейчас, так что давайте сконцентрируемся на условной логике. Предложение Использование предложения "let"Мы уже рассмотрели как использовать все части выражения FLWOR кроме одной: речь идет о предложении Предположим, что вы хотите составить список, показывающий, сколько комментариев было получено, для каждого продукта в отдельности. Это можно сделать при помощи следующего запроса: Листинг 20. Использование предложения "let"
Функция Результаты запроса могут выглядеть примерно так: Листинг 21. Пример вывода для предыдущего запроса
Запросы XQuery c вложенным SQLК этому моменту мы рассмотрели, как составлять запросы XQuery, которые осуществляют выборку фрагментов XML-документа, создают новые формы вывода XML и возвращают различные результаты на основании условий, определенных в самих запросах. Другими словами, вы познакомились с несколькими способами использования языка XQuery для составления запроса на выборку XML-данных, хранимых в DB2. Конечно, весь язык XQuery нельзя изучить, прочитав такую короткую статью. Но мы не можем пропустить обширную тему, которую до сих пор не рассматривали: как встроить код SQL в запрос XQuery. Это может оказаться полезным, если вам нужно составить запросы, которые осуществляют фильтрацию данных по XML- и не-XML значениям столбцов. Вспомните статью "Запрос XML-данных в среде DB2 при помощи языка SQL": в ней шла речь о том, как использовать для решения этой задачи простые выражения XQuery, встроенные в предложения SQL. В этой статье попробуем сделать наоборот: встроим в запрос на языке XQuery код SQL, чтобы ограничить результат по значениям как в традиционном формате данных SQL, так и в специфическом формате элементов XML. Вместо того, чтобы вызвать функцию Запрос, описанный в листинге 22 , осуществляет поиск информации о комментариях, относящихся к продуктам с рекомендуемой розничной ценой (*srp*) более 100 долларов вместе с запросом ответа от клиента. Вспомним, что данные о цене хранятся в десятичном столбце в формате SQL, тогда как комментарии клиентов хранятся как XML-данные. Возвращенные данные, включая идентификатор продукта, идентификатор клиента и сообщение клиента для каждого соответствующего критерию запроса комментария, хранящегося в базе данных, включается в отдельный элемент XML "action". Листинг 22. Встраивание кода SQL в запрос XQuery
И снова, большая часть аспектов этого запроса должна быть понятна вам уже сейчас, так что давайте сконцентрируемся на новой функции. С учетом вышесказанного, давайте подумаем, как можно решить другую задачу, которая немного отличается от первой. Представьте, что вам нужно получить список адресов электронной почты для "особо ценных" клиентов, проживающих в городе Сан-Хосе.Кроме того, если для одного клиента в базе данных имеется несколько адресов электронной почты, то вы хотите включить их все в вывод запроса таким образом, чтобы они были частью отдельной записи о клиенте.. И, наконец, если соответствующий критериям отбора "особо ценный" клиент не предоставил адреса электронной почты, вы хотите получить его обычный почтовый адрес. Листинг 23 иллюстрирует один из способов составления такого запроса: Листинг 23. Встраивание кода SQL в тело запроса XQuery, который содержит условную логику
Два аспекта этого запроса нуждаются в некотором объяснении. Во-первых, предложение Кроме того, предложение ИндексированиеИ наконец, ничего не стоит научиться создавать специализированные индексы XML для ускорения доступа к данным, хранимым в столбцах XML. Мы не будем рассматривать эту тему в данной статье из-за вводного характера статьи и малого объема данных для упражнений. Однако, в производственной обстановке определение соответствующих индексов может быть критически важным для достижения оптимальной производительности. Чтобы Ресурсы больше узнать о новой технологии индексирования в DB2, обратитесь к источникам из раздела "Ресурсы". ЗаключениеЯзык XQuery имеет много существенных отличий от языка SQL; некоторые из них были освещены в этой статье. Более детальное изучение этого языка поможет вам определить, в каких случаях можно с выгодой использовать его в работе, а также понять, когда может оказаться полезным совместное использование XQuery и SQL. В следующей статье мы углубимся в еще одну тему, которая может показаться вам интересной: как разработать Java-приложения, использующие возможности работы с XML в DB2. Впрочем, и в этой статье содержится маленький пример, как можно внедрить в запрос XQuery Java-приложение. |