2

I have XML data stored in SQL Server database in one column.

<data>
    <row>
<element name="product">Piston</element>
<element name="number">1.2</element>
    </row>
<row>
<element name="product">Piston Ring</element>
<element name="number">2</element>
    </row>
<row>
<element name="product">Piston</element>
<element name="number">1.5</element>
    </row>
</data>

Is there a way I can get result in following format?

------------------------------
Product    | Count
------------------------------
Piston     |   2
Piston Ring|   1
------------------------------

I tried with Xpath which gives me count of anything, but not sure if I can group by product and then get a count.

I'm looking for something like (In SQL Query)

SELECT Product, Count(Product) FROM ABC
GROUP BY Product

3 Answers 3

5

You cannot use the XML methods directly within GROUP BYso I'd use a CTE. First you get table data out of your XML, than you can do a "normal" COUNT with GROUP BY:

DECLARE @xml XML=
'<data>
  <row>
    <element name="product">Piston</element>
    <element name="number">1.2</element>
  </row>
  <row>
    <element name="product">Piston Ring</element>
    <element name="number">2</element>
  </row>
  <row>
    <element name="product">Piston</element>
    <element name="number">1.5</element>
  </row>
</data>';

;WITH MyRows AS
(
    SELECT OneRow.value('(element[@name="product"])[1]','varchar(max)') AS Product
    FROM @xml.nodes('/data/row') AS A(OneRow)
)
SELECT Product,COUNT(Product) AS [Count]
FROM MyRows
GROUP BY Product
Sign up to request clarification or add additional context in comments.

3 Comments

Hi, this is giving the expected result, but taking too much time. ( I checked with very large data). But thanks, it works.
@Anand,you might think about an XML index. I answered a similar question shortly: stackoverflow.com/q/35575990/5089204
@Shnugo. Can you please explain how the following works? SELECT OneRow.value('(element[@name="product"])[1]','varchar(max)') AS Product FROM @xml.nodes('/data/row') AS A(OneRow)
1
DECLARE @x XML=
'<data>
  <row>
    <element name="product">Piston</element>
    <element name="number">1.2</element>
  </row>
  <row>
    <element name="product">Piston Ring</element>
    <element name="number">2</element>
  </row>
  <row>
    <element name="product">Piston</element>
    <element name="number">1.5</element>
  </row>
</data>'

SELECT val, COUNT_BIG(1)
FROM (
    SELECT val = t.c.value('.', 'VARCHAR(100)')
    FROM @x.nodes('/data/row/element[@name="product"]') t(c)
) t
GROUP BY val
OPTION (OPTIMIZE FOR (@x = NULL))

Output -

------------------- --------------------
Piston              2
Piston Ring         1

2 Comments

This is brilliant! Thanks. Could you please explain me the last line? "OPTION (OPTIMIZE FOR (@x = NULL))"
Just a small optimization issue, if you expected a very big xml
0

I would use CROSS APPLY from table to XML column

CREATE TABLE XMLwithOpenXML (
     id INT IDENTITY PRIMARY KEY
   , XMLData XML
   , LoadedDateTime DATETIME
)
GO

DECLARE @xml XML = '
<data> 
    <row>
        <element name="product">Piston</element>
        <element name="number">1.2</element>
    </row>
    <row>
        <element name="product">Piston Ring</element>
        <element name="number">2</element>
    </row>
    <row>
        <element name="product">Piston</element>
        <element name="number">1.5</element>
    </row>
</data>'

INSERT INTO XMLwithOpenXML (XMLData, LoadedDateTime)
SELECT @xml, GETDATE()

SELECT Product, COUNT(Product) AS ProdCount
FROM (
    SELECT
         n.C.value('(element[@name="product"])[1]', 'varchar(100)') product
       , n.C.value('(element[@name="number"])[1]', 'varchar(100)') number
    FROM XMLwithOpenXML
    CROSS APPLY XMLData.nodes('/data/row') n(C)
) A
GROUP BY Product

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.