FOR XML SQL Server - Variable Element name in output XML - sql-server

I'm quite new to FOR XML in SQL Server, I've searched considerable and I can't find an answer to this.
Can I have a variable element name using 'for xml' where the element name is not hard-coded and is instead take from a cell in each row? Take the following example...
Table ORDERS:
ID STATUS TIME AMOUNT
------------------------------------
1 COMPLETE 02:31 2355
2 ACCEPTED 02:39 6653
3 ACCEPTED 04:21 4102
4 RECEIVED 05:03 4225
FOR XML query:
select ID,
TIME as STATUS_TIME,
AMOUNT as CURRENT_AMOUNT
from ORDERS
for xml raw(' **STATUS NAME HERE** '),root('ORDERS'), elements
Required output:
<ORDERS>
<COMPLETE> <<<<--- Variable element name from STATUS in ORDERS
<ID>1</ID>
<STATUS_TIME>02:31</STATUS_TIME>
<CURRENT_AMOUNT>2355</CURRENT_AMOUNT>
</COMPLETE>
<ACCEPTED> <<<<--- Variable element name from STATUS in ORDERS
<ID>2</ID>
<STATUS_TIME>02:39</STATUS_TIME>
<CURRENT_AMOUNT>6653</CURRENT_AMOUNT>
</ACCEPTED>
<ACCEPTED> <<<<--- Variable element name from STATUS in ORDERS
<ID>3</ID>
<STATUS_TIME>04:21</STATUS_TIME>
<CURRENT_AMOUNT>4102</CURRENT_AMOUNT>
</ACCEPTED>
<RECEIVED> <<<<--- Variable element name from STATUS in ORDERS
<ID>4</ID>
<STATUS_TIME>05:03</STATUS_TIME>
<CURRENT_AMOUNT>4225</CURRENT_AMOUNT>
</RECEIVED>
</ORDERS>
I know I'm able to give attributes to the element names, and that I could give the individual ORDER in ORDERS and attribute of STATUS like below but unfortunately that's not what the people that will receive the XML document are looking for :(
select ID,
STATUS as '#STATUS'
TIME as STATUS_TIME,
AMOUNT as CURRENT_AMOUNT
from ORDERS
for xml raw('ORDER'),root('ORDERS'), elements
Output:
<ORDERS>
<ORDER STATUS='COMPLETE'> <<<<--- Attribute for STATUS but not what I want
<ID>1</ID>
<STATUS_TIME>02:31</STATUS_TIME>
<CURRENT_AMOUNT>2355</CURRENT_AMOUNT>
</ORDER>
<ORDER STATUS='ACCEPTED'> <<<<--- Attribute for STATUS but not what I want
<ID>2</ID>
<STATUS_TIME>02:39</STATUS_TIME>
<CURRENT_AMOUNT>6653</CURRENT_AMOUNT>
</ORDER>
....
I'd like to be able to do all this within SQL Server if possible. Many, many thanks if you can help me at all on this.

You can't specify column value in XML Raw(). So what you have to do is select required column from select query and cast result into XML, like this -
Schema
DECLARE #temp table (ID int, [STATUS] [varchar](100) NOT NULL, [TIME] [varchar](100), AMOUNT int);
INSERT #temp (ID, [STATUS], [TIME], AMOUNT) VALUES (1, 'COMPLETE', '02:31', 2355),(2, 'ACCEPTED', '02:41', 6653),(3, 'ACCEPTED', '02:31', 4102),(4, 'ACCEPTED', '02:31', 4225)
Query
SELECT
CAST('<' + STATUS + '>' +
'<ID>' + CAST(ID AS varchar) + '</ID>' +
'<TIME>' + TIME + '</TIME>' +
'<AMOUNT>' + CAST(AMOUNT AS varchar) + '</AMOUNT>' +
'</' + STATUS + '>' AS XML) from #temp
FOR XML PATH(''),root('ORDERS')
Output
<ORDERS>
<COMPLETE>
<ID>1</ID>
<TIME>02:31</TIME>
<AMOUNT>2355</AMOUNT>
</COMPLETE>
<ACCEPTED>
<ID>2</ID>
<TIME>02:41</TIME>
<AMOUNT>6653</AMOUNT>
</ACCEPTED>
<ACCEPTED>
<ID>3</ID>
<TIME>02:31</TIME>
<AMOUNT>4102</AMOUNT>
</ACCEPTED>
<ACCEPTED>
<ID>4</ID>
<TIME>02:31</TIME>
<AMOUNT>4225</AMOUNT>
</ACCEPTED>
</ORDERS>

In SQL Server, XML schema has to be static, so it is impossible to specify a variable element name (be it document or attribute).
If possible options for the STATUS field are limited and stable, you can mention them all explicitly, like in the example below:
select (
select t.ID, t.TIME as [STATUS_TIME], t.AMOUNT as [CURRENT_AMOUNT]
from #temp t
where t.STATUS = 'ACCEPTED'
for xml path('ACCEPTED'), type, elements
), (
select t.ID, t.TIME as [STATUS_TIME], t.AMOUNT as [CURRENT_AMOUNT]
from #temp t
where t.STATUS = 'COMPLETE'
for xml path('COMPLETE'), type, elements
)
for xml path('ORDERS'), type;
I think you have already noticed numerous possibilities for how this code can betray you, but frankly this approach is the only one available which does not include string manipulations (they will be detrimental to performance if the size of the XML output will be at least several Mb).
As a possible workaround, you can generate this query dynamically, including as many sections as there are distinct STATUS values in your table. Very ugly, but it will work.

Related

Returning data in non tabular form from SQL server

Pardon me for the vague title, but I could not find more appropriate words for summarizing my problem.
In the database there are two tables that I want to combine and retrieve data from:
Id Name Description Id Batch Quantity
1 Item_A .... 1 1A 25
2 Item_B .... 1 1B 25
3 Item_C .... 1 1C 50
. 1 1D 50
. 2 2A 21
. . .
. . .
I want combine the from the data in second table with its corresponding Id in the first table,
that is providing the appropriate name and description for the Batches of items.
A simple join does give me the data that I want, but joining the two tables produces a large table in which the the description column is repeated for every Batch with the same Id even though only one Description data for the same Id would be sufficient.
Is there any way that combines the Name and Description data to the corresponding Id value in the second table, but that does not produce redundant data, in which the Name and the fairly long Description column is not repeated for the same Id?
One solution that I have tried, is to retrieve the two tables separately, but by sorting according to the Id in the same order. In this way I can use simple mapping function to create a pseudo object like this:
Main{
List<Item> Items
}
Item{
string Name
string Description
List<Quantity> Quantities
}
Quantity{
string Batch
int Quantity
}
However this breaks the data manipulation step in two languages and will make the code complicated and harder to understand.
Preferably, I want to retrieve the data for all the items at once(with the execution of a stored procedure once). Can somebody show be a good way to do this?
You can try to use XML.
Here is how to produce parent/child one-to-many XML in MS SQL Server.
SQL
-- DDL and sample data population, start
DECLARE #parent TABLE (ID INT PRIMARY KEY, ItemName VARCHAR(30));
INSERT INTO #parent (ID, ItemName) VALUES
(1, 'Item_A'),
(2, 'Item_B');
DECLARE #child TABLE (ID INT IDENTITY PRIMARY KEY, ParentID INT, Batch CHAR(2), Quantity INT);
INSERT INTO #child (ParentID, Batch, Quantity) VALUES
(1, '1A', 25),
(1, '1B', 25),
(1, '1C', 50),
(2, '1D', 50),
(2, '2A', 21);
-- DDL and sample data population, end
SELECT p.*
, (
SELECT c.*
FROM #child AS c
WHERE c.ParentID = p.ID
FOR XML PATH('r'), TYPE, ROOT('child')
)
FROM #parent AS p
FOR XML PATH('r'), TYPE, ROOT('root');
Output
<root>
<r>
<ID>1</ID>
<ItemName>Item_A</ItemName>
<child>
<r>
<ID>1</ID>
<ParentID>1</ParentID>
<Batch>1A</Batch>
<Quantity>25</Quantity>
</r>
<r>
<ID>2</ID>
<ParentID>1</ParentID>
<Batch>1B</Batch>
<Quantity>25</Quantity>
</r>
<r>
<ID>3</ID>
<ParentID>1</ParentID>
<Batch>1C</Batch>
<Quantity>50</Quantity>
</r>
</child>
</r>
<r>
<ID>2</ID>
<ItemName>Item_B</ItemName>
<child>
<r>
<ID>4</ID>
<ParentID>2</ParentID>
<Batch>1D</Batch>
<Quantity>50</Quantity>
</r>
<r>
<ID>5</ID>
<ParentID>2</ParentID>
<Batch>2A</Batch>
<Quantity>21</Quantity>
</r>
</child>
</r>
</root>

How to add a new line if there is a specific text appears in XML data?

I'm passing an XML to a stored procedure for inserting. XML contains some pieces of information like product specification, which is a string.
Here is a sample how the XML looks like:
<?xml version="1.0"?>
<Details>
<item Unit="PilotApp.DataAccessObject.DTO.Unit"
PSASysCommon=""
ProductModel="PilotApp.DataAccessObject.DTO.ProductModel"
Product="PilotSmithApp.DataAccessObject.DTO.Product"
SpecTag="62793f05-25ab-41b5-a081-f6c542f1f7cd"
Rate="100" UnitCode="1" Qty="1"
ProductSpec="Pilot Cone Blender Model No. Pilot PCB - 10 , volume of vessel -30 Ltr , handling capacity per batch by weight - 10 Kg and by volume - 20 Ltr. with motor - 0.25 HP/3 ph. Crompton make or equivalent , feeding door , discharge butterfly valve and safety guard .Material of construction of contact stainless steel (AISI) 304 and frame in carbon steel . Purpose : For blending dry powder and granules"
ProductModelID="10c0b51b-7799-4597-a4af-7c3fd431353b"
ProductID="15745d53-8219-431e-a0e3-0d319abf132d"
EnquiryID="00f9436c-ed2a-442c-b333-16348b0d8c33"
ID="e6812788-e67e-4874-bf80-87b39579a837"/>
</Details>
In this product specification section, there is Purpose section added. So, I want to insert it as a new line or display it as a new line and I want to do this using T-SQL
here is the insertion code of XML to a temp table
DECLARE #temp TABLE(
ID UNIQUEIDENTIFIER,
EnquiryID UNIQUEIDENTIFIER,
ProductID UNIQUEIDENTIFIER,
ProductModelID UNIQUEIDENTIFIER,
ProductSpec NVARCHAR(MAX),
Qty DECIMAL(18,2),
Rate DECIMAL(18,2),
UnitCode INT,
SpecTag UNIQUEIDENTIFIER,
IsProcessed bit,
tmpID UNIQUEIDENTIFIER
);
------------parse from xml to temptable ----
INSERT INTO #temp(ID,EnquiryID,ProductID,ProductModelID,
ProductSpec,Qty,Rate,UnitCode,SpecTag,IsProcessed,tmpID)
SELECT T.ID,T.EnquiryID,T.ProductID,T.ProductModelID,replace(replace(replace(replace(T.ProductSpec,'"','"'),'&','&'),'<','<'),'>','>') AS ProductSpec,
T.Qty,T.Rate,T.UnitCode,
-----modified on 14-May-2018 added field SpecTag in EnquiryDetail by Thomson
CASE WHEN T.SpecTag=CAST(CAST(0 AS BINARY) AS UNIQUEIDENTIFIER) THEN NEWID() ELSE T.SpecTag END,
T.IsProcessed,T.tmpID FROM
(SELECT [xmlData].[Col].value('./#ID', 'UNIQUEIDENTIFIER') as ID,
[xmlData].[Col].value('./#EnquiryID', 'UNIQUEIDENTIFIER') as EnquiryID,
[xmlData].[Col].value('./#ProductID', 'UNIQUEIDENTIFIER') as ProductID,
[xmlData].[Col].value('./#ProductModelID', 'UNIQUEIDENTIFIER') as ProductModelID,
[xmlData].[Col].value('./#ProductSpec', 'NVARCHAR(MAX)') as ProductSpec,
[xmlData].[Col].value('./#Qty','DECIMAL(18,2)')as Qty,
[xmlData].[Col].value('./#Rate','DECIMAL(18,2)')as Rate,
[xmlData].[Col].value('./#UnitCode','INT')as UnitCode,
[xmlData].[col].value('./#SpecTag','UNIQUEIDENTIFIER') AS SpecTag,
0 as IsProcessed,
newid() as tmpID
from #DetailXML.nodes('/Details/item') as [xmlData]([Col])) T
Here are the steps to solve this problem.
First get whole string from ProductSpec XML tag as column name "ProductSpec".
Get the sub-string from ProductSpec where sub string started from Purpose in new column as "ProductSpecPurpose".
Append char(10) or char(13) as per your need in string which you have extracted. E.g. char(10) + ProductSpecPurpose.
Merge the two columns which created in step 1 & 2.
Save it.
PS: I did not write solution directly so that at least you can try different sql functions and learn more. Because I believe in learning by ourselves rather spoon feeding. Give it try and if you are not able to figure it out. Do comment I will then write whole sql answer.
Try this to find how to extract the data nested within your XML:
DECLARE #xml XML=
'<?xml version="1.0"?>
<Details>
<item Unit="PilotApp.DataAccessObject.DTO.Unit"
PSASysCommon=""
ProductModel="PilotApp.DataAccessObject.DTO.ProductModel"
Product="PilotSmithApp.DataAccessObject.DTO.Product"
SpecTag="62793f05-25ab-41b5-a081-f6c542f1f7cd"
Rate="100" UnitCode="1" Qty="1"
ProductSpec="Pilot Cone Blender Model No. Pilot PCB - 10 , volume of vessel -30 Ltr , handling capacity per batch by weight - 10 Kg and by volume - 20 Ltr. with motor - 0.25 HP/3 ph. Crompton make or equivalent , feeding door , discharge butterfly valve and safety guard .Material of construction of contact stainless steel (AISI) 304 and frame in carbon steel . Purpose : For blending dry powder and granules"
ProductModelID="10c0b51b-7799-4597-a4af-7c3fd431353b"
ProductID="15745d53-8219-431e-a0e3-0d319abf132d"
EnquiryID="00f9436c-ed2a-442c-b333-16348b0d8c33"
ID="e6812788-e67e-4874-bf80-87b39579a837"/>
</Details>';
SELECT itm.value('#Unit','nvarchar(max)') AS Unit
,itm.value('#PSASysCommon','nvarchar(max)') AS PSASysCommon
,itm.value('#Product','nvarchar(max)') AS Product
,itm.value('#SpecTag','uniqueidentifier') AS SpecTag
,itm.value('#Rate','int') AS Rate
,itm.value('#UnitCode','int') AS UnitCode
,itm.value('#Qty','int') AS Qty
,itm.value('#ProductSpec','nvarchar(max)') AS ProductSpec
,itm.value('#ProductModelID','uniqueidentifier') AS ProductModelID
,itm.value('#ProductID','uniqueidentifier') AS ProductID
,itm.value('#ID','uniqueidentifier') AS ID
FROM #xml.nodes('/Details/item') A(itm);
My approach assumes, that there might be several <item> elements within <Details>.
Just some explanation: The <item> element is a self-closing element with all data placed within attributes. This is a very easy form to query. Good for you...
Btw: It would be best to avoid the <?xml blah?>-declaration at all. Within SQL-Server this declaration is useless and can disturb with encodings...
UPDATE
An enhanced query to parse the spec in lines and extract the Purpose:
SELECT itm.value('#Unit','nvarchar(max)') AS Unit
,itm.value('#PSASysCommon','nvarchar(max)') AS PSASysCommon
,itm.value('#Product','nvarchar(max)') AS Product
,itm.value('#SpecTag','uniqueidentifier') AS SpecTag
,itm.value('#Rate','int') AS Rate
,itm.value('#UnitCode','int') AS UnitCode
,itm.value('#Qty','int') AS Qty
,itm.value('#ProductSpec','nvarchar(max)') AS ProductSpec
,itm.value('#ProductModelID','uniqueidentifier') AS ProductModelID
,itm.value('#ProductID','uniqueidentifier') AS ProductID
,itm.value('#ID','uniqueidentifier') AS ID
,LTRIM(RTRIM(ProductSpecLine.value('text()[1]','nvarchar(max)'))) AS ProductSpecLine_Text
,Purpose
FROM #xml.nodes('/Details/item') A(itm)
OUTER APPLY(SELECT CAST('<x>' + REPLACE((SELECT itm.value('#ProductSpec','nvarchar(max)') AS [*] FOR XML PATH('')),',','</x><x>') + '</x>' AS XML)) B(x)
OUTER APPLY B.x.nodes('/x') C(ProductSpecLine)
OUTER APPLY (SELECT CASE WHEN CHARINDEX('Purpose : ',ProductSpecLine.value('text()[1]','nvarchar(max)'))>0
THEN SUBSTRING(ProductSpecLine.value('text()[1]','nvarchar(max)'),CHARINDEX('Purpose : ',ProductSpecLine.value('text()[1]','nvarchar(max)')),1000)
END) D(Purpose);

SQL to populate values in xml list

In an SQL Server sproc I need to generate xml using data originating from two different tables. In my example below, the patient number for type EPI comes from one table and the patient number for type MRN comes from another table. To create the xml I am using a UNION to combine the records from two distinct select statements and then using 'FOR XML PATH'. Is there a different way - such as using two select sub-queries without using UNION?
<Patients>
<Patient>
<Number>1234</Number>
<NumberType>EPI</NumberType>
</Patient>
<Patient>
<Number>5678</Number>
<NumberType>MRN</NumberType>
</Patient>
</Patients>
Thanks in advance.
If I understood your answer to my question, you are not really joining the tables on PatientId, you are just creating a list of all the data from both tables, and you don't need to group the records by patient.
Yes, UNION is the easiest way to accomplish a single list.
However, since you want to output xml, there is an alternate that can be done without UNION, per your question:
Assuming you have two tables that might look something like this:
CREATE TABLE SrcA (PatientId int, NumberA int, TypeA varchar(16));
CREATE TABLE SrcB (PatientId int, NumberB int, TypeB varchar(16));
with sample values like this (note how each table has one record not in the other):
INSERT INTO SrcA VALUES(100, 1234, 'EPI'), (200, 2222, 'EPI'), (400, 4444, 'EPI');
INSERT INTO SrcB VALUES(100, 5678, 'MRN'), (200, 2121, 'MRN'), (300, 3131, 'MRN');
Then the following query:
SELECT
(SELECT SA.NumberA AS Number, SA.TypeA AS NumberType WHERE SA.NumberA IS NOT NULL FOR XML PATH('Patient'), TYPE),
(SELECT SB.NumberB AS Number, SB.TypeB AS NumberType WHERE SB.NumberB IS NOT NULL FOR XML PATH('Patient'), TYPE)
FROM SrcA SA
FULL OUTER JOIN SrcB SB ON SA.PatientId = SB.PatientId
FOR XML PATH(''), ROOT('Patients')
will produce:
<Patients>
<Patient>
<Number>1234</Number>
<NumberType>EPI</NumberType>
</Patient>
<Patient>
<Number>5678</Number>
<NumberType>MRN</NumberType>
</Patient>
<Patient>
<Number>2222</Number>
<NumberType>EPI</NumberType>
</Patient>
<Patient>
<Number>2121</Number>
<NumberType>MRN</NumberType>
</Patient>
<Patient>
<Number>4444</Number>
<NumberType>EPI</NumberType>
</Patient>
<Patient>
<Number>3131</Number>
<NumberType>MRN</NumberType>
</Patient>
</Patients>

How to get results in a specific XML format from a TSQL query?

I have the following T-SQL query that I want to convert into XML file. I was trying to use FOR XML Path, but this isn't working the way I need it to.
Here is my T-SQL table definition:
create table TN_DataFeed
(
--Patient uniqueidentifier,
ProviderPatientNo varchar(50) null,
LastName varchar(25),
FirstName varchar(25),
SSN char(9) null,
DOB char(10) null,
Gender tinyint null,
Race tinyint null,
Ethnicity tinyint null,
--PhoneAssessment varchar(50),
ProviderPhoneAssessmentID varchar(50),
CallEndDate char(10),
CallEndTime varchar(8)
)
My data matches this format above and successfully is inserted. But I need my XML to look like:
<Patient>
<ProviderPatientNo>ProviderPatientNo0</ProviderPatientNo>
<LastName>LastName0</LastName>
<FirstName>FirstName0</FirstName>
<SSN>000000000</SSN>
<DOB>2006-05-04</DOB>
<Gender>1</Gender>
<Race>1</Race>
<Ethnicity>1</Ethnicity>
<PhoneAssessment>
<ProviderPhoneAssessmentId>52854541</ProviderPhoneAssessmentId>
<CallEndDate>2006-05-04</CallEndDate>
<CallEndTime>01:01:01.001</CallEndTime>
</PhoneAssessment>
</Patient>
This is my XML Path code for retrieving the above T-SQL query:
select
ProviderPatientNo,
LastName,FirstName,SSN,DOB,Gender,Race,Ethnicity,
(
select distinct
ProviderPhoneAssessmentId, CallEndDate, CallEndTime
from TN_DataFeed
For XML path ('PhoneAssessment'), root('PhoneAssessment2'), type
)
from TN_DataFeed
For XML path ('Patient'), root('Patient_root'), type
Note that I have not yet included all of the columns. Instead, I'm just trying to get the Patient section working. Notice how in the example XML file below, the section that shows how Patient is the parent node of ProviderPatientNo, LastName, FirstName, SSN, DOB, Gender, Race, and Ethnicity.
But instead, my XML output from my above XML Path is:
<Patient_root>
<Patient>
<ProviderPatientNo>00200543</ProviderPatientNo>
<LastName>Ga</LastName>
<FirstName>Ti</FirstName>
<SSN>4108</SSN>
<DOB>1998-08-16</DOB>
<Gender>2</Gender>
<Race>2</Race>
<Ethnicity>3</Ethnicity>
<PhoneAssessment2>
<PhoneAssessment>
<ProviderPhoneAssessmentId>BEA5487B-82E9-4226-B883-BFBFE7EF2B1A</ProviderPhoneAssessmentId>
<CallEndDate>2013-09-16</CallEndDate>
<CallEndTime>22:00:00</CallEndTime>
</PhoneAssessment>
<PhoneAssessment>
<ProviderPhoneAssessmentId>C8F39E2F-BC4A-48AD-BD07-C07EB8384AD7</ProviderPhoneAssessmentId>
<CallEndDate>2013-09-16</CallEndDate>
<CallEndTime>16:24:00</CallEndTime>
</PhoneAssessment>
</PhoneAssessment2>
</Patient>
<Patient>
<ProviderPatientNo>00200543</ProviderPatientNo>
<LastName>Ga</LastName>
<FirstName>Ti</FirstName>
<SSN>4108</SSN>
<DOB>1998-08-16</DOB>
<Gender>2</Gender>
<Race>2</Race>
<Ethnicity>3</Ethnicity>
<PhoneAssessment2>
<PhoneAssessment>
<ProviderPhoneAssessmentId>BEA5487B-82E9-4226-B883-BFBFE7EF2B1A</ProviderPhoneAssessmentId>
<CallEndDate>2013-09-16</CallEndDate>
<CallEndTime>22:00:00</CallEndTime>
</PhoneAssessment>
<PhoneAssessment>
<ProviderPhoneAssessmentId>C8F39E2F-BC4A-48AD-BD07-C07EB8384AD7</ProviderPhoneAssessmentId>
<CallEndDate>2013-09-16</CallEndDate>
<CallEndTime>16:24:00</CallEndTime>
</PhoneAssessment>
</PhoneAssessment2>
</Patient>
So the problems are:
Many of the elements are repeated. I tried using Distinct to limit repetitions, but this caused the error:
The xml data type cannot be selected as DISTINCT because it is not
comparable.
Ok: First thing I notice is that you're querying the information_schema not the actual table, and all this gives you is the table schema metadata. Can you change your query to query the table please? SELECT ... FROM TN_DataFeed.
See this example : http://technet.microsoft.com/en-us/library/bb510462.aspx
Something like this should get you close to what you want:
SELECT ProviderPatientNo,
LastName,
FirstName,
SSN,
DOB,
Gender,
Race,
PhoneAssessment ....
FROM TN_DataFeed
FOR XML PATH ('Patient');
you can replace the distinct with a GROUP BY
select
ProviderPhoneAssessmentId, CallEndDate, CallEndTime
from
TN_DataFeed
group by
ProviderPhoneAssessmentId, CallEndDate, CallEndTime

SQL Server 2005 - searching for value in XML field

I'm trying to query a particular value in an XML field. I've seen lots of examples, but they don't seem to be what I'm looking for
Supposing my xml field is called XMLAttributes and table TableName, and the complete xml value is like the below:
<Attribute name="First2Digits" value="12" />
<Attribute name="PurchaseXXXUniqueID" value="U4RV123456762MBE79" />
(although the xml field will frequently have other attributes, not just PurchaseXXXUniqueID)
If I'm looking for a specific value in the PurchaseXXXUniqueID attribute name - say U4RV123456762MBE79 - how would I write the query? I believe it would be something like:
select *
from TableName
where XMLAttributes.value('(/path/to/tag)[1]', 'varchar(100)') = '5FTZP2QT8Z3E2MAV2D'
... but it's the path/to/tag that I need to figure out.
Or probably there's other ways of getting the values I want.
To summarize - I need to get all the records in a table where the value of a particular attribute in the xml field matches a value I'll pass to the query.
thanks for the help!
Sylvia
edit: I was trying to make this simpler, but in case it makes a difference - ultimately I'll have a temporary table of 50 or so potential values for the PurchaseXXXUniqueID field. For these, I want to get all the matching records from the table with the XML field.
This ought to work:
SELECT
(fields from base table),
Nodes.Attr.value('(#name)[1]', 'varchar(100)'),
Nodes.Attr.value('(#value)[1]', 'varchar(100)')
FROM
dbo.TableName
CROSS APPLY
XMLAttributes.nodes('/Attribute') AS Nodes(Attr)
WHERE
Nodes.Attr.value('(#name)[1]', 'varchar(100)') = 'PurchaseXXXUniqueID'
AND Nodes.Attr.value('(#value)[1]', 'varchar(100)') = 'U4RV123456762MBE79'
You basically need to join the base table's row against one "pseudo-row" for each of the <Attribute> nodes inside the XML column, and the pick out the individual attribute values from the <Attribute> node to select what you're looking for.
Something like that?
declare #PurchaseXXXUniqueID varchar(max)
set #PurchaseXXXUniqueID = 'U4RV123456762MBE79';
select * from TableName t
where XMLAttributes.exist('//Attribute/#value = sql:variable("#PurchaseXXXUniqueID")') = 1

Resources