I am trying to format the output of a query using FOR XML in SQL Server 2012.
Each PART_NO can have a varying number of SUPPLIER_PART_NUMBER's mapped to it.
The table has data in the following format.
PART_NO SUPPLIER_PART_NO
------- ----------------
AAA 1
AAA 2
BBB 3
BBB 4
BBB 5
The desired output is as follows where part AAA has two supplier part numbers and part BBB has three supplier part numbers, and the supplier part numbers are nested below the part number.
<root>
<item PartNo ="AAA">
<mpn>1</mpn>
<mpn>2</mpn>
</item>
<item PartNo ="BBB">
<mpn>3</mpn>
<mpn>4</mpn>
<mpn>5</mpn>
</item>
</root>
The closest I can get is below, but this does not group the mpn under PartNo:
SELECT
[PART_NO] as 'item/#PartNo',
[SUPPLIER_PART_NO] as 'mpn'
FROM
[dbo].[supplier_part_mapping2]
ORDER BY
PART_NO
FOR XML PATH('') , ROOT('root');
Thank you in advance
Try this:
SELECT
p1.PART_NO as 'item/#PartNo',
(SELECT
SUPPLIER_PART_NO AS 'mpn'
FROM
[dbo].[supplier_part_mapping2] p2
WHERE
p1.PART_NO = p2.PART_NO
FOR XML PATH(''), TYPE) AS 'item'
FROM
[dbo].[supplier_part_mapping2] p1
GROUP BY
PART_NO
ORDER BY
PART_NO
FOR XML PATH('') , ROOT('root');
This should produce:
You basically need to group by the PART_NO so that you get only one <item> entry for each distinct PART_NO, and you need to grab the "sub-elements" as a subquery to list them all together under one parent node.
Related
I have
mytable consists of one XMLTYPE column called 'RS'. RS contains:
<test>
<mycol>
<name>a</name>
<number>1</number>
<number>2</number>
<number>50</number>
<number>60</number>
</mycol>
<mycol>
<name>b</name>
<number>5</number>
<number>820</number>
<number>601</number>
</mycol>
<mycol>
<name>c</name>
<number>6</number>
<number>8</number>
<number>62</number>
</mycol>
etc...
</test>
I'm looking to run a select statement that will display ALL names and up to 2 numbers from mytable.
something like this select statement but for all rows and without calling mycol[] several times.
select a.RS.extract('/test/mycol[1]/name[1]/text()').getstringval() as Names,
a.RS.extract('/test/mycol[1]/a[1]/text()').getstringval() ||''||
a.RS.extract('/test/mycol[1]/a[2]/text()').getstringval() ||''||
a.RS.extract('/test/mycol[1]/a[3]/text()').getstringval()
as num
from mytable a;/
output should be:
Names | num
a | 1 2
b | 5 820
c | 6 8
etc...
Thanks in advance.
Xml_table and string-join may be helpful
I'm currently working with a database that stores XML record for all of its field, please see below example. Lets name the table CUSTOMER table.
customer table
------------------------------------------------------
| RECID | XMLRECORD |
| 1 | <row id='1' xml:space="preserve"><c1>... |
| 2 | <row id='2' xml:space="preserve"><c1>... |
| 3 | <row id='3' xml:space="preserve"><c1>... |
------------------------------------------------------
All of the record of each customer is stored in 1 field called XMLRECORD, below is one example of XML RECORD of a customer.
<row id="1" xml:space="preserve">
<c1>James</c1>
<c2>Anderson</c2>
<c3>25</c3>
<c4>District 2 1657</c4>
<c4 m="2">Riverside Drive Redding</c4>
<c4 m="3">California, USA</c4>
</row>
Where c1 would be the customer's first name, c2 for last name, c3 for age and c4 would be the customer's address.
To query or extract values for each column, I usually use .value function to extract and return single value.
SELECT XMLRECORD.value('(/row/c4)[1]','NVARCHAR(20)') as ADDRESS
FROM CUSTOMER
Now my problem is this function only returns a single value, what I want is to return all the values under c4, which is multi value field. Can someone advise a way to do this?
Initiating the table
declare #xml as table
(
recid int,
xmlrecord xml
)
insert into #xml
values
( 1 , '<row id="1" xml:space="preserve">
<c1>James</c1>
<c2>Anderson</c2>
<c3>25</c3>
<c4>District 2 1657</c4>
<c4 m="2">Riverside Drive Redding</c4>
<c4 m="3">California, USA</c4>
</row>' )
DECLARE #XMLRECORD as xml =
'<row id="1" xml:space="preserve">
<c1>James</c1>
<c2>Anderson</c2>
<c3>25</c3>
<c4>District 2 1657</c4>
<c4 m="2">Riverside Drive Redding</c4>
<c4 m="3">California, USA</c4>
</row>' ;
Using .nodes functionality to fetch all the nodes
SELECT T.C.value('.','NVARCHAR(1000)') as c4_nodes FROM #XMLRECORD.nodes('(/row/c4)') as T(C)
Output -
c4_nodes
---------
District 2 1657
Riverside Drive Redding
California, USA
Since this fetches multiple records, using stuff command to concatenate the rows
SELECT
recid
,STUFF((
SELECT ',' + T.C.value('.','NVARCHAR(1000)')
FROM XMLRECORD.nodes('(/row/c4)') as T(C)
FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'), 1, 1, '') c4
FROM #xml
Output -
recid | c4
-----------
1 District 2 1657,Riverside Drive Redding,California, USA
c4 should not repeat multiple time. data should be stored in single node. For all node value, you should use [*] to get all node value.
You can try something like this
SELECT Tmp.record.value('.','NVARCHAR(20)')
FROM [customer]
CROSS APPLY [XMLRECORD].nodes('/row/c4') as Tmp(record)
I am supposed to be extracting data from an XML column in sql server 2012. Some values for this column will have multiple nodes. Unfortunately, the XML does not have a root node, and so using the CROSS APPLY does not seem to work.
Simplified example:
<header><msg_type>TYPE_ONE</msg_type>
<status><status_1>aaaa</status_1><status_2>bbbb</status_2>
<node_1><customerID>1234</customerID><zipcode>11111</zipcode>...</node_1>
<node_2><customerID>1234</customerID><ordernum>12345</ordernum><data2>A</ordernum>...</node_2>
<node_2><customerID>1234</customerID><ordernum>34567></ordernum><data2>B</ordernum>...</node_2>
<node_3><customerID>1234</customerID><delivery>2014-05-05 14:00:00></delivery>...</node_3>
<node_1><customerID>ABCD</customerID><zipcode>12345</zipcode>...</node_1>
<node_2><customerID>ABCD</customerId><ordernum>123536</ordernum><data2>C</ordernum>...</node_2>
<node_3><customerID>ABCD</customerID><delivery>2014-05-05 16:00:00>...</node_3>
.
.
.
(... = more elements)
Here's an example using CROSS APPLY against one of the multi-node types:
select
t.InfoXML.value( '/node_1/customerID)[1]', 'varchar(50)' ) as CustomerId
, CA.Det.value( '(/node_2/ordernum)[1]', 'varchar(20)') as OrderNumber
, CA.Det.value( '(/node_2/data2)[1]', 'varchar(5)' ) as Data2
from TableUnderTest as t
CROSS APPLY t.InfoXML.nodes( '/node_2') as CA(Det)
where t.InfoXML.value( '(/header/msg_type)[1]', 'varchar(20)') = 'TYPE_ONE'
This had results
CustomerID OrderNumber Data2
================================
1234 12345 A
1234 12345 A
1234 12345 A
My current thought is to create a temporary table and insert the XML fields (that match the WHERE clause) after wrapping the XML value in a root node, and then trying to get the data from the temporary table. My current effort to set the first part up:
Declare #Rooted Table (Rec XML);
insert into #Rooted(Rec)
(
select (convert (XML, '<root>', + convert(varchar(MAX),
t.XmlData.query('./') + '<\root>')) as Rec
from TableUnderTest t
where t.XmlData.value( '(/header/msg_type)[1]', 'varchar(20)' ) = 'TYPE_ONE'
)
Right now, the above gives a syntax error.
What I want for output is something as follows:
CustomerID ZipCode OrderNumber Data2 Delivery status2
-------------------------------------------------------------------
1234 11111 12345 A 2014-05-05 14:00:00 aaaa
1234 11111 34567 B 2014-05-05 14:00:00 aaaa
ABCD 12345 123456 D 2014-05-05 15:00:00 aaaa
What would be the best approach to take? (This is for testing, not production, so performance is not critical.) I've only been learning to write sql queries for XML for the last month, so perhaps I'm overlooking something. It appears the critical issue is the lack of a root node for the XML, but how do I work around it?
I'm trying to split an SQL results set (in a Stored Proc) into multiple columns for XML formatting. I have a results set with a Supplier Number and a Product Number like this:
SupplierID ProdCode
----------- ---------
Supp1 Prod1
Supp1 Prod2
Supp1 Prod3
Supp2 Prod2
Supp2 Prod3
Supp3 Prod2
etc.
I need to split this results set so that each supplier has its own dataset, which can then be split into its own XML node, as shown here:
<SUPPLIER>
<SUPPLIER_LINES>
<SUPPNO>Supp1</SUPPNO>
<PRODCODE>Prod1</WWPROD>
</SUPPLIER_LINES>
<SUPPLIER_LINES>
<SUPPNO>Supp1</SUPPNO>
<PRODCODE>Prod2</WWPROD>
</SUPPLIER_LINES>
<SUPPLIER_LINES>
<SUPPNO>Supp1</SUPPNO>
<PRODCODE>Prod3</WWPROD>
</SUPPLIER_LINES>
</SUPPLIER>
<SUPPLIER>
<SUPPLIER_LINES>
<SUPPNO>Supp2</SUPPNO>
<PRODCODE>Prod2</WWPROD>
</SUPPLIER_LINES>
<SUPPLIER_LINES>
<SUPPNO>Supp2</SUPPNO>
<PRODCODE>Prod3</WWPROD>
</SUPPLIER_LINES>
</SUPPLIER>
I'll be able to figure out the XML formatting, but am having trouble splitting the results inside a stored proc to get this:
SupplierID ProdCode
Supp1 Prod1
Supp1 Prod2
SupplierID ProdCode
Supp2 Prod2
Supp2 Prod3
You can do a group by on SupplierID for the SUPPLIER nodes and use a correlated sub-query to get the SUPPLIER_LINES nodes.
select (
select T2.SupplierID as SUPNO,
T2.ProdCode as PRODCODE
from YourTable as T2
where T1.SupplierID = T2.SupplierID
for xml path('SUPPLIER_LINES'), type
)
from YourTable as T1
group by SupplierID
for xml path('SUPPLIER')
You probably have suppliers in table of it's own so if you use that table in the main query you don't have to do the group by.
I don't think you need to generate separate result sets in your SP (which I think is what you're asking).
By various tweaking of the FOR XML options, you should be able to generate this XML in one query, although you may need to use the EXPLICIT option.
This should be a good starting point
select
SupplierID as SuppNo,
ProdCode
from
#t
for xml path('Supplier'), elements, type
I have a table like this :
YEAR int,
Fields XML
My XML column has this structure for all rows but with different values:
How I can get this result:
YEAR ID NAME LASTNAME
---------------------------------------------------
2011 1000 Nima Agha
2011 1001 Begha Begha
2011 1002 Jigha Jigha
2011 1003 Aba Aba
2012 1034 AAA BBB
...
thanks
How about this:
SELECT
Year,
E.P.value('(ID)[1]', 'INT') AS 'ID',
E.P.value('(Name)[1]', 'VARCHAR(50)') AS 'Name',
E.P.value('(LastName)[1]', 'VARCHAR(50)') AS 'LastName'
FROM
dbo.YourTable
CROSS APPLY
Fields.nodes('/Employees/Person') AS E(P)
You're basically selecting Year from the base table and then extracting each <Person> node from the Fields column into an "inline XML table" called E with a single XML column called P (you can choose whatever names you like for those) that you again query and extract the individual elements from .