I'm working on a problem even my colleagues say is impossible. There is XML already in our database and I want to be able to take single attributes from the XML and set them equal to variables to work with. This is my code so far (that doesn't work).
declare #MyText varchar(10)
declare #MyXML XML
set #MyXML = '
<ns0:TestXML xmlns:ns0="http://test.com">
<TestValue>11</TestValue>
</ns0:TestXML>'
set #MyText =
(
;with XMLNAMESPACES ('http://test.com' as ns0)
set #MyText =
(
select
a.bo.value('(/ns0:TestXML2[1]/TestXML3)[1]','INT') as [Number]
from #MyXML.nodes('ns0:TestXML') a(bo)
)
)
Any help would be greatly appreciated, thank you. Also if my logic is completely off about how SQL works with XML, please don't hesitate to educate me.
How's this, it returns 11 from the provided XML which is what you want I assume:
declare #MyText varchar(10)
declare #MyXML XML
set #MyXML = '
<ns0:TestXML xmlns:ns0="http://test.com">
<TestValue>11</TestValue>
</ns0:TestXML>'
;with XMLNAMESPACES ('http://test.com' as ns0)
select #MyText =
a.bo.value('(/ns0:TestXML)[1]','INT')
from #MyXML.nodes('ns0:TestXML') a(bo)
select #MyText as [TheImpossibleValue]
Related
The below code is a common way of splitting a delimited varchar in TSQL. My question is about
the syntax in the last 2 line. Why are we select N.Value() and giving xml.nodes the alias T(N).
I have not come across this T(N) syntax, i'm unsure what it means and what the N in N.Value is
referencing. I've tried to google this but have found it hard to get an answer, would anyone be
able to help me? Thank you
DECLARE #xml as xml,#str as varchar(100),#delimiter as varchar(10)
SET #str='A,B,C,D,E'
SET #delimiter =','
SET #xml = cast(('<X>'+replace(#str,#delimiter ,'</X><X>')+'</X>') as xml)
SELECT N.value('.', 'varchar(10)') as value
FROM #xml.nodes('X') as T(N)
MSFT documentation on XML nodes() Method can be found here.
The basic syntax of the nodes method is:
nodes (XQuery) as Table(Column)
It transforms the xml data type to relational data, a value per row.
As Panagiotis already pointed out, there is a faster route. If you are using a database with compatibility level of 130 and higher, go can use the STRING_SPLIT table-valued function.
DECLARE #str as varchar(100),#delimiter as varchar(10)
SET #str='A,B,C,D,E'
SET #delimiter =','
Select [value] FROM STRING_SPLIT(#str, #delimiter)
Hope this clarifies things for you.
I need to use a dynamic string for an xquery path but .query/.nodes methods require a literal string as parameter. So I decided to try sql:variable
DECLARE #xmlData XML, #node varchar(max)
SET #xmlData = 'Some XML Here'
SET #node = '/path1/path2/path3'
When I query with
select #xmlData.query('/path1/path2/path3')
It returns the intended result
But when I query with
select #xmlData.query('sql:variable("#node")')
It returns the variable value itself as "/path1/path2/path3"
What is wrong here?
This should do the trick:
select #xmlData.query('/*[local-name()=sql:variable("#node")]')
It matches any node with a wildcard *, but there is an extra predicate that the name has to match the variable
For performance reasons, you should preferably use /text() to get inner text, and use .values to get a single value.
select #xmlData.value('(/*[local-name()=sql:variable("#node")]/text())[1]', 'nvarchar(100)')
sql:variable is used to substitute a single scalar variable into an XPath expression, so can't be used to define a full path. You can use it to test against a single node's name, though, e.g.:
declare #xmlData XML = '<path1><path2><path3>foo</path3></path2></path1>'
select [example1] = #xmlData.query('/path1/path2/path3')
--example1
--<path3>foo</path3>
declare #node1 varchar(max) = 'path1'
declare #node2 varchar(max) = 'path2'
declare #node3 varchar(max) = 'path3'
select [example2] = #xmlData.query('//*[local-name()= sql:variable("#node1")]/*[local-name()= sql:variable("#node2")]/*[local-name()= sql:variable("#node3")]');
--example2
--<path3>foo</path3>
I am using MS SQL server to get a search result in json format there is only ever 1 row returned in my use case but they designed this as a search tool so you can return more than one value hence the array. The issue I am having is extracting the id value from the array that is returned.
json #response (Array):
{"hits":[{"id":1320172,"email":"xyz#domain.eu","first_name":"IMA","last_name":"TESTERTOO","created":"2018-12-12T11:52:58+00:00","roles":["Learner"],"status":true}],"total":1}
I have tried a number of things but I can't seem to get the path right.
SET #MyUserid = JSON_QUERY(#Reponse, '$.hits[0].id')
SET #MyUserid =JSON_VALUE(#Reponse,'$.hits[0].id')
SET #MyUserid = JSON_QUERY(#Reponse, '$.id')
On most examples I have found the json is not a single line array so I feel like I am missing something there. I'm inexperienced with working with json so any help would be greatly appreciated.
You can try this
DECLARE #json NVARCHAR(MAX)=
N'{"hits":[{"id":1320172,"email":"xyz#domain.eu","first_name":"IMA","last_name":"TESTERTOO","created":"2018-12-12T11:52:58+00:00","roles":["Learner"],"status":true}],"total":1}';
--This will return just one selected value
SELECT JSON_VALUE(#json,'$.hits[0].id')
--This will return the whole everything:
SELECT A.total
,B.*
FROM OPENJSON(#json)
WITH(hits nvarchar(max) AS JSON, total int) A
CROSS APPLY OPENJSON(A.hits)
WITH(id int
,email nvarchar(max)
,first_name nvarchar(max)
,last_name nvarchar(max)
,created nvarchar(max)
,roles nvarchar(max) AS JSON
,[status] bit) B
If I have a DataField that consists of:
Red|Blue|Green|Orange|Black
I'd like to create a function that returns this as a single dynamic variable [Colors] and when rendered it looks like this:
<li>Red</li>
<li>Blue</li>
<li>Green</li>
<li>Orange</li>
<li>Black</li>
So I need to generate the li elements, just as they are above, all within SQL.
I've done this the other way around using STUFF, where I can create this when the values are individual items in a table.
Any help would be appreciated.
Thank you!
This should do it:
DECLARE #xml as xml
DECLARE #string as varchar(100)
SET #string ='Red|Blue|Green|Orange|Black'
SET #xml = cast( ('<li>' + replace( #string, '|' ,'</li><li>') + '</li>') as xml)
SELECT #xml
I have a xml document which contains some custom fields which i wont know the names of. i want to generate a select statement which will list the contents in a name value style.
All examples I have found sofar require me to know the names of the nodes.
i.e.
declare #idoc int
declare #doc nvarchar(max); set
#doc = '<user>
<additionalfields>
<Account__Manager>Fred Dibner</Account__Manager>
<First__Aider>St Johns Ambulance</First__Aider>
</additionalfields>
</user>'
EXEC sp_xml_preparedocument #idoc OUTPUT, #doc;
SELECT * FROM OPENXML (#idoc, 'user/additionalfields/',1)
is it possible to achieve this?
well i found the answer after a fair amount more experimenting.(incidentally the double underscore replace is due to the output format of some of the database field names.)
SELECT replace(name,'__',' ') as name, value
FROM OPENXML (#idoc, '/user/additionalfields/*',1)
WITH (
Name nvarchar(4000) '#mp:localname',
value nvarchar(4000) './text()'
)