sql server query xml related nodes - sql-server

In the T-SQL sample code below I am trying to query related pieces of data that are in different nodes in the xml, but I can't figure out how to do that. For example, the LX01_AssignedNumber and the C00302_ProcedureCode values need to be pulled together for the same record. The result should look like this.
CLAIM_SOURCE_ID ITEM_NUMBER HCPCS_LINE_CODE
16202E123456 1 99203
16202E123456 2 96372
Can someone help me?
USE [tempdb];
GO
DECLARE #XML XML =
N'<ns1:X12EnrichedMessage xmlns:ns1="http://schemas.microsoft.com/BizTalk/EDI/EDIFACT/2006/EnrichedMessageXML">
<TransactionSet>
<!-- ProcessLogID=PLG0007182226 ;ProcessLogDetailID=PLG0007182968 ;EnvID=1;RetryCount=1 -->
<ns0:X12_00501_837_P xmlns:ns0="http://schemas.microsoft.com/BizTalk/EDI/X12/2006">
<ns0:TS837_2000A_Loop xmlns:ns0="http://schemas.microsoft.com/BizTalk/EDI/X12/2006">
<ns0:TS837_2000B_Loop xmlns:ns0="http://schemas.microsoft.com/BizTalk/EDI/X12/2006">
<ns0:TS837_2300_Loop xmlns:ns0="http://schemas.microsoft.com/BizTalk/EDI/X12/2006">
<ns0:TS837_2400_Loop>
<ns0:LX_ServiceLineNumber>
<LX01_AssignedNumber>1</LX01_AssignedNumber>
</ns0:LX_ServiceLineNumber>
<ns0:SV1_ProfessionalService>
<ns0:C003_CompositeMedicalProcedureIdentifier>
<C00301_ProductorServiceIDQualifier>HC</C00301_ProductorServiceIDQualifier>
<C00302_ProcedureCode>99203</C00302_ProcedureCode>
<C00303_ProcedureModifier>25</C00303_ProcedureModifier>
<C00307_Description>NO DESCRIPTION</C00307_Description>
</ns0:C003_CompositeMedicalProcedureIdentifier>
<SV102_LineItemChargeAmount>167.82</SV102_LineItemChargeAmount>
<SV103_UnitorBasisforMeasurementCode>UN</SV103_UnitorBasisforMeasurementCode>
<SV104_ServiceUnitCount>1</SV104_ServiceUnitCount>
<ns0:C004_CompositeDiagnosisCodePointer>
<C00401_DiagnosisCodePointer>1</C00401_DiagnosisCodePointer>
</ns0:C004_CompositeDiagnosisCodePointer>
</ns0:SV1_ProfessionalService>
<ns0:DTP_SubLoop_2>
<ns0:DTP_Date_ServiceDate>
<DTP01_DateTimeQualifier>472</DTP01_DateTimeQualifier>
<DTP02_DateTimePeriodFormatQualifier>RD8</DTP02_DateTimePeriodFormatQualifier>
<DTP03_ServiceDate>20160627-20160627</DTP03_ServiceDate>
</ns0:DTP_Date_ServiceDate>
</ns0:DTP_SubLoop_2>
</ns0:TS837_2400_Loop>
<ns0:TS837_2400_Loop>
<ns0:LX_ServiceLineNumber>
<LX01_AssignedNumber>2</LX01_AssignedNumber>
</ns0:LX_ServiceLineNumber>
<ns0:SV1_ProfessionalService>
<ns0:C003_CompositeMedicalProcedureIdentifier>
<C00301_ProductorServiceIDQualifier>HC</C00301_ProductorServiceIDQualifier>
<C00302_ProcedureCode>96372</C00302_ProcedureCode>
<C00307_Description>NO DESCRIPTION</C00307_Description>
</ns0:C003_CompositeMedicalProcedureIdentifier>
<SV102_LineItemChargeAmount>82.56</SV102_LineItemChargeAmount>
<SV103_UnitorBasisforMeasurementCode>UN</SV103_UnitorBasisforMeasurementCode>
<SV104_ServiceUnitCount>2</SV104_ServiceUnitCount>
<ns0:C004_CompositeDiagnosisCodePointer>
<C00401_DiagnosisCodePointer>2</C00401_DiagnosisCodePointer>
</ns0:C004_CompositeDiagnosisCodePointer>
</ns0:SV1_ProfessionalService>
<ns0:DTP_SubLoop_2>
<ns0:DTP_Date_ServiceDate>
<DTP01_DateTimeQualifier>472</DTP01_DateTimeQualifier>
<DTP02_DateTimePeriodFormatQualifier>RD8</DTP02_DateTimePeriodFormatQualifier>
<DTP03_ServiceDate>20160627-20160627</DTP03_ServiceDate>
</ns0:DTP_Date_ServiceDate>
</ns0:DTP_SubLoop_2>
</ns0:TS837_2400_Loop>
</ns0:TS837_2300_Loop>
</ns0:TS837_2000B_Loop>
</ns0:TS837_2000A_Loop>
</ns0:X12_00501_837_P>
</TransactionSet>
</ns1:X12EnrichedMessage>'
IF OBJECT_ID(N'tempdb..#CLAIM_XML', N'U') IS NOT NULL
DROP TABLE #CLAIM_XML;
CREATE TABLE #CLAIM_XML (
CLAIM_SOURCE_ID VARCHAR(20) NOT NULL
,RAW_XML XML NOT NULL
,CLAIM_FORM_TYPE CHAR(1) NOT NULL
,CREATED_DATE DATE NOT NULL
,CONSTRAINT CLAIM_XML_PK PRIMARY KEY (CLAIM_SOURCE_ID)
);
CREATE PRIMARY XML INDEX CLAIM_XML_RAW_XML_IDX
ON #CLAIM_XML (RAW_XML);
INSERT INTO #CLAIM_XML
([CLAIM_SOURCE_ID]
,[RAW_XML]
,[CLAIM_FORM_TYPE]
,[CREATED_DATE])
VALUES('16202E123456'
,#XML
,'H'
,CONVERT(DATE, DATEADD(DAY, -1, GETDATE())));
WITH XMLNAMESPACES ('http://schemas.microsoft.com/BizTalk/EDI/EDIFACT/2006/EnrichedMessageXML' AS ns1
,'http://schemas.microsoft.com/BizTalk/EDI/X12/2006' AS ns0)
SELECT [CX].[CLAIM_SOURCE_ID]
,[ITEM_NUMBER] = LineNumber.ref.value('text()[1]', 'int')
,[HCPCS_LINE_CODE] = [CX].[RAW_XML].value('(/ns1:X12EnrichedMessage/TransactionSet/ns0:X12_00501_837_P/ns0:TS837_2000A_Loop/ns0:TS837_2000B_Loop/ns0:TS837_2300_Loop/ns0:TS837_2400_Loop/ns0:SV1_ProfessionalService/ns0:C003_CompositeMedicalProcedureIdentifier/C00302_ProcedureCode)[1]','varchar(100)')
FROM #CLAIM_XML AS [CX]
CROSS APPLY [CX].[RAW_XML].nodes('/ns1:X12EnrichedMessage/TransactionSet/ns0:X12_00501_837_P/ns0:TS837_2000A_Loop/ns0:TS837_2000B_Loop/ns0:TS837_2300_Loop/ns0:TS837_2400_Loop/ns0:LX_ServiceLineNumber/*') LineNumber(ref)
WHERE [CX].[CLAIM_FORM_TYPE] = 'H'
AND [CX].[CREATED_DATE] = CONVERT(DATE, DATEADD(DAY, -1, GETDATE()));

