sql 使用XQuery方法查询,值,存在,节点在SQL Server中查询XML

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了sql 使用XQuery方法查询,值,存在,节点在SQL Server中查询XML相关的知识,希望对你有一定的参考价值。

/* the XML data type exposes methods support for XQuery expressions that you can use to query XML data stored in SQL Server

- query (xquery): returns XML node(s)
- value (equery, datatype): returns a scalar value
- exist (xquery): returns 1 (True) or 0 (False) to indicate existence of specified node (ie does this order have any items?)
- nodes (xquery) AS table (column): returns a rowset of XML nodes. Often used with CROSS APPLY

*/

-- example, start by creating a table that has a column OrderItems to hold XML
CREATE TABLE dbo.SalesOrder2
(OrderID INT IDENTITY PRIMARY KEY CLUSTERED,
OrderDate DATE DEFAULT GETDATE(),
OrderItems XML);

-- insert some XML into this table, specifying the items for three orders
INSERT INTO dbo.SalesOrder2 (OrderItems)
VALUES
('<items count="2">
    <item id="561" quantity="1"> </item>
    <item id="127" quantity="2"> </item>
  </items>' ),
('<items count="1">
    <item id="129" quantity="1"> </item>
  </items>' ),
('<items count="2">
    <item id="561" quantity="1"> </item>
    <item id="167" quantity="1"> </item>
  </items>');
  
/* Results of querying the SalesOrder2 table that now stores the XML:
OrderID	  OrderDate	OrderItems
5	  2017-11-05	<items count="2"><item id...
6	  2017-11-05	<items count="1"><item id...
7	  2017-11-05	<items count="2"><item id...
*/

-- example of using the query method to return the XML fragments. For the OrderItems column which holds the XML, query it and bring back the items/item node as XML - this will in effect pull the whole OrderItems, and then search within the XML and pull out just the item elements from that larger XML fragment:
SELECT	OrderID,
	OrderDate,
	OrderItems.query('items/item') AS Items
FROM dbo.SalesOrder2;

/* Results:
OrderID	OrderDate	Items
5	2017-11-05	<item id="561" quantity="1" /><item id="127" quantity="2" />
6	2017-11-05	<item id="129" quantity="1" />
7	2017-11-05	<item id="561" quantity="1" /><item id="167" quantity="1" />
*/

-- example using //, which is shorthad for all <item> descendants, regardless of where in the XML hierarchy it resides:
SELECT	OrderID,
	OrderDate,
	OrderItems.query('//item') AS Items
FROM dbo.SalesOrder2;

/* Results:
OrderID	OrderDate	Items
5	2017-11-05	<item id="561" quantity="1" /><item id="127" quantity="2" />
6	2017-11-05	<item id="129" quantity="1" />
7	2017-11-05	<item id="561" quantity="1" /><item id="167" quantity="1" />
*/

-- example of adding XML tags to the XML that is stored in the OrderItems column. For example, this will pull /items/item (the text within the {}, and outside of that create an element <products> which will encapsulate the XML pulled out of the table:
SELECT	OrderID,
	OrderDate,
	OrderItems.query('<products> {items/item} </products>') AS Products
FROM dbo.SalesOrder2;

/* Results:
OrderID	OrderDate	Products
5	2017-11-05	<products><item id="5...</products>
6	2017-11-05	<products><item id="1...</products>
7	2017-11-05	<products><item id="5...</products>
*/

-- example of retrieving an attribute from the XML. In the example, this creates a <lineitems> element that has an itemcount attribute, and it will place within that attribute the value of the count attribute of the items element that it finds (expressed as '{/items/@count}'):
SELECT	OrderID,
	OrderDate,
	OrderItems.query('<lineitems itemcount="{/items/@count}" />') AS LineItems
FROM dbo.SalesOrder2;

/* Results, showing how the attribute itemcount now has the values pulled from items/@count:
OrderID	OrderDate	LineItems
5	2017-11-05	<lineitems itemcount="2" />
6	2017-11-05	<lineitems itemcount="1" />
7	2017-11-05	<lineitems itemcount="2" />
*/

-- example of bringing back an attribute from a specific element instance. If the element you are bringing back occurs more than once, it'll bring back all of the attribute values, separated by a space. For example, if you're bringing back a <product> and you're looking for an item element in the source XML and there are two instances, one with id="561" and one with id="127", it'll bring back '<product id="561 127" />. Therefore, it's often more useful to bring back only a specific instance of the element. Below, there are multiple item elements, so this is bringing back the first instance as denoted by '/item[1]':
SELECT	OrderID,
	OrderDate,
	OrderTiems.query('<product id="{items/item[1]/@id}" />') AS Products
FROM dbo.SalesOrder2;

/* Results, bringing back on the first instance of the items/item/@id element:
OrderID	OrderDate	Products
5	2017-11-05	<product id="561" />
6	2017-11-05	<product id="129" />
7	2017-11-05	<product id="561" />
*/

-- example of taking data from the normal SQL columns and combining it with an XML query pulling from the XML code stored in the XML column. The example will return an XML element order, which will contain an attribute called orderid which will be populated with the value for that row found in the normal OrderID column of the table (relational data), and will have an attribute itemcount which will take the value from {/items/@count} (XML data):
SELECT	OrderID,
	OrderDate,
	OrderItems.query('<order orderid="{sql:column("OrderID")}" itemcount="{/items/@count}" />') AS Orders
FROM dbo.SalesOrder2;

/* Results, showing XML that attribute values that are mix and match from the OrderID column (relational data) and the @count attribute (XML data):
OrderID	OrderDate	Orders
5	2017-11-05	<order orderid="5" itemcount="2" />
6	2017-11-05	<order orderid="6" itemcount="1" />
7	2017-11-05	<order orderid="7" itemcount="2" />
*/

-- example of querying using FLWOR syntax. FLWOR allows you to customize the way the XML is returned, including pulling multiple elements that may exist within another element. In the example below, this will do is bring each item element for each row if the quantity is greater than one, order it by @id, and then return it. As you see in the bottom row, it allows you to pull the individual item elements one by one:
SELECT	OrderID,
	OrderItems.query ('for $i in /items/item
			  where $i/@quantity = 1
			  order by $i/@id
			  return $i') AS SingleItems
FROM dbo.SalesOrder2;

/* Results:
OrderID	SingleItems
5	<item id="561" quantity="1" />
6	<item id="129" quantity="1" />
7	<item id="167" quantity="1" /><item id="561" quantity="1" />
*/

-- example using the value method. While the query method brings back XML data, the value method returns a scalar value. In the example below, it pulls the first @count attribute from the items elements and returns regular scalar values (non-XML values). Note that after specifying the XML path, you have to tell it what data type to return. In this case it's returning an integer:
SELECT	OrderID,
	OrderDate,
	OrderItems.value('/items[1]/@count', 'int') AS ItemCount
FROM dbo.SalesOrder2;

/* Results:
OrderID	OrderDate	ItemCount
5	2017-11-05	2
6	2017-11-05	1
7	2017-11-05	2
*/

-- example using the exist method, which checks for the existence of a node. exist returns a 1 if it exists and a 0 if it doesn't, so in the final line this is bringing back only nodes WHERE exist /items/item element exists (is 1). The opposite scenario could be done by placing in a 0 instead of a 1, which would bring back any rows that don't have an item:
SELECT * FROM dbo.SalesOrder2
WHERE OrderItems.exist('/items/item') = 1;

/* Results:
OrderID	OrderDate	OrderItems
5	2017-11-05	<items count="2"><item id="561" quantity="1" /><item id="127" quantity="2" /></items>
6	2017-11-05	<items count="1"><item id="129" quantity="1" /></items>
7	2017-11-05	<items count="2"><item id="561" quantity="1" /><item id="167" quantity="1" /></items>
*/

-- example of using exists to check for a specific node value, in this case looking for item elemens with a @count attribute value of greater than 1:
SELECT * FROM dbo.SalesOrder2
WHERE OrderItems.exist('/items[@count > 1]') = 1;

/* Results:
OrderID	OrderDate	OrderItems
5	2017-11-05	<items count="2"><item id="561" quantity="1" /><item id="127" quantity="2" /></items>
7	2017-11-05	<items count="2"><item id="561" quantity="1" /><item id="167" quantity="1" /></items>
*/

-- example of nodes method, which shreds the XML and allows you to identify nodes that will be returned as rows. In the example below, there is an OrderItems columns which contains three rows of XML. The first row contains two item elements, the second row contains one item element, and the third row contains two item elements. This query identifies the item element as the node in question, and will retrieve each item element into its own row in the XML results set. 
SELECT OrderID, NodesResultTable.ColumnToHoldTheXML.query('.') AS 'Cross Apply XML Retrieved'
FROM   SalesOrder2  
CROSS APPLY OrderItems.nodes('/items/item') AS NodesResultTable(ColumnToHoldTheXML);

/* Result, breaking the item element into its own rows:
OrderID	Cross Apply XML Retrieved
5	<item id="561" quantity="1" />
5	<item id="127" quantity="2" />
6	<item id="129" quantity="1" />
7	<item id="561" quantity="1" />
7	<item id="167" quantity="1" />
*/

-- detail of nodes example above.

-- complete query method for the root ('.') from the NodesResultTable and ColumnToHoldTheXML column which is definied in the CROSS APPLY line of the query
SELECT OrderID, NodesResultTable.ColumnToHoldTheXML.query('.') AS 'Cross Apply XML Retrieved'
FROM   SalesOrder2  
-- completes nodes method for the XML-containing OrderItems column of the SalesOrder2 table, with the AS defining the resulting table as NodesResultTable, with a column ColumnToHoldXML which will be of XML data type. This result table is queried in the first line of the query.
CROSS APPLY OrderItems.nodes('/items/item') AS NodesResultTable(ColumnToHoldTheXML);

-- another example of CROSS APPLY the nodes method to generate relational results. The format of the nodes method is nodes (XQuery) as Table(Column).  The example below will have a row for each item (therefore each OrderID will show up more than once if there is more than one item):
SELECT	OrderID,
	itemsTable.itemXml.value('./@id', 'int') AS Product,
	itemsTable.itemXml.value('./@quantity', 'int') AS Quantity
FROM dbo.SalesOrder2
CROSS APPLY OrderItems.nodes('/items/item') AS itemsTable(itemXml);

/* Results:
OrderID	Product	Quantity
5	561	1
5	127	2
6	129	1
7	561	1
7	167	1
*/

-- detail of CROSS APPLY example above:

-- example of CROSS APPLY using the nodes method to generate relational results. The format of the nodes method is nodes (XQuery) as Table(Column).  The example below will have a row for each item (therefore each OrderID will show up more than once if there is more than one item):
SELECT	OrderID,
  -- select value method of XML @id attribute for the items.Table.itemXml table created in final line of query, all into a column named Product
	itemsTable.itemXml.value('./@id', 'int') AS Product,
	-- select value method of XML @quantity attribute for the items.Table.itemXml table created in final line of query, all into a column named Quantity
	itemsTable.itemXml.value('./@quantity', 'int') AS Quantity
FROM dbo.SalesOrder2
-- CROSS APPLY the nodes method for the XML-containing column OrderItems, the AS determines the name of the resulting table (itemsTable) and the column in the table which will hold the XML (itemXML). This table is referenced in the SELECT statement above. In the end, it creates a row for each item found, and the SELECT then selects the @id and @quantity attribute values into the columns of the resulting relational results set.
CROSS APPLY OrderItems.nodes('/items/item') AS itemsTable(itemXml);

以上是关于sql 使用XQuery方法查询,值,存在,节点在SQL Server中查询XML的主要内容,如果未能解决你的问题,请参考以下文章

XQuery 存在方法

XQuery sql Join在join不匹配时插入空节点

SQL语句中column的意思和常用法 是怎么的 ??? 谢谢 麻烦解释下

SQL Server 中的 XQuery 对零值进行 SUM

使用 XPath 谓词优化 XQuery 查询

如何在 MS SQL 2005 中使用 SQL XQuery 修改多个节点