Кафедра «ОСУ» Весенний семестр 2010/2011 уч. года Языки описания информации Лекция ХХХ. Работа с XML данными в реляционных СУБД Использование XML документов • XML документы используются для описания информации. • Они могут использоваться для хранения и обработки. – в документах файловой системы; – в базах данных (в поля записей). • Обработка: – обработка в программе; – обработка с помощью процессоров (XSLT процессор, XQuery процессор); – передача в сообщениях. Зачем хранить XML-данных в SQL сервере • Требуется эффективно распространять, запрашивать и изменять свои XML-данные на основе транзакций. – Большое значение имеет высокая детализация доступа к данным. – Например, иногда нужно извлекать некоторые разделы XML-документа или вставлять в него новые разделы без замены всего документа. • Необходимо совместно использовать как реляционные, так и XML-данные, и обеспечить их совместимость в приложении. • Необходима единая языковая поддержка запросов и модификации данных в различных приложениях. Зачем хранить XML-данных в SQL сервере (2) • Требуется, гарантировал правильность структуры данных (выполнение проверки данных в соответствии с XML-схемами). • Требуется индексировать XML-данные для оптимизации обработки запросов и улучшения масштабируемости и использовать эффективный оптимизатор запросов. • Требуется обращаться к XML-данным, используя технологии SOAP, ADO.NET и OLE DB. • Требуется использовать для управления XML-данными средства администрирования, реализованные в сервере баз данных. – Примерами таких задач управления могут служить резервное копирование данных, их восстановление и репликация. • Если ни одно из этих условий не выполняется, то для хранения данных лучше использовать тип данных отличный от XML, например типы данных для хранения больших объектов (например, [n]varchar(max) или varbinary(max)). Поддержка работы с XML в СУБД SQL Server • Для поддержки новых требований к обработке данных, Microsoft добавил в SQL Server возможности работы с XML данными начиная с SQL Server 2000. • SQL Server 2008 предоставляет следующие возможности работы с XML: – поддержка нового типа данных “xml”; – поддержка запросов XQuery; – возможность указывать запросы XQuery к XML-данным, хранящимся в столбцах и переменных типа «xml»; – возможность выполнять массовую загрузку XML-данных с помощью расширенной инструкции OPENROWSET, позволяющие ; – расширения в предложении FOR XML и функции OPENXML, впервые реализованные в SQL Server 2000. Поддержка работы с XML в SQL Server 2008 • Поддержка работы с XML в SQL Server 2008 может быть разделена на три большие категории: – возможности формировать XML документы (из реляционных данных); – возможности выполнять грамматический разбор и запросы к XML документам, хранящимся в XML полях; – возможности выполнять проверку XML документов. Варианты хранения XML-данных SQL Server поддерживает несколько вариантов хранения XML-данных. – Хранение в виде XML типа данных. – Сочетание XML типов данных и реляционном данных. – Хранение XML данных в виде больших объектов, [n]varchar(max) и varbinary(max). – Гибридная модель • Обычно используется сочетание этих подходов. – Например, XML-данные можно сохранить в столбце типа xml, производя продвижение его свойств до уровня реляционных столбцов. – Либо можно использовать технологию сопоставления для хранения нерекурсивных фрагментов в столбцах, отличных от XML, а в столбцах типа xml хранить только рекурсивные фрагменты. Хранение в виде типа данных XML. • Данные при этом хранятся во внутреннем представлении, которое обеспечивает неизменность XML-содержимого данных. • Это внутреннее представление включает в себя сведения об иерархии контейнеров, порядке документов и значений элементов и атрибутов. • Точнее говоря, при этом обеспечивается неизменность InfoSetсодержимого XML-данных. • InfoSet-содержимое не всегда идентично текстовым XML-данным, потому что следующая информация при этом не сохраняется: несущественные пробелы, порядок атрибутов, префиксы пространств имен и XML-декларация. • Для типизированного (то есть связанного с XML-схемой) типа данных xml модуль проверки после обработки схемы (PSVI) добавляет в информационный набор данные о типах и кодирует их во внутреннее представление. Это значительно ускоряет синтаксический анализ. Хранение XML данных в виде больших объектов • XML данных можно хранить в виде больших объектов в полях типа [n]varchar(max) и varbinary(max). • При этом хранится идентичная копия данных. • Это полезно в приложениях специального назначения, например в приложениях, обрабатывающих юридическую документацию. • Большинству приложений точная копия данных не нужна — им хватает XML-содержимого (правильности элементов InfoSet). Сочетание XML типов данных и реляционном данных • Используя аннотированную схему (AXSD), можно разбить XML на столбцы одной или нескольких таблиц. • Это обеспечивает правильность данных на реляционном уровне. • В результате гарантируется сохранность иерархической структуры данных, хотя порядок элементов не учитывается. • Схема не может быть рекурсивной. Технология XML View • Путем определения взаимосвязи между XML схемами и таблицами в БД можно создать "XML view" имеющихся реляционных данных. • Для ввода данных в используемые XML view таблицы может использоваться массовая XML загрузка. • Можно выполнять запросы к XML view с помощью XPath; такой запрос транслируется в SQL запросы к таблицам. • Аналогично обновления также распространяются по всем таблицам. Достоинства технологии XML View • Технология XML-view полезна в следующих ситуациях: – Нужна программная модель ориентированная на XML для работы с существующими реляционными данными. – Имеется схема (XSD, XDR) для XML данных, которую предоставил внешний партнер. – Порядок в данных не важен, или запросы к данным в таблицах не являются рекурсивными, или максимальная глубина рекурсии известна заранее. – Требуется выполнять запросы и изменять данные с помощью XML view, используя XPath. – Нужна массовая загрузка XML данных и их декомпозиция на нижележащие таблицы, с помощью XML view. • Например, реляционные данные представляются в виде XML данных для обмена данными и работы Web сервисов, и XML данные имеют фиксированную схему. Пример: моделирование данных с помощью аннотированной XML Schema (AXSD) • Предположим, что имеются следующие данные, которые хотелось бы обрабатывать, как XML данные: – customers (клиенты), – orders (заказы) и – товары заказов (line items), • Для этого нужно: – Описать XML view используя AXSD над реляционными данными. – XML view позволяет выполнять массовую загрузку XML данных в таблицы, выполнять запросы и обновления реляционных данных с помощью XML view. – Такая модель является полезной, если требуется обмениваться данными, содержащими XML разметку, с другими приложениями, и при этом не нарушать работу уже имеющихся SQL приложений. • Взаимосвязь между XML и реляционным хранилищем выполняется с помощью аннотированных схем (annotated schema, AXSD), • XML данные делятся по колонкам одной или нескольких таблиц. Это сохраняет поддержку XML данных на реляционном уровне. • В результате этого, сохраняется иерархическая структура, хотя порядок следования элементов игнорируется. <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:sql="urn:schemas-microsoft-com:mapping-schema"> <xsd:element name="Employee" sql:relation="Employees" > <xsd:complexType> <xsd:sequence> <xsd:element name="FName" sql:field="FirstName” type="xsd:string" /> <xsd:element name="LName“ sql:field="LastName“ type="xsd:string" /> </xsd:sequence> <xsd:attribute name="EmpID“ sql:field="EmployeeID“ type="xsd:integer" /> </xsd:complexType> </xsd:element> </xsd:schema> Гибридная модель • Часто для моделирования данных подходящей является комбинация колонок с реляционными и xml типами данных. – Некоторые из значений из XML данных могут быть сохранены в реляционных колонках, а оставшиеся или все XML значение может быть сохранено в XML колонке. – Это может дать лучшую производительность, так как при использовании реляционных колонок имеется больше контроля над индексами и параметрами связывания. Гибридная модель (2) • Какие значения хранить в реляционных колонках зависит от степени их использования (workload). – Например, если все XML значения получаются с использованием XPath выражения (например, /Customer/@CustId), то перенос значения атрибута CustId в реляционную колонку и ее индексирование, может повысить скорость обработки запросов. – С другой стороны, если значительную часть XML данных неизбыточно декомпозировать в реляционные колонки, то значительно увеличатся и затраты на их сборку (reassembly). • Для сильно структурированных XML данных, например, если содержание таблицы было конвертировано в XML; то можно отобразить все значения в реляционные колонки и можно использовать технологию XML view. Названия таблиц • В СУБД используются схемы: • <имя БД>.<схема1> … <схемаN>.<название таблицы> Формат XML может использоваться только как формат вывода данных • Формат XML может использоваться только, как временный формат вывода данных, полученных из реляционных данных с помощью FOR XML. • Такой подход применяется в таких сценариях, когда реляционные таблицы содержат текущие данные, а XML формат создается только для их чтения приложениями, например, для отображения динамических web страниц. • В таком сценарии, XML просто предоставляет независимые от СУБД, легкие для преобразования представления данных. XML данные могут сохраняться в реляционных колонках • XML can be stored in relational (nvarchar and so on) columns. • This might be the best option when your XML is sometimes not well formed or when the learning curve to XQuery is too high for an application-delivery time frame. • This is also a valuable option when the bytefor-byte exactness of the XML must be preserved. XML данные могут сохраняться в колонках специального типа данных XML • XML данные могут хранится, как не типизированный XML, т.е. XML хранится в колонках типа «xml data» без использования коллекции схем. Расширение FOR XML для оператора SELECT Формирование XML данных с помощью FOR XML • Можно выполнять запросы SQL, возвращающие результаты в формате XML, а не в виде стандартных наборов строк. • Такие запросы могут выполняться как напрямую, так и из хранимых процедур или пользовательских функций. • Для получения результатов напрямую сначала необходимо использовать предложение FOR XML инструкции SELECT. Затем необходимо задать режим XML внутри предложения FOR XML: RAW, AUTO, EXPLICIT или PATH. Формирование XML документов • В языке T-SQL к оператору SELECT добавлены новые ключевые слова FOR XML, который преобразует результаты запроса SELECT в XML формат. • Директивы AUTO, RAW, EXPLICIT и PATH позволяют управлять структурой формируемого XML документа; • Оператор FOR XML совместно с директивами RAW, AUTO, PATH и EXPLICIT позволяет генерировать XML документы, удовлетворяющие почти всем требованиям языка XML. Использование AUTO, RAW, EXPLICIT и PATH • Директивы AUTO, RAW, EXPLICIT и PATH позволяют управлять структурой формируемого XML документа; – использование директив AUTO и RAW позволяет формировать XML документ, содержащий XML элемент для каждой строки в результате выборки. Они имеют простой синтаксис и их просто использовать, но они предоставляют мало возможности управлять структурой получаемого XML документа. – использование директивы EXPLICIT предоставляет больше возможностей по управлению структурой создаваемых XML данных, но при этом используется намного более сложный синтаксис и многие пользователи считают, что его трудно использовать; – директива PATH имеет более простой синтаксис и мощные возможности настройки. Почти все, что возможно сделать с помощью директивы EXPLICIT также возможно и с помощью директивы PATH. • Например, следующая инструкция SELECT получает данные из таблиц Sales.Customer и Sales.SalesOrderHeader базы данных AdventureWorks2008R2. • В этом запросе задается режим AUTO в предложении FOR XML: USE AdventureWorks2008R2 GO SELECT Cust.CustomerID, OrderHeader.CustomerID, OrderHeader.SalesOrderID, OrderHeader.Status FROM Sales.Customer Cust INNER JOIN Sales.SalesOrderHeader OrderHeader ON Cust.CustomerID = OrderHeader.CustomerID FOR XML AUTO Режим RAW • Запись в конце SELECT оператора ключевых слов FOR XML RAW говорит SQL Server генерировать XML документ имеющий структуру: один-XMLэлемент-для-записи. • Утверждение FOR XML имеет несколько опций, которые меняют получаемый XML результат от фрагмента XML документа, до well-formed документов с немного (в сравнении с несколькими другими опциями FOR XML) измененной структурой. • Синтаксис записи : FOR XML RAW [ (’ElementName’) ] [ [ , BINARY BASE64 ] [ , TYPE ] [ , ROOT [ (’RootName’) ] ] [ , { XMLDATA | XMLSCHEMA [ (’TargetNameSpaceURI’) ]} ] [ , ELEMENTS [ XSINIL | ABSENT ] ] SELECT Name, ListPrice, Color FROM Production.Product [Product] WHERE Name LIKE ‘%Chain%’ ORDER BY Name FOR XML RAW Go <row Name=”Chain” ListPrice=”20.2400” Color=”Silver” /> <row Name=”Chain Stays” ListPrice=”0.0000” /> <row Name=”Chainring” ListPrice=”0.0000” Color=”Black” /> <row Name=”Chainring Bolts” ListPrice=”0.0000” Color=”Silver” /> <row Name=”Chainring Nut” ListPrice=”0.0000” Color=”Silver” /> SELECT [PurchaseOrderID],[Status] ,[EmployeeID] ,[VendorID] ,[ShipMethodID],[OrderDate] ,[ShipDate] ,[SubTotal] ,[TaxAmt],[Freight] ,[TotalDue] FROM [AdventureWorks].[Purchasing].[PurchaseOrderH eader] WHERE [TotalDue] > 300000 FOR XML RAW FOR XML RAW <row PurchaseOrderID="4007" Status="2" EmployeeID="164" VendorID="102" ShipMethodID="3" OrderDate="2004-0401T00:00:00" ShipDate="2004-04-26T00:00:00" SubTotal="554020.0000" TaxAmt="44321.6000" Freight="11080.4000" TotalDue="609422.0000"/> <row PurchaseOrderID="4008" Status="2" EmployeeID="244" VendorID="95" ShipMethodID="3" OrderDate="2004-0523T00:00:00" ShipDate="2004-06-17T00:00:00" SubTotal="396729.0000" TaxAmt="31738.3200" Freight="7934.5800" TotalDue="436401.9000"/> <row PurchaseOrderID="4012" Status="2" EmployeeID="231" VendorID="29" ShipMethodID="3" OrderDate="2004-0725T00:00:00" ShipDate="2004-08-19T00:00:00" SubTotal="997680.0000" TaxAmt="79814.4000" Freight="19953.6000" TotalDue="1097448.0000"/> FOR XML RAW, ELEMENTS <row> <PurchaseOrderID>4007</PurchaseOrderID> <Status>2</Status> <EmployeeID>164</EmployeeID> <VendorID>102</VendorID> <ShipMethodID>3</ShipMethodID> <OrderDate>2004-04-01T00:00:00</OrderDate> <ShipDate>2004-04-26T00:00:00</ShipDate> <SubTotal>554020.0000</SubTotal> <TaxAmt>44321.6000</TaxAmt> <Freight>11080.4000</Freight> <TotalDue>609422.0000</TotalDue> </row> <row><PurchaseOrderID>4008</PurchaseOrderID><Status>2</Status><EmployeeID>244</EmployeeID><Vend orID>95</VendorID><ShipMethodID>3</ShipMethodID><OrderDate>2004-0523T00:00:00</OrderDate><ShipDate>2004-0617T00:00:00</ShipDate><SubTotal>396729.0000</SubTotal><TaxAmt>31738.3200</TaxAmt><Freight>793 4.5800</Freight><TotalDue>436401.9000</TotalDue></row> <row><PurchaseOrderID>4012</PurchaseOrderID><Status>2</Status><EmployeeID>231</EmployeeID><Vend orID>29</VendorID><ShipMethodID>3</ShipMethodID><OrderDate>2004-0725T00:00:00</OrderDate><ShipDate>2004-0819T00:00:00</ShipDate><SubTotal>997680.0000</SubTotal><TaxAmt>79814.4000</TaxAmt><Freight>199 53.6000</Freight><TotalDue>1097448.0000</TotalDue></row> FOR XML RAW('Order'), ROOT('Orders'), ELEMENTS <Orders> <Order> <PurchaseOrderID>4007</PurchaseOrderID> <Status>2</Status> <EmployeeID>164</EmployeeID> <VendorID>102</VendorID> <ShipMethodID>3</ShipMethodID> <OrderDate>2004-04-01T00:00:00</OrderDate> <ShipDate>2004-04-26T00:00:00</ShipDate> <SubTotal>554020.0000</SubTotal> <TaxAmt>44321.6000</TaxAmt> <Freight>11080.4000</Freight> <TotalDue>609422.0000</TotalDue> </Order> <Order><PurchaseOrderID>4008</PurchaseOrderID><Status>2</Status><EmployeeID>244</EmployeeID><VendorID>95< /VendorID><ShipMethodID>3</ShipMethodID><OrderDate>2004-05-23T00:00:00</OrderDate><ShipDate>2004-0617T00:00:00</ShipDate><SubTotal>396729.0000</SubTotal><TaxAmt>31738.3200</TaxAmt><Freight>7934.5800</Freigh t><TotalDue>436401.9000</TotalDue></Order> <Order><PurchaseOrderID>4012</PurchaseOrderID><Status>2</Status><EmployeeID>231</EmployeeID><VendorID>29< /VendorID><ShipMethodID>3</ShipMethodID><OrderDate>2004-07-25T00:00:00</OrderDate><ShipDate>2004-0819T00:00:00</ShipDate><SubTotal>997680.0000</SubTotal><TaxAmt>79814.4000</TaxAmt><Freight>19953.6000</Freig ht><TotalDue>1097448.0000</TotalDue></Order> </Orders> FOR XML RAW(‘Order’), ROOT(‘Orders’), ELEMENTS XSINIL, XMLSCHEMA • • • • • <Orders xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <xsd:schema targetNamespace="urn:schemas-microsoft-com:sql:SqlRowSet1" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:sqltypes="http://schemas.microsoft.com/sqlserver/2004/sqltypes" elementFormDefault="qualified"> <xsd:import namespace="http://schemas.microsoft.com/sqlserver/2004/sqltypes" schemaLocation="http://schemas.microsoft.com/sqlserver/2004/sqltypes/sqltypes.xsd"/ > <xsd:element name="Order"><xsd:complexType><xsd:sequence><xsd:element name="PurchaseOrderID" type="sqltypes:int" nillable="1"/><xsd:element name="Status" type="sqltypes:tinyint" nillable="1"/><xsd:element name="EmployeeID" type="sqltypes:int" nillable="1"/><xsd:element name="VendorID" type="sqltypes:int" nillable="1"/><xsd:element name="ShipMethodID" type="sqltypes:int" nillable="1"/><xsd:element name="OrderDate" type="sqltypes:datetime" nillable="1"/><xsd:element name="ShipDate" type="sqltypes:datetime" nillable="1"/><xsd:element name="SubTotal" type="sqltypes:money" nillable="1"/><xsd:element name="TaxAmt" type="sqltypes:money" nillable="1"/><xsd:element name="Freight" type="sqltypes:money" nillable="1"/><xsd:element name="TotalDue" type="sqltypes:money" nillable="1"/></xsd:sequence></xsd:complexType></xsd:element> </xsd:schema> <Order xmlns="urn:schemas-microsoft-com:sql:SqlRowSet1"> <PurchaseOrderID>4007</PurchaseOrderID> <Status>2</Status><EmployeeID>164</EmployeeID><VendorID>102</VendorID><ShipMethodID>3</ShipM ethodID><OrderDate>2004-04-01T00:00:00</OrderDate><ShipDate>2004-0426T00:00:00</ShipDate><SubTotal>554020.0000</SubTotal><TaxAmt>44321.6000</TaxAmt><Freight>1 1080.4000</Freight><TotalDue>609422.0000</TotalDue></Order><Order xmlns="urn:schemasmicrosoftcom:sql:SqlRowSet1"><PurchaseOrderID>4008</PurchaseOrderID><Status>2</Status><EmployeeID>24 4</EmployeeID><VendorID>95</VendorID><ShipMethodID>3</ShipMethodID><OrderDate>2004-0523T00:00:00</OrderDate><ShipDate>2004-0617T00:00:00</ShipDate><SubTotal>396729.0000</SubTotal><TaxAmt>31738.3200</TaxAmt><Freight>7 934.5800</Freight><TotalDue>436401.9000</TotalDue></Order> <Order xmlns="urn:schemas-microsoft-com:sql:SqlRowSet1"> <PurchaseOrderID>4012</PurchaseOrderID><Status>2</Status><EmployeeID>231</EmployeeID><VendorID >29</VendorID><ShipMethodID>3</ShipMethodID> <OrderDate>2004-07-25T00:00:00</OrderDate> <ShipDate>2004-08-19T00:00:00</ShipDate> <SubTotal>997680.0000</SubTotal> <TaxAmt>79814.4000</TaxAmt> <Freight>19953.6000</Freight> <TotalDue>1097448.0000</TotalDue> </Order> </Orders> Режим AUTO • When RAW mode is not enough, FOR XML AUTO provides a few more ways to shape your XML output. • Its usefulness derives from its capability to produce nested XML elements from rows derived by joining multiple tables, in contrast to the flat structure of RAW mode. • The ROOT keyword introduced earlier also applies with AUTO mode, and it is good practice to continue to use it in your queries. • Like RAW mode, AUTO mode produces attribute-centric XML by default, but you can change this by using the ELEMENTS keyword. XSINIL and XMLSCHEMA are also applicable here, having the same effect as with RAW mode. SELECT Color, Offer.SpecialOfferId Id, Product.ProductId Id, Name, Description [Desc], Size FROM Sales.SpecialOffer Offer JOIN Sales.SpecialOfferProduct OP ON OP.SpecialOfferId = Offer.SpecialOfferId JOIN Production.Product Product ON Product.ProductId = OP.ProductId WHERE Name LIKE ‘Mountain Bike%’ FOR XML AUTO, ELEMENTS XSINIL, ROOT(‘MountainBikeSpecials’) go Результат: <MountainBikeSpecials xmlns:xsi=”http://www.w3.org/200 1/XMLSchema-instance”> <Product> <Color>White</Color> <Id>710</Id> <Name>Mountain Bike Socks, L </Name> <Size>L</Size> <Offer> <Id>1</Id> <Desc>No Discount</Desc> </Offer> </Product> <Product> <Color>White</Color> <Id>709</Id> <Name>Mountain Bike Socks, M</Name> <Size>M</Size> <Offer> <Id>1</Id> <Desc>No Discount</Desc> </Offer> <Offer> <Id>2</Id> <Desc>Volume Discount 11 to 14</Desc> </Offer> <Offer> <Id>3</Id> <Desc>Volume Discount 15 to 24</Desc> </Offer> <Offer> <Id>4</Id> <Desc>Volume Discount 25 to 40</Desc> </Offer> </Product> </MountainBikeSpecials> SELECT PurchaseOrderID, Status, EmployeeID, VendorID, ShipMethodID, OrderDate, ShipDate, SubTotal, TaxAmt, Freight, TotalDue FROM Purchasing.PurchaseOrderHeader WHERE (TotalDue > 300000) FOR XML AUTO • <Purchasing.PurchaseOrderHeader PurchaseOrderID="4007" Status="2" EmployeeID="164" VendorID="102" ShipMethodID="3" OrderDate="2004-04-01T00:00:00" ShipDate="2004-04-26T00:00:00" SubTotal="554020.0000" TaxAmt="44321.6000" Freight="11080.4000" TotalDue="609422.0000"/> • <Purchasing.PurchaseOrderHeader PurchaseOrderID="4008" Status="2" EmployeeID="244" VendorID="95" ShipMethodID="3" OrderDate="2004-05-23T00:00:00" ShipDate="2004-06-17T00:00:00" SubTotal="396729.0000" TaxAmt="31738.3200" Freight="7934.5800" TotalDue="436401.9000"/> • <Purchasing.PurchaseOrderHeader PurchaseOrderID="4012" Status="2" EmployeeID="231" VendorID="29" ShipMethodID="3" OrderDate="2004-07-25T00:00:00" ShipDate="2004-08-19T00:00:00" SubTotal="997680.0000" TaxAmt="79814.4000" Freight="19953.6000" TotalDue="1097448.0000"/> Режим EXPLICIT • FOR XML EXPLICIT is a powerful, oft-maligned, somewhat daunting mode of SQL Server XML production. • It allows for the shaping of row data in any desirable XML structure, but the SQL required to produce it can easily end up being hundreds (or, in some cases, thousands) of lines long, leading to a potential maintenance headache. • With EXPLICIT mode, the query author is responsible for making sure the XML is well formed and that the rowset generated behind the scenes corresponds to a very particular format. • The FOR XML PATH statement renders FOR XML EXPLICIT obsolete except when you need to output column values as CDATA. • This section therefore briefly covers the required query structure for and provides an example of this particular case. Режим PATH • PATH mode is the latest and best addition to the FOR XML syntax. It provides a straightforward way of using a limited XPath syntax to specify the shaping of queryproduced XML. • It is also a very compact syntax in comparison with some of the other modes, especially EXPLICIT. • Let’s look at how PATH mode works by re-creating the XML produced in Listing 47.9, this time using PATH mode. Listing 47.10 illustrates this mode. SELECT Reason.ScrapReasonId, Name ‘text()’, WorkOrderId ‘WorkOrder/@WorkOrderId’, ScrappedQty ‘WorkOrder/@ScrappedQuantity’ FROM Production.ScrapReason Reason JOIN Production.WorkOrder WorkOrder ON Reason.ScrapReasonId = WorkOrder.ScrapReasonID WHERE Reason.ScrapReasonId = 12 FOR XML PATH(‘ScrapReason’), ROOT(‘ScrappedWorkOrders’) go <ScrappedWorkOrders> <ScrapReason> <ScrapReasonId>12</ScrapReasonId> Thermoform temperature too high <WorkOrder WorkOrderId=”2573” ScrappedQuantity=”14” /> </ScrapReason> <ScrapReason> <ScrapReasonId>12</ScrapReasonId> Thermoform temperature too high <WorkOrder WorkOrderId=”4972” ScrappedQuantity=”1” /> </ScrapReason> <ScrapReason> <ScrapReasonId>12</ScrapReasonId> Thermoform temperature too high <WorkOrder WorkOrderId=”7771” ScrappedQuantity=”6” /> </ScrapReason> <ScrapReason> <ScrapReasonId>12</ScrapReasonId> Thermoform temperature too high <WorkOrder WorkOrderId=”9071” ScrappedQuantity=”1” /> </ScrapReason> {...} </ScrappedWorkOrders> SELECT [PurchaseOrderID],[Status], [EmployeeID],[VendorID] ,[ShipMethodID], [OrderDate],[ShipDate],[SubTotal],[TaxAmt], [Freight],[TotalDue] FROM [AdventureWorks].[Purchasing].[PurchaseOrd erHeader] WHERE [TotalDue] > 300000 SELECT [PurchaseOrderHeader].[PurchaseOrderID] ,[PurchaseOrderHeader].[Status],[PurchaseOrderHeader].[EmployeeID] ,[PurchaseOrderHeader].[VendorID],[PurchaseOrderHeader].[ShipMethodID] ,[PurchaseOrderHeader].[OrderDate],[PurchaseOrderHeader].[ShipDate] ,[PurchaseOrderHeader].[SubTotal],[PurchaseOrderHeader].[TaxAmt] ,[PurchaseOrderHeader].[Freight],[PurchaseOrderHeader].[TotalDue] ,[PurchaseOrderDetail].[OrderQty],[PurchaseOrderDetail].[ProductID] ,[PurchaseOrderDetail].[UnitPrice] FROM [Purchasing].[PurchaseOrderHeader] PurchaseOrderHeader INNER JOIN Purchasing.PurchaseOrderDetail PurchaseOrderDetail ON PurchaseOrderHeader.[PurchaseOrderID] = PurchaseOrderDetail.[PurchaseOrderID] WHERE [PurchaseOrderHeader].[TotalDue] > 300000 Функция OPENXML() Функции SQL Server для доступа и работы с внешними данными • OPENQUERY() – выполняет запрос к внешнему серверу и возвращает список записей; • OPENROWSET () – аналогично OPENQUERY(), а также для массовой загрузки данных из файлов; • OPENXML () – предоставляет набор записей их XML документа. Функция OPENXML() • Функция OPENXML позволяет просматривать XML документ в виде набора записей (rowset view). • OPENXML может использоваться в SQL операторах , в которых могут использоваться таблицы, представления (view) или функция OPENROWSET. • Обычный вызов функции OPENXML() включает – вызов системной хранимой процедуры для подготовки указателя (handle) на XML документ; – вызов функции OPENXML() для получения результирующего набора; – вызов системной хранимой процедуры для освобождения полученного на данный документ указателя. • В связи с такими специфическими требованиями до и после вызова OPENXML() нужно вызывать системную хранимую процедуру. • Функция OPENXML() не может быть вызвана из другой функции или использована в операциях с множествами (set-based operation). – Например, to read information from an XML formatted string stored in a SQL Server column, a WHILE loop is required, because OPENXML() can process only one XML document at a time. – Before and after processing each document, calls to system stored procedures to initialize and release the document handle are necessary. Выполнение грамматического разбора и запросов к XML документам • Почти для всех приложений, выполняющих обмен информацией в XML формате требуется модуль или компонент, способный извлекать информацию из XML разметки. – Например, для desktop приложения, читающего RSS может потребоваться извлечение информации о каналах (channel) и элементах (item) из XML документа, прежде чем он будет показан в пользовательском интерфейсе (UI element). – Клиентскому приложению, вызывающему Web Service с прогнозом погоды или о биржевых ценах требуется выполнить разбор полученного XML документа и извлечь требуемые элементы информации. • Многие из этих приложений хранят информацию, полученную из одной или нескольких реляционных таблиц. – Примером является Web Service, получающий от потребителей информацию о заказах на покупки. Web Service может отправлять информацию заказа хранимой процедуре, для сохранения данной информации в наборе реляционных таблиц. • • SQL Server имеет мощную функцию обработки XML - OPENXML(), которая способна разделить XML документ в результирующий набор. Приложения могут передать весь XML документ хранимой процедуре SQL Server, а не заниматься самим грамматическим разбором XML документа. Приложения, которые используют несколько параметров (например, заказы на продажи и покупки) могут использовать такие возможности сервера по обработке XML и отправлять всю информацию в виде единого XML документа с помощью одного вызова хранимой процедуры. Пример использования функции OPENXML • В следующем примере показано применение процедуры OPENXML в инструкции INSERT и инструкции SELECT. – Образец XML-документа содержит элементы <Customers> и <Orders>. • • • • Сначала вызывается хранимая процедура sp_xml_preparedocument для проведения синтаксического анализа XML-документа. В процессе синтаксического анализа создается древовидное представление узлов (элементов, атрибутов, текста и комментариев), входящих в XML-документ. Затем OPENXML ссылается на этот проанализированный XML-документ и формирует представление наборов строк для всех частей XML-документа. Инструкция INSERT, использующая функцию OPENXML, может вставлять данные из такого набора строк в таблицу базы данных. Можно вызывать функцию OPENXML несколько раз, получая и обрабатывая представление в виде набора строк различных частей XML-документа. – Например, их можно вставить в различные таблицы. Данный процесс также называют разделение XML-данных по таблицам. • Последним шагом обработки является повторный вызов процедуры sp_xml_removedocument. Это позволяет освободить память, выделенную для внутреннего древовидного представления XML, создаваемого в фазе синтаксического анализа. Пример использования функции OPENXML • • В следующем примере XML-документ разделяется таким образом, что элементы <Customers> сохраняются в таблице Customers, а элементы <Orders> сохраняются в таблице Orders с помощью двух инструкций INSERT. Этот пример также демонстрирует инструкцию SELECT, использующую функцию OPENXML, которая получает элементы CustomerID и OrderDate из XMLдокумента. -- Create tables for later population using OPENXML. CREATE TABLE Customers (CustomerID varchar(20) primary key, ContactName varchar(20), CompanyName varchar(20)) GO CREATE TABLE Orders( CustomerID varchar(20), OrderDate datetime) GO DECLARE @docHandle int DECLARE @xmlDocument nvarchar(max) -- or xml type SET @xmlDocument = N'<ROOT> <Customers CustomerID="XYZAA" ContactName="Joe" CompanyName="Company1"> <Orders CustomerID="XYZAA" OrderDate="2000-0825T00:00:00"/> <Orders CustomerID="XYZAA" OrderDate="2000-10-03T00:00:00"/> </Customers> <Customers CustomerID="XYZBB" ContactName="Steve" CompanyName="Company2">No Orders yet! </Customers> </ROOT>' EXEC sp_xml_preparedocument @docHandle OUTPUT, @xmlDocument -- Use OPENXML to provide rowset consisting of customer data. INSERT Customers SELECT * FROM OPENXML(@docHandle, N'/ROOT/Customers') WITH Customers -- Use OPENXML to provide rowset consisting of order data. INSERT Orders SELECT * FROM OPENXML(@docHandle, N'//Orders') WITH Orders -- Using OPENXML in a SELECT statement. SELECT * FROM OPENXML(@docHandle, N'/ROOT/Customers/Orders') WITH (CustomerID nchar(5) '../@CustomerID', OrderDate datetime) -- Remove the internal representation of the XML document. EXEC sp_xml_removedocument @docHandle • На рисунке показано XML-дерево, полученное в результате анализа предыдущего XML-документа и созданное с помощью хранимой процедуры sp_xml_preparedocument. XML как реляционные данные: использование OPENXML • Функция OPENXML выполняет операцию обратную FOR XML. • Функция OPENXML используется в T-SQL запросах для чтения XML данных и их декомпозиции в реляционные результирующие наборы данных. • OPENXML является частью оператора SELECT и может использоваться для создания таблицы их XML документа. • • • • • • • • • • • • • • • • • • • DECLARE @XmlDoc XML, @iXml int SET @XmlDoc = ‘ <ex:ExampleDoc xmlns:ex=”urn:www-samspublishing-com:examples”> <ex:foo>hello</ex:foo> <ex:bar>sql!</ex:bar> </ex:ExampleDoc>’ EXEC sp_xml_preparedocument @iXml OUTPUT, @XmlDoc, ‘<ExampleDoc xmlns:ex=”urn:www-samspublishing-com:examples”/>’ SELECT id, parentid, nodetype, localname, prefix FROM OPENXML(@iXml, ‘/ex:ExampleDoc/ex:foo’) --WITH (foo varchar(10) ‘/ex:ExampleDoc/ex:foo’) EXEC sp_xml_removedocument @iXml go id parentid nodetype localname prefix ------ ------------ ------------- ------------- ----3 0 1 foo ex 5 3 3 #text NULL Встроенный XML тип данных Тип данных XML • • • Наиболее существенным дополнением возможностей SQL Server работать с XML данными было введение специально типа данных XML. Тип данных XML может хранить полные XML документы или их части. Тип данных XML может использоваться аналогично тому, как используются и другие типы данных SQL Server: – можно создавать таблицы с XML колонками, – можно объявлять XML переменные и использовать их в качестве параметров и возвращаемых значений. • • • • С помощью XML типа данных в SQL Servere реализовано ограниченное подмножество языка XQuery и запросы на языке T-SQL могут использовать язык XQuery для получения информации из XML колонок и переменных. Поддержка языка XQuery встроена в Relational Engine сервера SQL Server и оптимизатор запросов Query Optimizer может создавать планы выполнения запросов, которые содержат операции реляционных запросов и операции XQuery. Результаты XQuery операций могут связываться с (joined) реляционными данными, а реляционные данные могут связываться с результатами XQuery операций. SQL Server поддерживает создание специальных типов индексов для XML колонок для оптимизации XQuery операций. Работа с XML в СУБД SQL Server • Новый тип данных «xml». Сведения о XML-столбце Store.Demographics • Пример базы данных Adventure Works: оптовые посредники покупают продукты в компании Adventure Works Cycles и продают их розничным торговцам. • Обычные демографические данные об этих оптовых посредниках (годовой доход, ежегодные продажи, вид бизнеса и год начала деятельности) хранятся в столбце Demographics типа xml в таблице Store. • Это типизированный xml-столбец. Для этого столбца используется XMLсхема AdventureWorks StoreSurvey. • Пример экземпляра XML, хранящегося в столбце Store.Demographics. <StoreSurvey xmlns="http://schemas.microsoft.com/sqlserver/2004/07/adventureworks/StoreSurvey"> <AnnualSales>300000</AnnualSales> <AnnualRevenue>30000</AnnualRevenue> <BankName>International Bank</BankName> <BusinessType>BM</BusinessType> <YearOpened>1970</YearOpened> <Specialty>Road</Specialty> <SquareFeet>7000</SquareFeet> <Brands>3</Brands> <Internet>T1</Internet> <NumberEmployees>2</NumberEmployees> </StoreSurvey> Пример XML колонки в таблице ProductModel • Содержание поля Instruction в записи таблицы ProductModel <root xmlns="http://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelManuInstructions"> Adventure Works CyclesFR-210B Instructions for Manufacturing HL Touring Frame. Summary: This document contains manufacturing instructions for manufacturing the HL Touring Frame, Product Model 7. Instructions are work center specific and are identified by Work Center ID. These instructions must be followed in the order presented. Deviation from the instructions is not permitted unless an authorized Change Order detailing the deviation is provided by the Engineering Manager. <Location LaborHours="2.5" LotSize="100" MachineHours="3" SetupHours="0.5" LocationID="10"> Work Center 10 - Frame Forming. The following instructions pertain to Work Center 10. (Setup hours = .5, Labor Hours = 2.5, Machine Hours = 3, Lot Sizing = 100) <step> Insert <material>aluminum sheet MS-2341</material> into the <tool>T-85A framing tool</tool>. </step> <step> Attach <tool>Trim Jig TJ-26</tool> to the upper and lower right corners of the aluminum sheet. </step> <step> Using a <tool>router with a carbide tip 15</tool>, route the aluminum sheet following the jig carefully. </step> <step> Insert the frame into <tool>Forming Tool FT-15</tool> and press Start. </step> <step> When finished, inspect the forms for defects per Inspection Specification <specs>INFS-111</specs>. </step> <step>Remove the frames from the tool and place them in the Completed or Rejected bin as appropriate.</step> </Location> <Location LaborHours="1.75" LotSize="1" MachineHours="2" SetupHours="0.15" LocationID="20"> Work Center 20 - Frame Welding. The following instructions pertain to Work Center 20. (Setup hours = .15, Labor Hours = 1.75, Machine Hours = 2, Lot Sizing = 1) <step> Assemble all frame components following blueprint <blueprint>1299</blueprint>. </step> <step> Weld all frame components together as shown in illustration <diag>3</diag></step> <step> Inspect all weld joints per Adventure Works Cycles Inspection Specification <specs>INFS-208</specs>. </step> </Location> ….. </root> Типизированные и не типизированные XML данные • • • • • • Тип данных XML поддерживает XSD с помощью коллекций XML схем, котораяможет быть создана из определения XML схемы. XML колонки и переменные могут быть связаны с коллекцией XML схем. XML колонки и переменные, которые связаны с коллекцией XML схем называются типизированными XML. Операции назначения или изменения типизированного XML будут выполнены успешно только в том случае, если новые значения пройдут проверку на валидность (validations) определенную в коллекции XML схем. Типизированные XML имеют много преимуществ по сравнению с нетипизированными XML колонками и переменными. The most important benefit is that the validation constraints are always respected. The content of a typed XML document is always valid as per the schema with which it is associated. Cпри работе с типизированными XML, SQL Server имеет больше знаний о XML документе (структуре, типах данных и т.п.) и может генерировать более оптимизированные планы запросов. Because SQL Server has complete knowledge of the data types of elements and attributes, storage of typed XML can be made significantly more compact than untyped XML. Static type checking is possible with typed XML documents, and SQL Server can detect, at compile time, if an XQuery expression on a typed XML document is mistyped. Stored procedures or functions that accept typed XML parameters are protected from receiving invalid XML documents, as SQL Server will perform implicit validation of the XML value against the schema collection before accepting the parameter value. Создание и использование XML колонок • XML тип данных в большинстве случаев может использоваться аналогично тому, как используются другие типы данных SQL сервера (целые, вещественные и т.п.). • Однако имеются некоторые исключения. – Например, XML колонка не может быть добавлена к обычному индексу или использована в операции сравнения. • Можно создать таблицу с одной или несколькими XML колонками. • XML колонки могут быть добавлены к существующей таблице. • Колонки с типами данных VARCHAR/NVARCHAR/VARBINARY/TEXT/NTEXT могут быть преобразованы в колонки XML типа данных, если все существующие значения являются правильными (well-formed) XML значениями (XML документами, участками XML формата). • Цельные XML документы могут быть получены с помощью SELECT запроса, или из XML документов может быть извлечена некоторая информация Создание и использование XML колонок • XML тип данных в большинстве случаев может использоваться аналогично тому, как используются другие типы данных SQL сервера (целые, вещественные и т.п.). • Однако имеются некоторые исключения. – Например, XML колонка не может быть добавлена к обычному индексу или использована в операции сравнения. • Можно создать таблицу с одной или несколькими XML колонками. • XML колонки могут быть добавлены к существующей таблице. • Колонки с типами данных VARCHAR/NVARCHAR/VARBINARY/TEXT/NTEXT могут быть преобразованы в колонки XML типа данных, если все существующие значения являются правильными (well-formed) XML значениями (XML документами, участками XML формата). • Цельные XML документы могут быть получены с помощью SELECT запроса, или из XML документов может быть извлечена некоторая информация Создание коллекции XML схем CREATE XML SCHEMA COLLECTION Sales.FeedbackSchemaCollection AS ‘<?xml version=”1.0”?> <xsd:schema xmlns:xsd=”http://www.w3.org/2001/XMLSchema” targetNamespace=”urn:www-samspublishingcom:examples:feedback_review_xsd” xmlns=”urn:www-samspublishingcom:examples:feedback_review_xsd” elementFormDefault=”qualified” attributeFormDefault=”unqualified”> <xsd:element name=”feedback_review” type=”feedbackReviewType”/> <xsd:complexType name=”feedbackReviewType”> <xsd:sequence minOccurs=”1” maxOccurs=”unbounded”> <xsd:element name=”order” type=”orderType”/> </xsd:sequence> <xsd:attribute name=”product_id” type=”xsd:integer” use=”optional”/> </xsd:complexType> <xsd:complexType name=”feedbackType” mixed=”true”> <xsd:attribute name=”id” type=”xsd:integer” use=”required”/> </xsd:complexType> <xsd:complexType name=”orderType”> <xsd:choice minOccurs=”0” maxOccurs=”unbounded”> <xsd:element name=”customer_comment” type=”feedbackType”/> <xsd:element name=”company_response” type=”feedbackType”/> </xsd:choice> <xsd:attribute name=”id” type=”xsd:integer” use=”required”/> <xsd:attribute name=”type” use=”required”> <xsd:simpleType> <xsd:restriction base=”xsd:string”> <xsd:enumeration value=”parts”/> <xsd:enumeration value=”product”/> <xsd:enumeration value=”service”/> </xsd:restriction> </xsd:simpleType> 1896 CHAPTER 47 Using XML in SQL Server 2008 </xsd:attribute> </xsd:complexType> </xsd:schema>’ Создаем таблицу использующую колонку со схемой CREATE TABLE Sales.FeedbackReview ( FeedbackReviewId int IDENTITY(1, 1) NOT NULL PRIMARY KEY, ProductId int NULL REFERENCES Production.Product, FeedbackReviewXml xml (DOCUMENT Sales.FeedbackSchemaCollection) NOT NULL, CONSTRAINT ProductIdMatches CHECK (Sales.fnCheckProductId(FeedbackReviewXml) = ProductId) ) CREATE FUNCTION Sales.fnCheckProductId (@FeedbackReviewXml xml) RETURNS int AS BEGIN DECLARE @ProductId int SELECT @ProductId = @FeedbackReviewXml.value (‘declare namespace fr=”urn:www-samspublishing-com:examples:feedback_review_xsd”; /fr:feedback_review[1]/@product_id’, ‘int’) RETURN @ProductId END Вставка записи в таблицу INSERT Sales.FeedbackReview SELECT NULL, ‘<feedback_review xmlns=”urn:www-samspublishing-com:examples:feedback_review_xsd”> <order id=”353” type=”service”> <customer_comment id=”131”> You guys said you&apos;d be here on Monday. </customer_comment> <company_response id=”242”>I said Wednesday!</company_response> </order> </feedback_review>’ Загрузка XML из файлов • Данный пример показывает, как вставить строку в таблицу T. • Значения XML колонки загружаются из файла C:\MyFile\xmlfile.xml в виде CLOB, а для колонки целого типа задается значение 10. INSERT INTO T SELECT 10, xCol FROM (SELECT * FROM OPENROWSET (BULK 'C:\MyFile\xmlfile.xml', SINGLE_CLOB) AS xCol) AS R(xCol) Выполнение проверки XML документов • • • • • • Одним из требований любого серьезного приложения является набор процессов проверки правильности структуры используемой информации. Правильно составленная программа должна полностью проверять все входные параметры перед выполнением их реальной обработки. Обычно полная проверка параметров защищает приложение и БД от логических ошибок и ошибок в данных. Она помогает защитить данные от злоумышленных действий (например, таких, как введение SQL (SQL injection)). При обмене данными в XML формате требуется их более строгая проверка, так как возможности задания неправильных значений увеличиваются. Приложение передающее значение ‘‘тридцать’’ для параметра хранимой процедуры @age (@age INT) получит сообщение об ошибке преобразования, сразу же после того, как SQL Server попытается выполнить неявную проверку типа данных. Разработчик составляющий хранимую процедуру не должен выполнять проверки, гарантирующие, что все параметры целого типа являются правильными целыми значениями. Данный разработчик должен только выполнять проверки специфичные для бизнес-логики, как например проверку предельных значений возраста сотрудников, чтобы гарантировать, что он попадает в приемлемый интервал (например, от 18 до 65). • • • Выполнение проверки XML документов (2) При использовании XML параметров SQL Server не сможет обнаружить такую возможную ошибку в XML документе, как ‘‘<Employee age=˝кто его знает˝/>’’ так как атрибут @age не связан с конкретным типом данных и SQL Server не знает, как его проверить. Это указывает на то, что для XML документов требуется намного более сложная проверка, чем для не-XML параметров. Например: – часто требуется чтобы элементы XML документа следовали в заданном порядке. An application that parses the XML document sequentially might require that the OrderDate element should precede the ExpectedShippingDate element to validate the shipping date based on the order date. – Structure of the XML should be validated. For example, an application might expect the employee address under the employee element, and the zip code as an attribute of the address element. – Certain elements may be optional and certain elements mandatory. – Certain elements may appear more than once and others may be allowed only once. – Data type validations may be needed. For example, age should be an integer value. – Restrictions might be needed on the accepted range of values, such as age of an employee should be between 18 and 65. – Certain values may follow specific formats. For example, an application might require phone numbers to be in the format of (999) 999-9999, or social security numbers must be 999-99-9999. Встроенные методы для работы с XML типом данных Встроенные методы для типа данных xml • SQL Server предоставляет 5 встроенных методов для типа данных xml: 1) query() – выполнение выражения на языке XQuery, преобразующее значение поля в список узлов, который может быть переформатирован нужным способом. Результатом является не типизированный XML. 2) exists() – выполнение проверки того, является ли результат выполнения XQuery запроса пустым (нет искомых узлов). Результат 1 (узлы есть) или 0 (узлов нет), 3) value() – извлечение одного (т.е. скалярного) значения из XML и преобразование его реляционный тип данных SQL Server (например, int, varchar), 4) nodes() – используется XQuery выражение для разделения XML данных в набор записей (rowset); аналогично работе OPENXML. 5) modify() – изменение содержания XML данных с помощью функций XQuery: insert, replace, delete. • Для вызова этих методов их нужно указать через точку после имени колонки с типом данных xml: ColumnName.MethodName([MethodParameters]) syntax. Метод query() Использование языка XQuery в SQL Server • К значениям типа данных xml можно выполнять запросы, описанные на языке XQuery. • XQuery выражения встроены в язык Transact-SQL. Transact-SQL это версия языка SQL, используемая в SQL Server. • Microsoft has learned from its past mistakes and has chosen to separate the nonstandard update functionality from the standardized XQuery. • This way, it can add the capability to insert, delete, and replace, when these become part of XQuery, without breaking past code. • It will then deprecate the nonstandard extensions and eventually phase them out. Расширение языка XQuery в SQL Server • Стандарт XQuery W3C ограничен тем, что он может выполнять запросы только к XML источникам данныхdata source. • В XQuery 1.0 нет возможностей удалять, вставлять или менять данные. • В SQL Server 2005, the XML Data Modification Language (DML) adds three keywords to the functionality available in XQuery 1.0: – delete – Insert – replace value of • Note that although SQL itself is not case sensitive, the preceding commands are; if you use DELETE instead of delete, you will receive a cryptic error message. • XQuery немного походит на SQL, тем что для поиска требуемых узлов использует семантику аналогичную SELECT-FROM-WHERE-ORDER BY. • It also bears a resemblance to writing foreach loops with object iterators in a language such as C#. • It is unique in that it combines the navigational power of XPath to locate nodes and (in the same expressions) allows for new XML generation on the fly, all in one tight syntax package built especially for processing XML. • To use XQuery effectively, you need to have at least a rudimentary understanding of XPath. A great starting point is the World Wide Web Consortium’s (W3C’s) site, at www.w3.org/TR/xpath20/. Использование XPath выражений • XPath is used for locating XML elements and attributes within an XML document and navigating through the XML tree. Every element and attribute within an XML document has a unique ‘‘path.’’ For example: ’<Items> <ItemNumber>1003</ItemNumber> <ItemNumber>1004</ItemNumber> </Items>’ • • In the preceding example, the path to the first ItemNumber element is /Items/ItemNumber[1] and • the second is /Items/ItemNumber[2]. • Each element and attribute within an XML document can be uniquely identified and processed using an XPath expression. • All the XML data type methods accept XPath expressions to specify the target element or attribute on which the given operation needs to be performed. Selecting XML by Using query() • The job of query() is to retrieve XML nodes by using XQuery expressions. • The result of query() is an instance of untyped xml. • It takes a single parameter, a string literal containing the XQuery code itself. • The parameter to query() cannot be a variable; it must be a string literal. • This puts something of a hold on dynamic XQuery expressions. • However, declared T-SQL variables and column values are available for use in XQuery, using the functions sql:variable() and sql:column() (described later in this chapter). • Each XQuery query is broken into two distinct parts, separated by a semicolon. – The first part is known as the prolog. This is the place where any namespaces used in the Xpath expressions and selected nodes are declared. – The second part is known as the body, and this is the place where XPath and XQuery expressions are evaluated. • The following example declares the act namespace in its query prolog and then selects any act:eMail nodes from Person.Person.AdditionalContactInfo in its body: SELECT AdditionalContactInfo.query( ‘ declare namespace act=”http://schemas.microsoft.com/sqlserver/2004/07/adventureworks/ContactTypes”; //act:eMail ‘ ) FROM Person.Person WHERE ContactId = 2 WITH XMLNAMESPACES ( ‘http://schemas.microsoft.com/sqlserver/2004/07/adventureworks/ContactTypes’ as act ) SELECT FirstName, LastName, AdditionalContactInfo.query( ‘ //act:eMail ‘) FROM Person.Contact WHERE ContactID = 2 FOR XML RAW(‘ContactInfo’), ROOT(‘Contact’) Результат <Contact xmlns:act=”http://schemas.microsoft.com/sqlserver/2004/07/adventurew orks/ ContactTypes”> <ContactInfo FirstName=”Catherine” LastName=”Abel”> <act:eMail xmlns:act=”http://schemas.microsoft.com/sqlserver/2004/07/ adventure-works/ContactTypes”> <act:eMailAddress>Joe@xyz.com</act:eMailAddress> <act:SpecialInstructions> Dont send emails for urgent issues. Use telephone instead. </act:SpecialInstructions> </act:eMail> </ContactInfo> </Contact> <Contact xmlns:act="http://schemas.microsoft.com/sqlserver/2004/07/adventureworks/ContactTypes"> <ContactInfo FirstName="Catherine" LastName="Abel"> <act:eMail xmlns:act="http://schemas.microsoft.com/sqlserver/2004/07/adventureworks/ContactTypes"> <act:eMailAddress>Joe@sample.com</act:eMailAddress> <act:SpecialInstructions>Do not send e-mail for urgent issues. Use telephone instead. </act:SpecialInstructions> </act:eMail> </ContactInfo> </Contact> SELECT Instructions.query ( 'declare default element namespace "http://schemas.microsoft.com/sqlserver/2004/07/adventureworks/ProductModelManuInstructions"; for $ContextNode in //Location return <LotSize> {$ContextNode/@LotSize} </LotSize>‘ ) AS Result FROM Production.ProductModel WHERE (ProductModelID = 10) • Результат <Number>1</Number> <Number>2</Number> <Number>3</Number> • Вместо XPath выражения можно использовать связанную переменную для выполнения итераций по множеству значений, а не узлов, as in the following example: SELECT Instructions.query(‘ for $ContextNode in (1, 2, 3) return <Number> {$ContextNode } </Number> ‘) as Result FROM Production.ProductModel WHERE ProductModelID = 10 Содержание поля Instruction в таблице ProductModel <root xmlns="http://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelManuInstructions"> Adventure Works CyclesFR-210B Instructions for Manufacturing HL Touring Frame. Summary: This document contains manufacturing instructions for manufacturing the HL Touring Frame, Product Model 7. Instructions are work center specific and are identified by Work Center ID. These instructions must be followed in the order presented. Deviation from the instructions is not permitted unless an authorized Change Order detailing the deviation is provided by the Engineering Manager. <Location LaborHours="2.5" LotSize="100" MachineHours="3" SetupHours="0.5" LocationID="10"> Work Center 10 - Frame Forming. The following instructions pertain to Work Center 10. (Setup hours = .5, Labor Hours = 2.5, Machine Hours = 3, Lot Sizing = 100) <step> Insert <material>aluminum sheet MS-2341</material> into the <tool>T-85A framing tool</tool>. </step> <step> Attach <tool>Trim Jig TJ-26</tool> to the upper and lower right corners of the aluminum sheet. </step> <step> Using a <tool>router with a carbide tip 15</tool>, route the aluminum sheet following the jig carefully. </step> <step> Insert the frame into <tool>Forming Tool FT-15</tool> and press Start. </step> <step> When finished, inspect the forms for defects per Inspection Specification <specs>INFS-111</specs>. </step> <step>Remove the frames from the tool and place them in the Completed or Rejected bin as appropriate.</step> </Location> <Location LaborHours="1.75" LotSize="1" MachineHours="2" SetupHours="0.15" LocationID="20"> Work Center 20 - Frame Welding. The following instructions pertain to Work Center 20. (Setup hours = .15, Labor Hours = 1.75, Machine Hours = 2, Lot Sizing = 1) <step> Assemble all frame components following blueprint <blueprint>1299</blueprint>. </step> <step> Weld all frame components together as shown in illustration <diag>3</diag></step> <step> Inspect all weld joints per Adventure Works Cycles Inspection Specification <specs>INFS-208</specs>. </step> </Location> ….. </root> <LotSize xmlns="http://schemas.microsoft.com/sqlserver/2004/07/adventureworks/ProductModelManuInstructions" LotSize="100" /> <LotSize xmlns="http://schemas.microsoft.com/sqlserver/2004/07/adventureworks/ProductModelManuInstructions" LotSize="1" /> <LotSize xmlns="http://schemas.microsoft.com/sqlserver/2004/07/adventureworks/ProductModelManuInstructions" LotSize="1" /> <LotSize xmlns="http://schemas.microsoft.com/sqlserver/2004/07/adventureworks/ProductModelManuInstructions" LotSize="20" /> <LotSize xmlns="http://schemas.microsoft.com/sqlserver/2004/07/adventureworks/ProductModelManuInstructions" LotSize="1" /> <LotSize xmlns="http://schemas.microsoft.com/sqlserver/2004/07/adventureworks/ProductModelManuInstructions" LotSize="1" /> Пример запроса SELECT Resume.query('declare namespace ns="http://schemas.microsoft.com/sqlserver/2004/07/adventure-works/Resume"; <Achievements> { for $EducationNode in //ns:Education order by xs:date(string($EducationNode/ns:Edu.EndDate[1])) descending return <Degree> <DateAwarded> { string($EducationNode/ns:Edu.EndDate[1]) } </DateAwarded> <Name> { string($EducationNode/ns:Edu.Degree[1]) } </Name> </Degree> } </Achievements> ') AS Expr1 FROM HumanResources.JobCandidate WHERE (JobCandidateID = 2) Результат <Achievements> <Degree> <DateAwarded> 1997-06-03Z </DateAwarded> <Name> Bachelor of Science </Name> </Degree> <Degree> <DateAwarded> 1993-06-12Z </DateAwarded> <Name> Diploma </Name> </Degree> </Achievements> Работа с таблицу, имеющей XML колонку • Создание таблицы с XML колонкой: DECLARE @t TABLE (OrderID INT, OrderData XML ) • Вставка новой строки в таблицу с XML колонкой INSERT INTO @t(OrderID, OrderData) SELECT 1, ‘<CustomerNumber>1001</CustomerNumber> <Items> <Item ItemNumber="1001" Quantity="1" Price="950"/> <Item ItemNumber="1002" Quantity="1" Price="650" /> </Items>’ • Пример SELECT запроса, извлекающего из таблицы колонку обычного типа (INT) и значение из XML документа, хранящегося в каждой записи (row): SELECT OrderID, OrderData.value(’CustomerNumber[1]’ , ’CHAR(4)’) AS CustomerNumber FROM @t • Полученный результат выборки OrderID CustomerNumber -----------------------1 1001 Более сложный запрос к XML колонке • • • • Код запроса станет более сложным, если требуется извлечь более чем один элемент из XML документов, хранящихся в колонке таблицы. Такой запрос должен формировать более чем одну запись (row) для каждой записи (row) хранимой в таблице. Для этого может быть использован метод nodes() типа данных XML, чтобы получить доступ к каждому элементу XML документа. Коллекция XML элементов, возвращаемая методом nodes() может быть объединена с базовой таблицей с помощью оператора CROSS APPLY, как показано в следующем примере: SELECT OrderID, o.value(’@ItemNumber’, ’CHAR(4)’) AS ItemNumber, o.value(’@Quantity’, ’INT’) AS Quantity, o.value(’@Price’, ’MONEY’) AS Price FROM @t CROSS APPLY OrderData.nodes(’/Items/Item’) x(o) Результат выполнения запроса OrderID ----------1 1 ItemNumber ---------1001 1002 Quantity ----------1 1 Price ----------950.00 650.00 Объявление и использование XML переменных • Just like other SQL Server native data types, XML variables can be created and used in T-SQL batches, stored procedures, functions, and so on. The following example demonstrates a few different ways an XML variable can be declared: -- Объявление не типизированной XML переменной DECLARE @x XML -- Declare a TYPED XML Variable DECLARE @x XML(CustomerSchema) -- Declare a TYPED XML DOCUMENT Variable DECLARE @x XML(DOCUMENT CustomerSchema) -- Declare a TYPED XML CONTENT variable DECLARE @x XML(CONTENT CustomerSchema) Использование XML переменной в запросе • • • • • • • • Имеется небольшое различие в записи XQuery выражения для XML переменной и XML колонки. При работе с XML variable, the query will always process only one document at a time. However, while working with an XML column, more than one XML document may be processed in a single batch operation. Because of this, the CROSS APPLY operator is required while running such a query on an XML column (as demonstrated in the previous example). Пример использования в запросе XML переменной : DECLARE @x XML SELECT @x = ‘ <CustomerNumber>1001</CustomerNumber> <Items> <Item ItemNumber="1001" Quantity="1" Price="950"/> <Item ItemNumber="1002" Quantity="1" Price="650" /> </Items>’ SELECT o.value(’@ItemNumber’,’CHAR(4)’) AS ItemNumber, o.value(’@Quantity’,’INT’) AS Quantity, o.value(’@Price’,’MONEY’) AS Price FROM @x.nodes(’/Items/Item’) x(o) Полученный результат ItemNumber Quantity Price ---------------------------------------1001 1 950.00 1002 1 650.00 Загрузка и запросы к XML документам, расположенным в файлах • • • • • The capability to load XML documents from disk files is one of the very interesting XML features available with SQL Server. This is achieved by using the BULK row set provider for OPENROWSET. The following example shows how to load the content of an XML file into an XML variable: Пусть файл с именем c:\temp\ items.xml имеет следующее содержание <Items> <Item ItemNumber="1001" Quantity="1" Price="950"/> <Item ItemNumber="1002" Quantity="1" Price="650" /> </Items> Загрузка значения XML переменной данными из файла DECLARE @xml XML SELECT @xml = CAST(bulkcolumn AS XML) FROM OPENROWSET(BULK ‘C:\temp\items.xml’, SINGLE_BLOB) AS x Запрос к переменной SELECT x.value(’@ItemNumber’,’CHAR(4)’) AS ItemNumber, x.value(’@Quantity’,’INT’) AS Quantity, x.value(’@Price’,’MONEY’) AS Price FROM @xml.nodes(’/Items/Item’) i(x) Результат выполнения запроса ItemNumber Quantity Price ---------------------------------------1001 1 950.00 1002 1 650.00 • • • • Функция OPENROWSET(BULK. . .[filename, option]) может даже напрямую выполнять запрос к данным в файле без их загрузки в таблицу или переменные. Результат вызова данной функции может использоваться в качестве входных данных для операций INSERT/UPDATE. The following example queries the XML file directly: SELECT x.value(’@ItemNumber’,’CHAR(4)’) AS ItemNumber, x.value(’@Quantity’,’INT’) AS Quantity, x.value(’@Price’,’MONEY’) AS Price FROM ( SELECT CAST(bulkcolumn AS XML) AS data FROM OPENROWSET(BULK ‘C:\temp\items.xml’, SINGLE_BLOB) AS x )a CROSS APPLY data.nodes(’/Items/Item’) i(x) Результат выполнения запроса ItemNumber Quantity Price -------------------1001 1 950.00 1002 1 650.00 --------------------- Другие встроенные методы типа данных XML Метод value() • value() является одним из наиболее часто используемых методов XML типа данных. • Он используется для получения скалярного значения из XML документа, хранимого в колонке таблицы. • Он получает XQuery выражение выполняет его, формирует один узел, преобразует его значение в заданный тип данных SQL Server и возвращает полученное значение. • Например: DECLARE @x XML SELEC @x = ‘<Order OrderID="1" OrderNumber="SO101" />’ SELECT @x.value(’(Order/@OrderID)[1]’, ’INT’) AS OrderID, @x.value(’(Order/@OrderNumber)[1]’, ’CHAR(5)’) AS OrderNumber • Результат выполнения запроса OrderID OrderNumber --------------------1 SO101 Метод nodes() • • • The nodes() method returns a row set representation of the XML document. An XQuery operation can be performed on each node returned by the nodes() method. This is useful when information has to be retrieved from all the nodes matching a specific expression. Here is an example: DECLARE @x XML SELECT @x = ‘ <Items> <ItemNumber>1001</ItemNumber> <ItemNumber>1002</ItemNumber> </Items>’ SELECT x.value(’.’, ’CHAR(4)’) AS ItemNumber FROM @x.nodes(’/Items/ItemNumber’) o(x) Результат выполнения запроса ItemNumber ---------1001 1002 • • • There is a slight difference between the way the query has to be written for XML variables and XML columns. That’s because when working with an XML variable, only one XML document is processed at a time; but when working with an XML column, several XML documents need to be processed in a single batch. This is usually achieved by using the CROSS APPLY operator. The following example is a modified version of the preceding query that reads information from an XML column: SELECT OrderID, x.value(’@ItemNumber’,’CHAR(4)’) AS ItemNumber FROM OrderXML CROSS APPLY ItemData.nodes(’/Order/Item’) o(x) • Результат выполнения запроса OrderID ItemNumber -------------------1 D001 1 Z001 2 D001 • The CROSS APPLY operator joins each node returned by the nodes() method with the table, and the value() method reads the ItemNumber value from each element returned by the nodes() method. Метод exist() • The exist() method checks whether an element or attribute specified by a given XPath expression exists in the document. • The following query uses the exist() method to filter rows that have a specific item number: SELECT OrderID FROM OrderXML WHERE ItemData.exist(’/Order/Item[@ItemNumber = "Z001"]’) = 1 OrderID ----------1 • The exist() method returns true (1) if an element or attribute with the specified XPath expression exists in the XML document. Метод modify() • Метод modify() – The modify() method is used to perform XML DML operations on an XML document. – It allows inserting, updating, or deleting XML elements or attributes within an XML document. Связывание XML вершин с реляционными таблицами • • • SQL Server has extended the Relational Engine with XQuery capabilities. This offers a number of advantages — for example, the query processor can evaluate relational and XQuery operations in a single query. A single query plan is created with relational and XQuery operations, and results of a relational query can be joined with XQuery results and vice versa. Пример T-SQL запроса, связывающего XML вершины с обычными колонками таблицы: SELECT oh.OrderID, c.Name AS Customer, i.ItemDescription AS Item, x.value(’@Quantity’,’INT’) AS Quantity, x.value(’@Price’,’MONEY’) AS Price FROM OrderHeader oh INNER JOIN OrderXML ox ON ItemData.value(’(Order/@OrderID)[1]’,’INT’) = oh.OrderID CROSS APPLY ItemData.nodes(’/Order/Item’) o(x) INNER JOIN Customers c ON c.CustomerID = oh.CustomerID INNER JOIN Items i ON i.ItemNumber = x.value(’@ItemNumber’,’CHAR(4)’) Результат выполнения запроса OrderID Customer Item -------------------------1 Jacob Sebastian DELL XPS 1130 Laptop 1 Jacob Sebastian XBOX 360 Console 2 Jacob Sebastian DELL XPS 1130 Laptop Quantity ------------ Price ------------1 900.00 1 200.00 1 900.00 Deleting with XML DML • The following code shows an example of how it can be used: DECLARE @myDoc XML SET @myDoc = ‘<Person><FirstName>Joe</FirstName> <LastName>Fawcett</LastName></Person> ‘SELECT @myDoc SET @myDoc.modify(‘ delete /Person/*[2]‘) SELECT @myDoc • Результат: <Person> <FirstName>Joe</FirstName> <LastName>Fawcett</LastName> </Person> Операции • Функция modify() • Удаление delete(//item/alph[@name=”B”]) • Замена replace value of old_expression with new_expression • Вставка insert new_node_expression ( {{{as first | as last} into} | after | before} reference_node_expression ) CREATE TABLE SimpleBook (BookId int IDENTITY(1,1) PRIMARY KEY CLUSTERED, BookXml xml) GO INSERT SimpleBook SELECT '<book book_id="1"> <title>A Great Work</title> <chapter chapter_id="1"> <title>An Excellent Chapter</title> <section id="1"> <title>A Boring Section</title> <paragraph para_id="1"> Something boring. </paragraph> </section> <section id="2"> <title>Another Fine Section</title> <paragraph para_id="2"> Another fine paragraph. </paragraph> </section> </chapter> </book>' Содержание ячейки BookXML <book book_id="1"> <title>A Great Work</title> <chapter chapter_id="1"> <title>An Excellent Chapter</title> <section id="1"> <title>A Boring Section</title> <paragraph para_id="1">Something boring.</paragraph> </section> <section id="2"> <title>Another Fine Section</title> <paragraph para_id="2"> Another fine paragraph. </paragraph> </section> </chapter> </book> • UPDATE SimpleBook • SET BookXml.modify('replace value of (/book/chapter/section[@id="1"]/title/text())[1] with "A Fine Section"') • WHERE BookId = 1 • GO • UPDATE SimpleBook • SET BookXml.modify('replace value of (/book/chapter/section/paragraph[@para_id="1"]/text ())[1] with "A Fine Paragraph"') • WHERE BookId = 1 <book book_id="1"> <title>A Great Work</title> <chapter chapter_id="1"> <title>An Excellent Chapter</title> <section id="1"> <title>A Fine Section</title> <paragraph para_id="1"> A Fine Paragraph</paragraph> </section> <section id="2"> <title>Another Fine Section</title> <paragraph para_id="2"> Another fine paragraph.</paragraph> </section> </chapter> </book>