Use multiple CROSS APPLYs to access the different parts of the XML, like this:
;WITH XMLNAMESPACES ('http://schemas.microsoft.com/BizTalk/EDI/EDIFACT/2006/EnrichedMessageXML' AS ns1
,'http://schemas.microsoft.com/BizTalk/EDI/X12/2006' AS ns0)
SELECT
c.[CLAIM_SOURCE_ID],
sln.c.value('(LX01_AssignedNumber/text())[1]', 'INT') AS [ITEM_NUMBER],
ps.c.value('(ns0:C003_CompositeMedicalProcedureIdentifier/C00302_ProcedureCode/text())[1]', 'INT') AS [HCPCS_LINE_CODE]
FROM #CLAIM_XML c
CROSS APPLY c.[RAW_XML].nodes('/ns1:X12EnrichedMessage/TransactionSet/ns0:X12_00501_837_P/ns0:TS837_2000A_Loop/ns0:TS837_2000B_Loop/ns0:TS837_2300_Loop/ns0:TS837_2400_Loop') l(c)
CROSS APPLY l.c.nodes('ns0:LX_ServiceLineNumber') sln(c)
CROSS APPLY l.c.nodes('ns0:SV1_ProfessionalService') ps(c)

No need for multiple CROSS APPLY with .nodes(). As the values you want to read are single occurance within their tree you can address them directly:
;WITH XMLNAMESPACES ('http://schemas.microsoft.com/BizTalk/EDI/EDIFACT/2006/EnrichedMessageXML' AS ns1
,'http://schemas.microsoft.com/BizTalk/EDI/X12/2006' AS ns0)
SELECT
loop2400.value('(ns0:LX_ServiceLineNumber/LX01_AssignedNumber)[1]', 'INT') AS [ITEM_NUMBER],
loop2400.value('(ns0:SV1_ProfessionalService/ns0:C003_CompositeMedicalProcedureIdentifier/C00302_ProcedureCode)[1]', 'INT') AS [HCPCS_LINE_CODE]
FROM #xml.nodes('/ns1:X12EnrichedMessage/TransactionSet/ns0:X12_00501_837_P/ns0:TS837_2000A_Loop/ns0:TS837_2000B_Loop/ns0:TS837_2300_Loop/ns0:TS837_2400_Loop') A(loop2400)
The lazy approach works too, but - in general - it's good advise to be as specific as possible...
SELECT
loop2400.value('(*//LX01_AssignedNumber)[1]', 'INT') AS [ITEM_NUMBER],
loop2400.value('(*//C00302_ProcedureCode)[1]', 'INT') AS [HCPCS_LINE_CODE]
FROM #xml.nodes('//*:TS837_2400_Loop') A(loop2400)

