SQL Server and XML Utilization - sql-server

I'm trying to utilize XML with SQL Server. All I'm trying to do is print out all three guests. When I run my code, it only shows the prints the first guest's information, and I need all three guest's information to be printed. What am I doing wrong?
SELECT Guest.GuestID, GuestFirst, GuestLast, CheckinDate, Nights
FROM GUEST
JOIN FOLIO
ON Guest.GuestID = Folio.GuestID
FOR XML RAW
Declare #idoc int
Declare #xmldoc nvarchar(4000)
Set #xmldoc = '
<ROOT>
<GUEST>
<GuestID>4431</GuestID>
<GuestFirst>Lacey</GuestFirst>
<GuestLast>Byington</GuestLast>
<RESERVATIONDETAIL>
<CheckInDate>2016-08-02</CheckInDate>
<Nights>2</Nights>
</RESERVATIONDETAIL>
</GUEST>
<GUEST>
<GuestID>5563</GuestID>
<GuestFirst>Jonathan</GuestFirst>
<GuestLast>Langford</GuestLast>
<RESERVATIONDETAIL>
<CheckInDate>2016-08-05</CheckInDate>
<Nights>2</Nights>
</RESERVATIONDETAIL>
</GUEST>
<GUEST>
<GuestID>6680</GuestID>
<GuestFirst>Tanner</GuestFirst>
<GuestLast>Olson</GuestLast>
<RESERVATIONDETAIL>
<CheckInDate>2015-09-11</CheckInDate>
<Nights>3</Nights>
</RESERVATIONDETAIL>
</GUEST>
</ROOT>'
EXEC sp_xml_preparedocument #idoc OUTPUT, #xmldoc
SELECT * FROM OPENXML (#idoc, '/ROOT', 3)
WITH
(
GuestID smallint 'GUEST/GuestID',
GuestFirst varchar(30) 'GUEST/GuestFirst',
GuestLast varchar(30) 'GUEST/GuestLast',
CheckinDate smalldatetime 'GUEST/RESERVATIONDETAIL/CheckInDate',
Nights tinyint 'GUEST/RESERVATIONDETAIL/Nights'
)
EXEC sp_xml_removedocument #idoc
GO

Instead xml document try it with xquery,
DECLARE #xmldoc XML
Set #xmldoc = '
<ROOT>
<GUEST>
<GuestID>4431</GuestID>
<GuestFirst>Lacey</GuestFirst>
<GuestLast>Byington</GuestLast>
<RESERVATIONDETAIL>
<CheckInDate>2016-08-02</CheckInDate>
<Nights>2</Nights>
</RESERVATIONDETAIL>
</GUEST>
<GUEST>
<GuestID>5563</GuestID>
<GuestFirst>Jonathan</GuestFirst>
<GuestLast>Langford</GuestLast>
<RESERVATIONDETAIL>
<CheckInDate>2016-08-05</CheckInDate>
<Nights>2</Nights>
</RESERVATIONDETAIL>
</GUEST>
<GUEST>
<GuestID>6680</GuestID>
<GuestFirst>Tanner</GuestFirst>
<GuestLast>Olson</GuestLast>
<RESERVATIONDETAIL>
<CheckInDate>2015-09-11</CheckInDate>
<Nights>3</Nights>
</RESERVATIONDETAIL>
</GUEST>
</ROOT>'
SELECT
a.b.value('GuestID[1]','smallint') AS GuestID,
a.b.value('GuestFirst[1]','varchar(30)') AS GuestFirst,
a.b.value('GuestLast[1]','varchar(30)') AS GuestLast,
a.b.value('RESERVATIONDETAIL[1]/CheckInDate[1]','smalldatetime') AS CheckInDate,
a.b.value('RESERVATIONDETAIL[1]/Nights[1]','tinyint') AS Nights
FROM #xmldoc.nodes('ROOT/GUEST') AS a(b)
GO
btw, the select query you have given on the top will not produce the same xml which you have given below.

#Jatin answer is good, you can use xquery. You can also use OPENXML like this:
EXEC sp_xml_preparedocument #idoc OUTPUT, #xmldoc
SELECT * FROM OPENXML (#idoc, '/ROOT/GUEST', 3)
WITH
(
GuestID smallint './GuestID',
GuestFirst varchar(30) './GuestFirst',
GuestLast varchar(30) './GuestLast',
CheckinDate smalldatetime './RESERVATIONDETAIL/CheckInDate',
Nights tinyint './RESERVATIONDETAIL/Nights'
)
EXEC sp_xml_removedocument #idoc

You are almost there. You just need to make this small change:
SELECT * FROM OPENXML (#idoc, '/ROOT/*', 3)
WITH
(
GuestID smallint 'GuestID',
GuestFirst varchar(30) 'GuestFirst',
GuestLast varchar(30) 'GuestLast',
CheckinDate smalldatetime 'RESERVATIONDETAIL/CheckInDate',
Nights tinyint 'RESERVATIONDETAIL/Nights'
)

Related

Apple Health XML to SQL Server

I want to process XML data I've imported from exported Apple Health XML file.
The XML data is stored in an import table and I'm trying to use sp_xml_preparedocument to prepare the document and query the data.
The approach described below worked for another part of the XML file, specifically activity summary. Now I receive the following error:
Msg 6603, Level 16, State 2, Line 23
XML parsing error: NodeTest expected here.
#-->[<--type]
The examples given by Microsoft in their documentation seems to be working on a differently structured data, so not sure how or if I could adapt one of their examples to my needs.
I have tried the following:
DECLARE #XML AS XML;
DECLARE #hDoc AS INT;
SELECT #XML = XMLData FROM [Data].AppleImport;
EXEC sp_xml_preparedocument #hDoc OUTPUT, #XML
SELECT [type],
sourceName,
sourceVersion,
unit,
creationDate,
startDate,
endDate,
[value]
FROM OPENXML(#hDoc, 'HealthData/Record')
WITH
(
[type] NVARCHAR(50) '#[type]',
sourceName NVARCHAR(50) '#sourceName',
sourceVersion NVARCHAR(50) '#sourceVersion',
unit NVARCHAR(50) '#unit',
creationDate NVARCHAR(50) '#creationDate',
startDate NVARCHAR(50) '#startDate',
endDate NVARCHAR(50) '#endDate',
[value] NVARCHAR(50) '#[value]'
)
EXEC sp_xml_removedocument #hDoc;
The XML Data structure (extracted parts for brewity):
<HealthData locale="nb_NO">
<ExportDate value="2020-09-03 12:10:19 +0200"/>
<Me HKCharacteristicTypeIdentifierDateOfBirth="1988-01-01" HKCharacteristicTypeIdentifierBiologicalSex="HKBiologicalSexMale" HKCharacteristicTypeIdentifierBloodType="HKBloodTypeNotSet" HKCharacteristicTypeIdentifierFitzpatrickSkinType="HKFitzpatrickSkinTypeNotSet"/>
<Record type="HKQuantityTypeIdentifierHeight" sourceName="amsten sin iPhone" sourceVersion="13.0" unit="cm" creationDate="2019-09-23 15:19:48 +0200" startDate="2019-09-23 15:19:48 +0200" endDate="2019-09-23 15:19:48 +0200" value="188"/>
<Record type="HKQuantityTypeIdentifierHeight" sourceName="Helse" sourceVersion="11.4.1" unit="cm" creationDate="2018-07-31 21:42:50 +0200" startDate="2018-07-31 21:42:50 +0200" endDate="2018-07-31 21:42:50 +0200" value="188"/>
<MetadataEntry key="HKWasUserEntered" value="1"/>
</Record>
<Record type="HKQuantityTypeIdentifierHeartRate" sourceName="amsten sin Apple Watch" sourceVersion="5.3.1" device="<<HKDevice: 0x2834d03c0>, name:Apple Watch, manufacturer:Apple Inc., model:Watch, hardware:Watch4,4, software:5.3.1>" unit="count/min" creationDate="2019-09-15 06:38:32 +0200" startDate="2019-09-15 06:30:08 +0200" endDate="2019-09-15 06:30:08 +0200" value="49">
<MetadataEntry key="HKMetadataKeyHeartRateMotionContext" value="1"/>
</Record>
</HealthData>
Any input on how to proceede or good reading materials are most appreciated.
When using valid XML also try using the following OPENXML statement:
SELECT [type],
sourceName,
sourceVersion,
unit,
creationDate,
startDate,
endDate,
[value]
FROM OPENXML(#hDoc, 'HealthData/Record')
WITH
(
[type] NVARCHAR(50) '#type',
sourceName NVARCHAR(50) '#sourceName',
sourceVersion NVARCHAR(50) '#sourceVersion',
unit NVARCHAR(50) '#unit',
creationDate NVARCHAR(50) '#creationDate',
startDate NVARCHAR(50) '#startDate',
endDate NVARCHAR(50) '#endDate',
[value] NVARCHAR(50) '#value'
)
Note that '#[type]' and '#[value]' have changed to '#type' and '#value'.

How to parse xml data in sql server dynamically

I am trying to get a node value of 'customer' but I need to pick this node dynamically and get the value of it because I am trying to get primary key node value and I will get that primary key from other table for now I have set the variable #primary ='CUSTOMER' but I am getting error like
The data types varchar and xml are incompatible in the add operator.
I tried to use cast but no use. Can anyone please help me on this
declare #var xml,
#var1 varchar(max),
#var2 varchar(max),
#var3 varchar(max),
#var4 varchar(max),
#var5 varchar(max),
#primary varchar(max);
set #primary='CUSTOMER';
set #var='<RequestData>
<CREATED_BY>nachagon</CREATED_BY>
<CUSTOMER_TYPE />
<modalid>editmodgrid_iBase_VW_Customers</modalid>
<Input_Date_From>31-Dec-2007 07:30:00 PM</Input_Date_From>
<Timestamp>26-Mar-2019 04:02:01 PM</Timestamp>
<UPDATED_ON />
<USER_SELECTED_TIMEZONE>Venezuela Standard Time</USER_SELECTED_TIMEZONE>
<NAME>Kevin Good</NAME>
<CITY>Stewartsville</CITY>
<COUNTRY>US</COUNTRY>
<Input_Date_To>29-Jun-2008 07:30:00 PM</Input_Date_To>
<UPDATED_BY>nachagon</UPDATED_BY>
<CREATED_ON>28-Mar-2019 11:57:46 AM</CREATED_ON>
<CUSTOMER>0000000233</CUSTOMER>
<oper>edit</oper>
<id>jqg1</id>
<tablename>iBase_VW_Customers</tablename>
<moduleId>Customers</moduleId>
<LOGGED_IN_USER_ID>11</LOGGED_IN_USER_ID>
</RequestData>'
select #var1=coalesce(#var1 + ',','')+NodeName , #var2=coalesce(#var2 +',','')+NodeValue
from (select NodeName,NodeValue from(SELECT NodeName = C.value('local-name(.)', 'varchar(50)'),
NodeValue = C.value('(.)[1]', 'varchar(50)') FROM #var.nodes('/RequestData/*') AS T(C))t2 WHERE t2.NodeName NOT IN ('CREATED_BY', 'CREATED_ON', 'id','LOGGED_IN_USER_ID','modalid', 'moduleId','oper','tablename','UPDATED_BY','UPDATED_ON','USER_SELECTED_TIMEZONE'))t
select #var1,#var2
SET #var5= 'select '+#var+'.value(''(RequestData/'+#primary+')[1]'',''varchar(max)'')'
exec (#var5)
print(#var5)
This example might help
declare #primary nvarchar(max) = 'CUSTOMER';
declare #var xml =
'<RequestData>
<CREATED_BY>nachagon</CREATED_BY>
<CUSTOMER_TYPE />
<modalid>editmodgrid_iBase_VW_Customers</modalid>
<Input_Date_From>31-Dec-2007 07:30:00 PM</Input_Date_From>
<Timestamp>26-Mar-2019 04:02:01 PM</Timestamp>
<UPDATED_ON />
<USER_SELECTED_TIMEZONE>Venezuela Standard Time</USER_SELECTED_TIMEZONE>
<NAME>Kevin Good</NAME>
<CITY>Stewartsville</CITY>
<COUNTRY>US</COUNTRY>
<Input_Date_To>29-Jun-2008 07:30:00 PM</Input_Date_To>
<UPDATED_BY>nachagon</UPDATED_BY>
<CREATED_ON>28-Mar-2019 11:57:46 AM</CREATED_ON>
<CUSTOMER>0000000233</CUSTOMER>
<oper>edit</oper>
<id>jqg1</id>
<tablename>iBase_VW_Customers</tablename>
<moduleId>Customers</moduleId>
<LOGGED_IN_USER_ID>11</LOGGED_IN_USER_ID>
</RequestData>'
DECLARE #cmd NVARCHAR(MAX) = 'SELECT #xml.value(''(/RequestData/'+#primary+')[1]'', ''nvarchar(max)'' )'
EXECUTE sp_executesql #cmd, N'#xml XML', #xml = #var
It's not 100% bullet proof but it might help you achieve your goal.
Also, if you know the datatype I recommend to pass this also to the dynamic query.

USE Open XML to extract the CDATA

I have xml which has the data embedded in CDATA. I would like to extract the info in different fields. But not able to do it.
<Item_Response Format="text/xml">
<![CDATA[ <Item sequence="1" type="item" itemId="999999"
itemVersion="2012-04-07T13:43:27">
<response><bubbleinput answered="y" input_id="bubbleinput1">
<bubble id="bubble1"/>
</bubbleinput></response></Item> ]]>
</Item_Response>
You can extract CDATA value with XPath. Then use openxml on extracted value.
declare #xml xml = '<Item_Response Format="text/xml"><![CDATA[ <Item sequence="1" type="item" itemId="999999" itemVersion="2012-04-07T13:43:27"><response><bubbleinput answered="y" input_id="bubbleinput1"><bubble id="bubble1"/></bubbleinput></response></Item> ]]></Item_Response>'
-- openxml
declare
#idoc int,
#qxml xml = cast(#xml.value('(/Item_Response)[1]', 'nvarchar(max)') as xml)
exec sp_xml_preparedocument #idoc output, #qxml
select
*
from
openxml(#idoc, '/Item', 0) with (
sequence int '#sequence',
bubbleinput nvarchar(1) './response/bubbleinput/#answered'
) as XMLData
exec sp_xml_removedocument #idoc

SELECT node text values from xml document in TSQL OPENXML

I have a xml document I want to use to update values in a stored procedure. I can process the XML using OPENXML, but I'm confused about extracting the values I want. Each row in the xml is a product record and I want to create a variable for each property. Cell0 is the ID, Cell2 description etc
DECLARE #idoc int
DECLARE #doc varchar(1000)
SET #doc ='
<products>
<rows>
<row>
<cell>1</cell>
<cell>BALSAMO DERMOSCENT</cell>
<cell>1.00</cell>
<cell>0.00</cell>
<cell>18.00</cell>
<cell>18.00</cell>
<cell>8.00</cell>
<cell>427</cell>
<cell>No</cell>
</row>
<row>
<cell>2</cell>
<cell>BAYTRIL 150 MG 1 CPDO</cell>
<cell>1.00</cell>
<cell>0.00</cell>
<cell>3.50</cell>
<cell>3.50</cell>
<cell>8.00</cell>
<cell>57</cell>
<cell>No</cell>
</row>
</rows>
</products>'
--Create an internal representation of the XML document.
EXEC sp_xml_preparedocument #idoc OUTPUT, #doc
-- Execute a SELECT statement that uses the OPENXML rowset provider.
SELECT *
FROM OPENXML (#idoc, '/products/rows/row/cell',1)
with (Col1 varchar(29) 'text()')
Running the above query returns 1 record for each CELL in the xml. I want to be able to return 1 record per row with different columns for each cell, something like:-
Prod Description Qty
---------- -------------------- --------
1 BALSAMO DERMOSCENT 1.00
2 BAYTRIL 150 MG 1 CPDO 1.00
I'm using MSSQL 2008
I've come up with the following which does the job for me
DECLARE #idoc int
DECLARE #doc varchar(1000)
SET #doc ='
<products>
<rows>
<row>
<cell>1</cell>
<cell>BALSAMO DERMOSCENT</cell>
<cell>1.00</cell>
<cell>0.00</cell>
<cell>18.00</cell>
<cell>18.00</cell>
<cell>8.00</cell>
<cell>427</cell>
<cell>No</cell>
</row>
<row>
<cell>2</cell>
<cell>BAYTRIL 150 MG 1 CPDO</cell>
<cell>1.00</cell>
<cell>0.00</cell>
<cell>3.50</cell>
<cell>3.50</cell>
<cell>8.00</cell>
<cell>57</cell>
<cell>No</cell>
</row>
</rows>
</products>'
--Create an internal representation of the XML document.
EXEC sp_xml_preparedocument #idoc OUTPUT, #doc
-- Execute a SELECT statement that uses the OPENXML rowset provider.
SELECT *
FROM OPENXML (#idoc, '/products/rows/row',1)
with (pLineNo int 'cell[1]/text()',
pDesc varchar(50) 'cell[2]/text()',
pQty float 'cell[3]/text()',
pCost float 'cell[4]/text()',
pPvp float 'cell[5]/text()',
pTotal float 'cell[6]/text()',
pIva float 'cell[7]/text()',
pId int 'cell[8]/text()',
pnoFact varchar(5) 'cell[9]/text()')
Why use openxml on sql server 2008?
This is a better option (I used varchar(max) as the datatype, but enter whatever is applicable). Note you have to declare the variable as xml, not varchar.
SELECT
Row.Item.value('data(cell[1])', 'varchar(max)') As Prod,
Row.Item.value('data(cell[2])', 'varchar(max)') As Description,
Row.Item.value('data(cell[3])', 'varchar(max)') As Qty
FROM
#doc.nodes('//row') AS Row(Item)
Note: If you're doing this is a stored procedure you may have to include the following before the select statement:
SET ARITHABORT ON -- required for .nodes
If you must use openxml, at least clean it up when you're done:
exec sp_xml_removedocument #idoc

How to parse xml in sql server to process NULL value in DateTime DataType

I have created a sample query in sql server to parse data from xml and to display it right now.
Although I will be inserting this data in my table but before that I am facing a simple problem.
I want to insert NULL in datetime field ADDED_DATE="NULL" as shown in xml given below. But when I executes this query. It gives me error
Conversion failed when converting datetime from character string.
What mistake am i doing. Please highlight my mistake.
declare #xml varchar(1000)
set #xml= '
<ROOT>
<TX_MAP FK_GUEST_ID="1" FK_CATEGORY_ID="2" ATTRIBUTE="Test" DESCRIPTION="TestDesc" IS_ACTIVE="1" ADDED_BY="NULL" ADDED_DATE="NULL" MODIFIED_BY="NULL" MODIFIED_DATE="NULL"></TX_MAP>
<TX_MAP FK_GUEST_ID="2" FK_CATEGORY_ID="1" ATTRIBUTE="Test2" DESCRIPTION="TestDesc2" IS_ACTIVE="1" ADDED_BY="NULL" ADDED_DATE="NULL" MODIFIED_BY="NULL" MODIFIED_DATE="NULL"></TX_MAP>
</ROOT> '
declare #handle int
exec sp_xml_preparedocument #handle output, #xml
select * from OPENXML(#handle,'/ROOT/TX_MAP',1)
with
(
FK_GUEST_ID INT
,FK_CATEGORY_ID VARCHAR(10)
,ATTRIBUTE VARCHAR(100)
,[DESCRIPTION] VARCHAR(100)
,IS_ACTIVE VARCHAR(10)
,ADDED_BY VARCHAR(100)
,ADDED_DATE DATETIME NULL
,MODIFIED_BY VARCHAR(100)
,MODIFIED_DATE DATETIME NULL
)
I am using Sql Server 2005.
After googling an hour, I got answer to my question and would like to share with you all so that for future users it become easy.
declare #xml varchar(1000)
set #xml= '
<ROOT>
<TX_MAP FK_GUEST_ID="1" FK_CATEGORY_ID="2" ATTRIBUTE="Test" DESCRIPTION="TestDesc" IS_ACTIVE="1" ADDED_BY="NULL" ADDED_DATE="12/3/2010" MODIFIED_BY="NULL" MODIFIED_DATE="12/3/2010"></TX_MAP>
<TX_MAP FK_GUEST_ID="2" FK_CATEGORY_ID="1" ATTRIBUTE="Test2" DESCRIPTION="TestDesc2" IS_ACTIVE="1" ></TX_MAP>
</ROOT> '
declare #handle int
exec sp_xml_preparedocument #handle output, #xml
select * from OPENXML(#handle,'/ROOT/TX_MAP',1)
with
(
FK_GUEST_ID INT
,FK_CATEGORY_ID VARCHAR(10)
,ATTRIBUTE VARCHAR(100)
,[DESCRIPTION] VARCHAR(100)
,IS_ACTIVE VARCHAR(10)
,ADDED_BY VARCHAR(100)
,ADDED_DATE DATETIME
,MODIFIED_BY VARCHAR(100)
,MODIFIED_DATE DATETIME
)
What you need to do is just to omit
those attributes that will result into
NULL value.
An XML element can be set to null like:
<ADDED_DATE xsi:nil="true"/>
I can't find a way to set an attribute to null though. Perhaps the only way is to omit it?

Resources