I have a column data structure like this, it can more than one row, more then one value, i want to get the deliveryID's value from this field, is there any way to do it?
i have a look of nodes and xmlpath, value()
is there a elegant way to do it? thanks very much
<row>
<value id="1ae95d67-599e-4ab6-9ffd-08d4d90ab608" display-name="Cardholder_id" data-type="Int32">17</value>
<value id="1ae95d67-599e-4ab6-9ffd-08d4d90ab608" display-name="Cardholder_id" data-type="Int32">17</value>
<value id="eb71fd46-f0b2-401d-9775-08d4d90ab608" display-name="Card_Number">3083 2614 5022 21321</value>
<value id="4fc261b2-f776-4fd4-8e1d-08d4d90ab608" display-name="Email_Address">jello#anc.com</value>
<value id="c867d4e5-cc0b-4ee6-b911-08d6134132e0" display-name="BP_TRIGGERS_2.0">{"transactions":[{"BP_CommsRef":"V0001","BP_Offer_Expiry":"2018-10-01T00:00:00","deliveryId":"20320925","Job_Number":"A34F443","Send_Date":"2018-09-26T00:00:00"}]}</value>
</row>
If you have SQL Server 2016 or above you can use OPENXMLand JSON_VALUE
DECLARE #XML XML ='<row>
<value id="1ae95d67-599e-4ab6-9ffd-08d4d90ab608" display-name="Cardholder_id" data-type="Int32">17</value>
<value id="1ae95d67-599e-4ab6-9ffd-08d4d90ab608" display-name="Cardholder_id" data-type="Int32">17</value>
<value id="eb71fd46-f0b2-401d-9775-08d4d90ab608" display-name="Card_Number">3083 2614 5022 21321</value>
<value id="4fc261b2-f776-4fd4-8e1d-08d4d90ab608" display-name="Email_Address">jello#anc.com</value>
<value id="c867d4e5-cc0b-4ee6-b911-08d6134132e0" display-name="BP_TRIGGERS_2.0">{"transactions":[{"BP_CommsRef":"V0001","BP_Offer_Expiry":"2018-10-01T00:00:00","deliveryId":"20320925","Job_Number":"A34F443","Send_Date":"2018-09-26T00:00:00"}]}</value>
</row>'
DECLARE #idoc int
EXEC sp_xml_preparedocument #idoc OUTPUT, #XML;
SELECT id, [display-name],
CASE WHEN ISJSON(JsonText) > 0 THEN JSON_VALUE(JsonText, '$.transactions[0].deliveryId') END deliveryId
, JsonText
FROM
OPENXML(#idoc,'row/value')
WITH (id uniqueidentifier,
[display-name] varchar(20),
JsonText varchar(max) '.' )
Result:
id display-name deliveryId JsonText
------------------------------------ -------------------- ------------------ --------------------------------------------------------------------------------------------------------------------------------------------------------------------------
1AE95D67-599E-4AB6-9FFD-08D4D90AB608 Cardholder_id NULL 17
1AE95D67-599E-4AB6-9FFD-08D4D90AB608 Cardholder_id NULL 17
EB71FD46-F0B2-401D-9775-08D4D90AB608 Card_Number NULL 3083 2614 5022 21321
4FC261B2-F776-4FD4-8E1D-08D4D90AB608 Email_Address NULL jello#anc.com
C867D4E5-CC0B-4EE6-B911-08D6134132E0 BP_TRIGGERS_2.0 20320925 {"transactions":[{"BP_CommsRef":"V0001","BP_Offer_Expiry":"2018-10-01T00:00:00","deliveryId":"20320925","Job_Number":"A34F443","Send_Date":"2018-09-26T00:00:00"}]}
You can also use this syntax.
SELECT
RowValue.value('#id', 'uniqueidentifier') id,
CASE WHEN ISJSON(RowValue.value('.', 'VARCHAR(max)') ) > 0
THEN JSON_VALUE(RowValue.value('.', 'VARCHAR(max)'), '$.transactions[0].deliveryId')
END AS deliveryId
FROM
(VALUES(#XML)) AS T (XmlValue)
CROSS APPLY
T.XmlValue.nodes('row/value') AS XT(RowValue)
Related
I am working with MS SQL Server 2012.
I am trying to use the function openxml with the following statement / xml data:
DECLARE #XML AS XML, #hDoc AS INT, #SQL NVARCHAR (MAX)
SET #SQL = '<master>
<List>
<Col>
<DisplayFieldName>Peter</DisplayFieldName>
<Value>
<string>Yes</string>
</Value>
</Col>
<Col>
<DisplayFieldName>Tom</DisplayFieldName>
<Value>
<string>No</string>
</Value>
</Col>
<Col>
<DisplayFieldName>Numerics</DisplayFieldName>
<Value>
<string>50 </string>
<string>100 </string>
<string>150 </string>
<string>200 </string>
</Value>
</Col>
</List>
</master>'
SELECT #XML = CONVERT(XML,#SQL)
EXEC sp_xml_preparedocument #hDoc OUTPUT, #XML
SELECT *
FROM OPENXML(#hDoc, '/master/List/Col/Value',3)
WITH
(
string [varchar](max)
)
EXEC sp_xml_removedocument #hDoc
The result is this:
string
1 Yes
2 No
3 50
I understand why this happens, but actually I would like to display just all numerical values (50,100,150,200) or at least all values in the field (Yes, No, 50, 100, 150, 200) which also would be sufficient.
FROM OPENXML is outdated and should not be used any more (There are some rare exceptions...)
You should rather use the XML-methods like .value(),.nodes(),.query() and .exist().
Give this a try: It is fully inlined (ad-hoc), easier to read and maintain - and much faster:
DECLARE #XML AS XML;
SET #XML = '<master>
<List>
<Col>
<DisplayFieldName>Peter</DisplayFieldName>
<Value>
<string>Yes</string>
</Value>
</Col>
<Col>
<DisplayFieldName>Tom</DisplayFieldName>
<Value>
<string>No</string>
</Value>
</Col>
<Col>
<DisplayFieldName>Numerics</DisplayFieldName>
<Value>
<string>50 </string>
<string>100 </string>
<string>150 </string>
<string>200 </string>
</Value>
</Col>
</List>
</master>';
SELECT C.value('DisplayFieldName[1]','nvarchar(max)') AS DisplayFieldName
,V.value('.','nvarchar(max)') AS string
FROM #XML.nodes('/master/List/Col') AS A(C)
CROSS APPLY C.nodes('Value/string') AS B(V);
The result
DisplayFieldName string
----------------------------
Peter Yes
Tom No
Numerics 50
Numerics 100
Numerics 150
Numerics 200
UPDATE
If you need the numerics only, you could append the same XQuery-filter to the .nodes() XPath, as pointed by Alex: /master/List/Col[DisplayFieldName="Numerics"]
You can give this a try, might return more than what you are expecting:
SELECT *
FROM OPENXML(#hDoc, '/master/List/Col/Value/*', 3)
WITH
(
string [varchar](max) '.'
)
Make xpath deeper. Filter data. Something like this.
SELECT text string
FROM OPENXML(#hDoc, '/master/List/Col[DisplayFieldName="Numerics"]/Value/string',3)
--WITH
--(
--string [varchar](max)
--)
where text is not null
update
You can also use native xml methods.
select t.v.value('.','varchar(100)') x
from #xml.nodes('master/List/Col[DisplayFieldName="Numerics"]/Value/string') t(v)
In my experience openxml works faster with large texts.
Would someone be able to help me I am trying to import an xml file to a sql server table. I can import the required data but having some trouble getting it in the format required.
declare #input XML = '<Sub>
<Results>
<Result>
<ids>
<id>
<type>code</type>
<value>9004a3d2</value>
</id>
<id>
<type>username</type>
<value>jbloggs001</value>
<date>20160725</date>
</id>
<id>
<type>EmployeeID</type>
<value>01234</value>
<date>20160725</date>
</id>
</ids>
</Result>
</Results>
</Sub>'
SELECT
datatype = XCol.value('(type)[1]','varchar(25)'),
datavalue = XCol.value('(value)[1]','varchar(50)')
FROM
#input.nodes('/Sub/Results/Result/ids/id') AS XTbl(XCol)
This gives 3 columns like:
datatype datavalue
--------------------------------
code 9004a3d2
username jbloggs001
employeeID 01234
Would it be possible to get it to import as?
EmployeeID USername Code
---------------------------------
01234 jbloggs 0019004a3d2
Thanks
As was suggested in comments that could be done using PIVOT:
SELECT *
FROM (
SELECT
datatype = XCol.value('(type)[1]','varchar(25)'),
datavalue = XCol.value('(value)[1]','varchar(50)')
FROM
#input.nodes('/Sub/Results/Result/ids/id') AS XTbl(XCol)
) as p
PIVOT (
MAX(datavalue) FOR datatype IN (EmployeeID,username,code)
) as pvt
Output:
EmployeeID username code
01234 jbloggs001 9004a3d2
If input is always with same types:
SELECT XCol.value('(id/value)[3]','varchar(50)') as EmployeeID,
XCol.value('(id/value)[2]','varchar(50)') as username,
XCol.value('(id/value)[1]','varchar(50)') as code
FROM #input.nodes('/Sub/Results/Result/ids') AS XTbl(XCol)
Another option is XQuery contains function
declare #input XML = '<Sub>
<Results>
<Result>
<ids>
<id>
<type>code</type>
<value>9004a3d2</value>
</id>
<id>
<type>username</type>
<value>jbloggs001</value>
<date>20160725</date>
</id>
<id>
<type>EmployeeID</type>
<value>01234</value>
<date>20160725</date>
</id>
</ids>
</Result>
</Results>
</Sub>';
SELECT
code = XCol.value('(id[contains((./type)[1],"code")]/value)[1]','varchar(50)'),
username = XCol.value('(id[contains((./type)[1],"username")]/value)[1]','varchar(50)'),
EmployeeID = XCol.value('(id[contains((./type)[1],"EmployeeID")]/value)[1]','varchar(50)')
FROM
#input.nodes('/Sub/Results/Result/ids') AS XTbl(XCol);
Below query works for your solution
Select [EmployeeID],[Username],[Code]
FROM #TEMP
PIVOT
(
MAX(DATAVALUE) FOR DATATYPE IN (code,username,employeeID)
)A
Another very straight and typesafe approach was this:
SELECT id.value('(id[type="code"]/value)[1]','varchar(max)') AS code
,id.value('(id[type="username"]/value)[1]','varchar(max)') AS username
,id.value('(id[type="EmployeeID"]/value)[1]','varchar(max)') AS EmployeeID
FROM #input.nodes('Sub/Results/Result/ids') AS A(id)
Hi I have XML data with attribute as input for SQL, i need this to be inserted in my table.
XML Data is
<?xml version="1.0" encoding="ISO-8859-1"?>
<MESSAGEACK>
<GUID GUID="kfafb30" SUBMITDATE="2015-10-15 11:30:29" ID="1">
<ERROR SEQ="1" CODE="28681" />
</GUID>
<GUID GUID="kfafb3" SUBMITDATE="2015-10-15 11:30:29" ID="1">
<ERROR SEQ="2" CODE="286381" />
</GUID>
</MESSAGEACK>
I want this to be inserted in below Format
GUID SUBMIT DATE ID ERROR SEQ CODE
kfafb3 2015-10-15 11:30:29 1 1 28681
kfafb3 2015-10-15 11:30:29 1 1 2868
please help.
Look into XPath and xml Data Type Methods in MSDN. This is one possible way :
declare #xml As XML = '...you XML string here...'
INSERT INTO YourTable
SELECT
guid.value('#GUID', 'varchar(100)') as 'GUID'
,guid.value('#SUBMITDATE', 'datetime') as 'SUBMIT DATE'
,guid.value('#ID', 'int') as 'ID'
,guid.value('ERROR[1]/#SEQ', 'int') as 'SEQ'
,guid.value('ERROR[1]/#CODE', 'int') as 'CODE'
FROM #xml.nodes('/MESSAGEACK/GUID') as x(guid)
Result :
just paste this into an empty query window and execute. Adapt to your needs:
DECLARE #xml XML=
'<?xml version="1.0" encoding="ISO-8859-1"?>
<MESSAGEACK>
<GUID GUID="kfafb30" SUBMITDATE="2015-10-15 11:30:29" ID="1">
<ERROR SEQ="1" CODE="28681" />
</GUID>
<GUID GUID="kfafb3" SUBMITDATE="2015-10-15 11:30:29" ID="1">
<ERROR SEQ="2" CODE="286381" />
</GUID>
</MESSAGEACK>';
SELECT Msg.Node.value('#GUID','varchar(max)') AS [GUID] --The value is no GUID, if the original values are, you could use uniqueidentifier instead of varchar(max)
,Msg.Node.value('#SUBMITDATE','datetime') AS SUBMITDATE
,Msg.Node.value('#ID','int') AS ID
,Msg.Node.value('(ERROR/#SEQ)[1]','int') AS [ERROR SEQ]
,Msg.Node.value('(ERROR/#CODE)[1]','int') AS CODE
FROM #xml.nodes('/MESSAGEACK/GUID') AS Msg(Node)
I have the following XML:
<help>
<item field="field1" help="helptext" />
<item field="field2" help="helptext" />
<item field="field3" help="helptext" />
</help>
I have this stored in an XML DataType in SQL server and would like to pull out the fields and help text seperately. I.e a results set similar to:
| field1 | helptext |
| field2 | helptext |
| field3 | helptext |
Does anybody know how to achieve this?
Kindest Regards,
Adam
DECLARE #xml AS XML = '<help>
<item field="field1" help="helptext" />
<item field="field2" help="helptext" />
<item field="field3" help="helptext" />
</help>'
select c.value('#field', 'varchar(max)') field, c.value('#help', 'varchar(max)') help
from #xml.nodes('/help/item') T(c);
To achieve the same when xml data is in a table field use:
SELECT c.value('#field', 'varchar(max)') field, c.value('#help', 'varchar(max)') help
FROM MyTable A CROSS APPLY A.MyXmlField.nodes('/help/item') T(c)
Where MyTable is the table with field MyXmlField containing xml data.
See if following helps:
DECLARE #processedXmlDoc int
DECLARE #inputDoc varchar(1000)
EXEC sp_xml_preparedocument #processedXmlDoc OUTPUT, #inputDoc
SELECT *
FROM OPENXML (#processedXmlDoc , '/help/item',1)
WITH (field varchar(20) 'field',
help varchar(20) 'helpText')
EXECUTE sp_xml_removedocument #idoc
Hope that helps.
Try something like this:
DECLARE #input XML = '<help>
<item field="field1" help="helptext" />
<item field="field2" help="helptext" />
<item field="field3" help="helptext" />
</help>'
SELECT
Field = Item.value('#field', 'varchar(25)'),
HELP = Item.value('#help', 'varchar(50)')
FROM
#input.nodes('/help/item') AS XTbl(Item)
I wonder how can i read a xml data and transform it to a table in TSQL?
For example:
<row>
<IdInvernadero>8</IdInvernadero>
<IdProducto>3</IdProducto>
<IdCaracteristica1>8</IdCaracteristica1>
<IdCaracteristica2>8</IdCaracteristica2>
<Cantidad>25</Cantidad>
<Folio>4568457</Folio>
</row>
<row>
<IdInvernadero>3</IdInvernadero>
<IdProducto>3</IdProducto>
<IdCaracteristica1>1</IdCaracteristica1>
<IdCaracteristica2>2</IdCaracteristica2>
<Cantidad>72</Cantidad>
<Folio>4568457</Folio>
</row>
To
8 3 8 8 25 4568457
3 3 1 2 72 4568457
This is the answer, hope it helps someone :)
First there are two variations on how the xml can be written:
1
<row>
<IdInvernadero>8</IdInvernadero>
<IdProducto>3</IdProducto>
<IdCaracteristica1>8</IdCaracteristica1>
<IdCaracteristica2>8</IdCaracteristica2>
<Cantidad>25</Cantidad>
<Folio>4568457</Folio>
</row>
<row>
<IdInvernadero>3</IdInvernadero>
<IdProducto>3</IdProducto>
<IdCaracteristica1>1</IdCaracteristica1>
<IdCaracteristica2>2</IdCaracteristica2>
<Cantidad>72</Cantidad>
<Folio>4568457</Folio>
</row>
Answer:
SELECT
Tbl.Col.value('IdInvernadero[1]', 'smallint'),
Tbl.Col.value('IdProducto[1]', 'smallint'),
Tbl.Col.value('IdCaracteristica1[1]', 'smallint'),
Tbl.Col.value('IdCaracteristica2[1]', 'smallint'),
Tbl.Col.value('Cantidad[1]', 'int'),
Tbl.Col.value('Folio[1]', 'varchar(7)')
FROM #xml.nodes('//row') Tbl(Col)
2.
<row IdInvernadero="8" IdProducto="3" IdCaracteristica1="8" IdCaracteristica2="8" Cantidad ="25" Folio="4568457" />
<row IdInvernadero="3" IdProducto="3" IdCaracteristica1="1" IdCaracteristica2="2" Cantidad ="72" Folio="4568457" />
Answer:
SELECT
Tbl.Col.value('#IdInvernadero', 'smallint'),
Tbl.Col.value('#IdProducto', 'smallint'),
Tbl.Col.value('#IdCaracteristica1', 'smallint'),
Tbl.Col.value('#IdCaracteristica2', 'smallint'),
Tbl.Col.value('#Cantidad', 'int'),
Tbl.Col.value('#Folio', 'varchar(7)')
FROM #xml.nodes('//row') Tbl(Col)
Taken from:
http://kennyshu.blogspot.com/2007/12/convert-xml-file-to-table-in-sql-2005.html
http://msdn.microsoft.com/en-us/library/ms345117(SQL.90).aspx
The sp_xml_preparedocument stored procedure will parse the XML and the OPENXML rowset provider will show you a relational view of the XML data.
For details and more examples check the OPENXML documentation.
As for your question,
DECLARE #XML XML
SET #XML = '<rows><row>
<IdInvernadero>8</IdInvernadero>
<IdProducto>3</IdProducto>
<IdCaracteristica1>8</IdCaracteristica1>
<IdCaracteristica2>8</IdCaracteristica2>
<Cantidad>25</Cantidad>
<Folio>4568457</Folio>
</row>
<row>
<IdInvernadero>3</IdInvernadero>
<IdProducto>3</IdProducto>
<IdCaracteristica1>1</IdCaracteristica1>
<IdCaracteristica2>2</IdCaracteristica2>
<Cantidad>72</Cantidad>
<Folio>4568457</Folio>
</row></rows>'
DECLARE #handle INT
DECLARE #PrepareXmlStatus INT
EXEC #PrepareXmlStatus= sp_xml_preparedocument #handle OUTPUT, #XML
SELECT *
FROM OPENXML(#handle, '/rows/row', 2)
WITH (
IdInvernadero INT,
IdProducto INT,
IdCaracteristica1 INT,
IdCaracteristica2 INT,
Cantidad INT,
Folio INT
)
EXEC sp_xml_removedocument #handle