Related

extracts value from xml nodes

I am trying to extracts some values and colonnes from xml nodes but it
is working . this is my code
Drop table #TableXML
CREATE TABLE #TableXML(Col1 int primary key, Col2 xml)
Insert into #TableXML values ( 1,
'<CookedUP>
<Evenement Calcul="16">
<Cookie xmlns="http://services.ariel.morneausobeco.com/2007/02" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<AlternateOptionTypeCodes />
<Cash>0</Cash>
<CashInterest>0</CashInterest>
<CashSource>Undefined</CashSource>
<Code>A</Code>
<SmallAmount>0</SmallAmount>
<SmallAmountType>Undefined</SmallAmountType>
</Cookie>
</Evenement>
</CookedUP> '
)
SELECT b.Col1,
x.XmlCol.value('(Cookie/SmallAmount)[1]','VARCHAR(100)') AS SmallAmount,
x.XmlCol.value('(Cookie/cash)[1]','VARCHAR(100)') AS cash
FROM #TableXML b
CROSS APPLY b.Col2.nodes('/CookedUP/Evenement') x(XmlCol)
when i ran this query , i am getting null values.
Your node Cookie has a namespace, so you need to declare that and and use it as part of your path (as it isn't the default namespace). Also, you had cash instead of Cash (xQuery is case sensitive). Thus you get:
WITH XMLNAMESPACES ('http://services.ariel.morneausobeco.com/2007/02' AS ns)
SELECT b.Col1,
x.XmlCol.value('(ns:Cookie/ns:SmallAmount/text())[1]', 'int') AS SmallAmount,
x.XmlCol.value('(ns:Cookie/ns:Cash/text())[1]', 'int') AS Cash
FROM #TableXML b
CROSS APPLY b.Col2.nodes('CookedUP/Evenement') x(XmlCol);
I also changed the datatype to int (this may not be the correct datatype, you might want decimal), as the data is clearly numerical and added /text() to the values (I can't remember the exact reason, but the use of /text() has a performance benefit).

Display a String after specific character

Consider A string has multiple dots but I want to read and display from 5th dot(.) to end of the string.Any single select query can you suggest.
Eg:
I/P
We.are.inserting.a.lot.of.records by using SSIS Package.even.the.records are.not committed.
o/P
of.records by using SSIS Package.even.the.records are.not committed.
Using CHARINDEX, one method:
DECLARE #String varchar(500);
SET #String = 'We.are.inserting.a.lot.of.records by using SSIS Package.even.the.records are.not committed.';
SELECT STUFF(#string, 1, CI5.CI,'')
FROM (VALUES(CHARINDEX('.',#String))) CI1(CI)
CROSS APPLY (VALUES(CHARINDEX('.',#String, CI1.CI+1))) CI2(CI)
CROSS APPLY (VALUES(CHARINDEX('.',#String, CI2.CI+1))) CI3(CI)
CROSS APPLY (VALUES(CHARINDEX('.',#String, CI3.CI+1))) CI4(CI)
CROSS APPLY (VALUES(CHARINDEX('.',#String, CI4.CI+1))) CI5(CI);
Returns: 'of.records by using SSIS Package.even.the.records are.not committed.'
Nesting the CHARINDEX:
SELECT
STUFF(val,1, charindex('.',val,charindex('.',val,charindex('.',val,charindex('.',
val,charindex('.',val)+1)+1)+1)+1), '')
FROM (values('.2.3.4.5.6.7'),('2.3.4.5.6.7'),('abc')) x(val)
This will return the whole string, when the string doesn't contain 5 dots.
You can call a recursice CTE for rescue:
DECLARE #yourString NVARCHAR(MAX)='We.are.inserting.a.lot.of.records by using SSIS Package.even.the.records are.not committed.';
DECLARE #CountDots INT=5;
WITH recCTE AS
(
SELECT #yourString AS Original
,CHARINDEX('.',#yourString) AS PosDot
,1 AS DotCount
UNION ALL
SELECT r.Original
,CHARINDEX('.',#yourString,r.PosDot+1)
,r.DotCount+1
FROM recCTE AS r
WHERE r.DotCount<#CountDots
)
SELECT SUBSTRING(#yourString,(SELECT MAX(PosDot) FROM recCTE)+1,LEN(#yourString))
One advantage is that you can define the count of dots dynamically. Another advantage is that you can fully inline this to any query, VIEW or iTVF.
UPDATE: Set-based approach
DECLARE #yourStringTable TABLE(ID INT IDENTITY,SomeString NVARCHAR(MAX));
INSERT INTO #yourStringTable VALUES
('We.are.inserting.a.lot.of.records by using SSIS Package.even.the.records are.not committed.')
,('1.2.3.4.5.6.7.8');
DECLARE #CountDots INT=5;
WITH recCTE AS
(
SELECT ID
,SomeString AS Original
,CHARINDEX('.',SomeString) AS PosDot
,1 AS DotCount
FROM #yourStringTable
UNION ALL
SELECT r.ID
,r.Original
,CHARINDEX('.',r.Original,r.PosDot+1)
,r.DotCount+1
FROM recCTE AS r
WHERE r.DotCount<#CountDots
)
SELECT ID
,Original
,SUBSTRING(Original,(SELECT MAX(x.posDot) FROM recCTE AS x WHERE x.ID=recCTE.ID)+1,LEN(Original))
FROM recCTE
WHERE PosDot=(SELECT MAX(x.posDot) FROM recCTE AS x WHERE x.ID=recCTE.ID)
For the said string values only patindex() function would be sufficient to read string after few dot(.)s with substring() function
select
substring(I/P, patindex('%[.A-Z].[A-Z][.A-Z].[A-Z]%', I/P)+2, LEN(I/P)) [O/P]
from table

XML Parsing in TSQL gives invalid column error?

I am trying to parse a simple XML file. As soon as I un comment the insert statement it gives me invalid column errors.
drop table #TEMP
drop table #TEMP_T
declare #XMl_DATA AS XML
set #XMl_DATA =
'<DocumentElement>
<Att_Table>
<L_ATTR_CD>GAS_FLOW_START_DATE</L_ATTR_CD>
<L_ATTR_DESC>GAS FLOW START DATE</L_ATTR_DESC>
<L_ATTR_VALUE>01/01/2012</L_ATTR_VALUE>
<R_ATTR_CD>EX_CTRCT_CO_ID</R_ATTR_CD>
<R_ATTR_DESC>EXCLUDE GID(S)</R_ATTR_DESC>
<R_ATTR_VALUE />
</Att_Table>
<Att_Table>
<L_ATTR_CD>GAS_FLOW_END_DATE</L_ATTR_CD>
<L_ATTR_DESC>GAS FLOW END DATE</L_ATTR_DESC>
<L_ATTR_VALUE>01/31/2012</L_ATTR_VALUE>
<R_ATTR_CD>EX_CTRCT_NBR</R_ATTR_CD>
<R_ATTR_DESC>EXCLUDE CONTRACT NUMBER(S)</R_ATTR_DESC>
<R_ATTR_VALUE />
</Att_Table>
<Att_Table>
<L_ATTR_CD>CTRCT_CO_ID</L_ATTR_CD>
<L_ATTR_DESC>GID(S)</L_ATTR_DESC>
<L_ATTR_VALUE />
<R_ATTR_CD>EX_RATE_CMPNT_CD</R_ATTR_CD>
<R_ATTR_DESC>EXCLUDE RATE COMPONENT CODE(S)</R_ATTR_DESC>
<R_ATTR_VALUE />
</Att_Table>
<Att_Table>
<L_ATTR_CD>CTRCT_NBR</L_ATTR_CD>
<L_ATTR_DESC>DART STYLE CONTRACT NUMBER(S)</L_ATTR_DESC>
<L_ATTR_VALUE />
<R_ATTR_CD>EX_PT_ID_NBR</R_ATTR_CD>
<R_ATTR_DESC>EXCLIDE POINT ID NUMBER(S)</R_ATTR_DESC>
<R_ATTR_VALUE />
</Att_Table>
</DocumentElement>'
Temp table:
CREATE TABLE #TEMP_T
(
ID INT IDENTITY(1,1),
ATT_CD VARCHAR(50),
ATT_CD_VALUE VARCHAR(1000)
)
SELECT
cast(Colx.query('data(L_ATTR_CD)') as varchar(max))as L_ATTR_CD,
cast(Colx.query('data(L_ATTR_VALUE)') as varchar(max))as L_ATTR_CD_VALUE,
cast(Colx.query('data(R_ATTR_CD)') as varchar(max)) as R_ATTR_CD,
cast(Colx.query('data(R_ATTR_VALUE)') as varchar(max))as R_ATTR_CD_VALUE
INTO #TEMP
FROM #XMl_DATA.nodes('DocumentElement/Att_Table') AS T(Colx)
--INSERT INTO #TEMP_T(ATT_CD,ATT_CD_VALUE)
--SELECT LTRIM(RTRIM(L_ATT_CD)),LTRIM(RTRIM(L_ATT_CD_VALUE))
--FROM #TEMP
--WHERE L_ATT_CD_VALUE <> 'NO_DATA'
--INSERT INTO #TEMP_T(ATT_CD,ATT_CD_VALUE)
--SELECT LTRIM(RTRIM(R_ATT_CD)),LTRIM(RTRIM(R_ATT_CD_VALUE))
--FROM #TEMP
--WHERE R_ATT_CD_VALUE <>'NO_DATA'
Output:
select * from #TEMP_T
select * from #TEMP
Sometimes you use things like L_ATTR and R_ATTR, and other times you use things like L_ATT and R_ATT (with no Rs). Pick one and stick to it.
The error message mentioning "invalid column" was trying to tell you this: the columns you try to select from #TEMP are "invalid" because you aren't using the same names as when you created #TEMP.
Why don't you just do something like this?
-- define your XML structure and create the #TEMP_T table
;WITH ParsedData AS
(
SELECT
Colx.value('(L_ATTR_CD)[1]', 'varchar(50)') as L_ATTR_CD,
Colx.value('(L_ATTR_VALUE)[1]', 'varchar(50)') as L_ATTR_CD_VALUE,
Colx.value('(R_ATTR_CD)[1]', 'varchar(50)') as R_ATTR_CD,
Colx.value('(R_ATTR_VALUE)[1]', 'varchar(50)') as R_ATTR_CD_VALUE
FROM
#XMl_DATA.nodes('DocumentElement/Att_Table') AS T(Colx)
)
INSERT INTO #temp_T(ATT_CD, ATT_CD_VALUE)
SELECT L_ATTR_CD, L_ATTR_CD_VALUE
FROM parseddata
UNION
SELECT R_ATTR_CD, R_ATTR_CD_VALUE
FROM parseddata
This just parses the XML (much simpler than your approach, too!) and then inserts both the (L_ATTR_CD, L_ATTR_CD_VALUE) as well as the (R_ATTR_CD, R_ATTR_CD_VALUE) pairs into the temp table in a single go.

SQL Server from XML parameter to table - working with optional child nodes

On SQL Server 2008 R2, I am trying to read XML value as table.
So far, I am here :
DECLARE #XMLValue AS XML;
SET #XMLValue = '<SearchQuery>
<ResortID>1453</ResortID>
<CheckInDate>2011-10-27</CheckInDate>
<CheckOutDate>2011-11-04</CheckOutDate>
<Room>
<NumberOfADT>2</NumberOfADT>
<CHD>
<Age>10</Age>
</CHD>
<CHD>
<Age>12</Age>
</CHD>
</Room>
<Room>
<NumberOfADT>1</NumberOfADT>
</Room>
<Room>
<NumberOfADT>1</NumberOfADT>
<CHD>
<Age>7</Age>
</CHD>
</Room>
</SearchQuery>';
SELECT
Room.value('(NumberOfADT)[1]', 'INT') AS NumberOfADT
FROM #XMLValue.nodes('/SearchQuery/Room') AS SearchQuery(Room);
As you can see, Room node sometimes get CHD child nodes but sometimes don't.
Assume that I am getting this XML value as a Stored Procedure parameter. So, I need to work with the values in order to query my database tables. What would be the best way to read this XML parameter entirely?
EDIT
I think I need to express what I am expecting in return here. The below script code is for the table what I need here :
DECLARE #table AS TABLE(
ResorrtID INT,
CheckInDate DATE,
CheckOutDate DATE,
NumberOfADT INT,
CHDCount INT,
CHDAges NVARCHAR(100)
);
For the XML value I have provide above, the below Insert t-sql is suitable :
INSERT INTO #table VALUES(1453, '2011-10-27', '2011-11-04', 2, 2, '10;12');
INSERT INTO #table VALUES(1453, '2011-10-27', '2011-11-04', 1, 0, NULL);
INSERT INTO #table VALUES(1453, '2011-10-27', '2011-11-04', 1, 1, '7');
CHDCount is for the number of CHD nodes under Room node. Also, how many Room node I have, that many table row I am having here.
As for how it should look, see the below picture :
Actually, this code is for hotel reservation search query. So, I need
to work with these values I got from XML parameter to query my tables
and return available rooms. I am telling this because maybe it helps
you guys to see it through. I am not looking for a complete code for
room reservation system. That would be so selfish.
select S.X.value('ResortID[1]', 'int') as ResortID,
S.X.value('CheckInDate[1]', 'date') as CheckInDate,
S.X.value('CheckOutDate[1]', 'date') as CheckOutDate,
R.X.value('NumberOfADT[1]', 'int') as NumberOfADT,
R.X.value('count(CHD)', 'int') as CHDCount,
stuff((select ';'+C.X.value('.', 'varchar(3)')
from R.X.nodes('CHD/Age') as C(X)
for xml path('')), 1, 1, '') as CHDAges
from #XMLValue.nodes('/SearchQuery') as S(X)
cross apply S.X.nodes('Room') as R(X)
This should get you close:
SELECT ResortID = #xmlvalue.value('(//ResortID)[1]', 'int')
, CheckInDate = #xmlvalue.value('(//CheckInDate)[1]', 'date')
, CheckOutDate = #xmlvalue.value('(//CheckOutDate)[1]', 'date')
, NumberOfAdt = Room.value('(NumberOfADT)[1]', 'INT')
, CHDCount = Room.value('count(./CHD)', 'int')
, CHDAges = Room.query('for $c in ./CHD
return concat(($c/Age)[1], ";")').value('(.)[1]',
'varchar(100)')
FROM #XMLValue.nodes('/SearchQuery/Room') AS SearchQuery ( Room ) ;

Update data in the table using XML string

I have table which contains columns like
SiteID (identity_Col)
SiteName
POrderID
Location
Address
Cluster
VenderName
I want to use xml string to insert/update/delete data in this table. Apart from this column, XML string contains one more column viz. RowInfo. This column will have values like "Unchanged","Update","New","Delete". Based on this values the rows in the table should be inserted,updated,deleted.
My XML string is as below:
<NewDataSet>
<DataTable>
<SiteID>2</SiteID>
<SiteName>NIZAMPURA</SiteName>
<POrderID>7</POrderID>
<Location>NIZAMPURA</Location>
<SiteAddress>Vadodara</SiteAddress>
<Cluster>002</Cluster>
<SubVendorName>Test Vender-1</SubVendorName>
<RowInfo>UNCHANGED</RowInfo>
</DataTable>
<DataTable>
<SiteID>16</SiteID>
<SiteName>Site-1</SiteName>
<POrderID>7</POrderID>
<Location>Alkapuri</Location>
<SiteAddress>test</SiteAddress>
<Cluster>Test Cluster</Cluster>
<SubVendorName>Test Vender12</SubVendorName>
<RowInfo>UNCHANGED</RowInfo>
</DataTable>
<DataTable>
<SiteID>17</SiteID>
<SiteName>Site-3</SiteName>
<POrderID>7</POrderID>
<Location>Alkapuri123</Location>
<SiteAddress>test123</SiteAddress>
<Cluster>Test Cluster123</Cluster>
<SubVendorName>Test Vender123</SubVendorName>
<RowInfo>DELETE</RowInfo>
</DataTable>
</NewDataSet>'
This is the code that I have written to insert data in table if RowInfo = "NEW"
IF len(ISNULL(#xmlString, '')) > 0
BEGIN
DECLARE #docHandle1 int = 0;
EXEC sp_xml_preparedocument #docHandle1 OUTPUT, #xmlString
INSERT INTO [SiteTRS] (
[SiteName],
[POrderID],
[Location],
[SiteAddress],
[Cluster],
[SubVendorName])
SELECT SiteName,POrderID,Location,SiteAddress,Cluster,SubVendorName
FROM OPENXML (#docHandle1, '/NewDataSet/DataTable')
WITH (SiteName varchar(50) './SiteName',
POrderID varchar(50) './PorderID',
Location varchar(50) './Location',
SiteAddress varchar(max) './SiteAddress',
Cluster varchar(50) './Cluster',
SubVendorName varchar(50) './SubVendorName',
RowInfo varchar(30) './RowInfo')
WHERE RowInfo='NEW'
But I don't know how to use XML to update/delete records in the table. Please guide
I am novice in the XML so dont have any idea. Please forgive me if I am making something childish.
I would strongly recommend not to use the old, legacy OPENXML stuff anymore - with XML support in SQL Server, it's much easier to use the built-in XPath/XQuery methods.
In your case, I would use a CTE (Common Table Expression) to break up the XML into an "inline" table of rows and columns:
DECLARE #input XML = '<NewDataSet>
<DataTable>
<SiteID>2</SiteID>
<SiteName>NIZAMPURA</SiteName>
<POrderID>7</POrderID>
<Location>NIZAMPURA</Location>
<SiteAddress>Vadodara</SiteAddress>
<Cluster>002</Cluster>
<SubVendorName>Vender-1</SubVendorName>
<RowInfo>UPDATE</RowInfo>
</DataTable>
<DataTable>
<SiteName>Site-1</SiteName>
<POrderID>7</POrderID>
<Location>Alkapuri</Location>
<SiteAddress>test</SiteAddress>
<Cluster>Cluster-1</Cluster>
<SubVendorName>Test Vender</SubVendorName>
<RowInfo>NEW</RowInfo>
</DataTable>
</NewDataSet>'
;WITH XMLData AS
(
SELECT
NDS.DT.value('(SiteID)[1]', 'int') AS 'SiteID',
NDS.DT.value('(SiteName)[1]', 'varchar(50)') AS 'SiteName',
NDS.DT.value('(POrderID)[1]', 'int') AS 'POrderID',
NDS.DT.value('(Location)[1]', 'varchar(100)') AS 'Location',
NDS.DT.value('(SiteAddress)[1]', 'varchar(100)') AS 'SiteAddress',
NDS.DT.value('(Cluster)[1]', 'varchar(100)') AS 'Cluster',
NDS.DT.value('(SubVendorName)[1]', 'varchar(100)') AS 'SubVendorName',
NDS.DT.value('(RowInfo)[1]', 'varchar(20)') AS 'RowInfo'
FROM
#input.nodes('/NewDataSet/DataTable') AS NDS(DT)
)
SELECT *
FROM XMLDATA
This gives you rows and columns which you can work with.
SiteID SiteName POrderID Location SiteAddress Cluster SubVendorName RowInfo
2 NIZAMPURA 7 NIZAMPURA Vadodara 002 Vender-1 UPDATE
NULL Site-1 7 Alkapuri test Cluster-1 Test Vender NEW
Now if you're on SQL Server 2008 or newer, you could combine this with the MERGE command to do your INSERT/UPDATE in a single statement, basically.
If you're on 2005, you will need to either store this information into a temporary table / table variable inside your stored proc, or you need to do the select multiple times; the CTE allows only one single command to follow it.
Update: with this CTE, you can then combine it with a MERGE:
;WITH XmlData AS
(
SELECT
NDS.DT.value('(SiteID)[1]', 'int') AS 'SiteID',
NDS.DT.value('(SiteName)[1]', 'varchar(50)') AS 'SiteName',
NDS.DT.value('(POrderID)[1]', 'int') AS 'POrderID',
NDS.DT.value('(Location)[1]', 'varchar(100)') AS 'Location',
NDS.DT.value('(SiteAddress)[1]', 'varchar(100)') AS 'SiteAddress',
NDS.DT.value('(Cluster)[1]', 'varchar(100)') AS 'Cluster',
NDS.DT.value('(SubVendorName)[1]', 'varchar(100)') AS 'SubVendorName',
NDS.DT.value('(RowInfo)[1]', 'varchar(20)') AS 'RowInfo'
FROM
#input.nodes('/NewDataSet/DataTable') AS NDS(DT)
)
MERGE INTO dbo.SiteTRS t
USING XmlData x ON t.SiteID = x.SiteID
WHEN MATCHED AND x.RowInfo = 'UPDATE'
THEN
UPDATE SET
t.SiteName = x.SiteName,
t.POrderID = x.POrderID,
t.Location = x.Location,
t.SiteAddress = x.SiteAddress,
t.Cluster = x.Cluster,
t.SubVendorName = x.SubVendorName
WHEN MATCHED AND x.RowInfo = 'DELETE'
THEN DELETE
WHEN NOT MATCHED AND x.RowInfo = 'NEW'
THEN
INSERT(SiteID, SiteName, POrderID, Location, SiteAddress, Cluster, SubVendorName)
VALUES(x.SiteID, x.SiteName, x.POrderID, x.Location, x.SiteAddress, x.Cluster, x.SubVendorName)
;
See some more resources:
SQL SERVER – 2008 – Introduction to Merge Statement – One Statement for INSERT, UPDATE, DELETE
Using SQL Server 2008's MERGE statement

Resources