Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Get the count of nodes in an XML field XQuery SQL Server 2008

I am trying to get the count of nodes in an XML field. but I always see 0 as the result. Here is how my query looks like.


 DECLARE @XmlTable TABLE (XmlResult XML)
INSERT INTO @XmlTable EXECUTE [dbo].usp_GetBooks @EditionId=400
--select * from  @XmlTable
SELECT
--Count number of nodes
  COUNT(*) AS BooksCount
FROM
(
SELECT XmlResult FROM @XmlTable
) AS XmlTable(XmlColumn)
CROSS APPLY XmlColumn.nodes('./books/book') XmlTableFunction(XmlColumn2);

My XML Looks like :

<Version number ="1"> 
<books>
<book>
  <name> </name>
  <author></author>
</book>
<book>
  <name> </name>
  <author></author>
</book>
</books>
</Version>
like image 697
BumbleBee Avatar asked Mar 25 '11 21:03

BumbleBee


People also ask

How do I count the number of nodes in XML?

Count the XML elements (XPath) newInstance(). newXPath(); NodeList nodes = (NodeList) xpath. evaluate("//staff", doc, XPathConstants. NODESET); int count = nodes.

How do I query XML data in XQuery?

Querying in an XQuery contextIf your query invokes an XQuery expression directly, you must prefix it with the case-insensitive keyword XQUERY. To retrieve all of the XML documents previously inserted into the INFO column, you can use XQuery with either db2-fn:xmlcolumn or db2-fn:sqlquery.

How do I query values in XML nodes?

You can retrieve multiple values from the rowset. For example, you can apply the value() method to the rowset returned by nodes() and retrieve multiple values from the original XML instance. The value() method, when applied to the XML instance, returns only one value.

How can I get SQL query results in XML?

You can optionally retrieve formal results of a SQL query as XML by specifying the FOR XML clause in the query. The FOR XML clause can be used in top-level queries and in subqueries. The top-level FOR XML clause can be used only in the SELECT statement.


2 Answers

I think your XPath expression is wrong - try this instead:

DECLARE @XmlTable TABLE (XmlResult XML)

INSERT INTO @XmlTable EXECUTE [dbo].usp_GetBooks @EditionId=400

SELECT
    COUNT(*) AS BooksCount
FROM
   (SELECT XmlResult FROM @XmlTable) AS XmlTable(XmlColumn)
CROSS APPLY 
   XmlColumn.nodes('/Version/books/book') XmlTableFunction(XmlColumn2)

Or even simpler:

DECLARE @XmlTable TABLE (XmlResult XML)

INSERT INTO @XmlTable EXECUTE [dbo].usp_GetBooks @EditionId=400

SELECT
    XmlResult.value('count(/Version/books/book)', 'int')
FROM
   @XmlTable
like image 195
marc_s Avatar answered Oct 27 '22 14:10

marc_s


Works for me with the XML pattern you give

DECLARE @XmlTable TABLE (XmlResult XML)
INSERT INTO @XmlTable VALUES ('<books><book><title>GWTW</title></book></books>')
INSERT INTO @XmlTable VALUES ('<foo />')
INSERT INTO @XmlTable VALUES ('<books />')
SELECT
  COUNT(*) AS BooksCount
FROM
(
SELECT XmlResult FROM @XmlTable
) AS XmlTable(XmlColumn)
CROSS APPLY XmlColumn.nodes('./books/book') XmlTableFunction(XmlColumn2);

Exist method is quite useful too. I use NULLIF to change 0 to NULL (it is bit so would need CAST with SUM)

SELECT COUNT(NULLIF(XmlResult.exist('./books/book'), 0)) FROM @XmlTable

Edit, after update

The XML you posted is wrong too.

You are not specifying the root note correctly:

DECLARE @XmlTable TABLE (XmlResult XML)
INSERT INTO @XmlTable VALUES ('
<Version number ="1"> 
<books>
<book>
  <name> </name>
  <author></author>
</book>
<book>
  <name> </name>
  <author></author>
</book>
</books>
</Version>')
SELECT
  COUNT(*)
FROM
(
SELECT XmlResult FROM @XmlTable
) AS XmlTable(XmlColumn)
CROSS APPLY XmlColumn.nodes('/Version/books/book') XmlTableFunction(XmlColumn2);

SELECT
  COUNT(*)
FROM
(
SELECT XmlResult FROM @XmlTable
) AS XmlTable(XmlColumn)
CROSS APPLY XmlColumn.nodes('*/books/book') XmlTableFunction(XmlColumn2);
like image 31
gbn Avatar answered Oct 27 '22 13:10

gbn