XML Query with a variable not working - sql

declare #xml xml =
'<ChangeSet DBSchemaVersion="2.0.0.88" DBSyncVersion="15" ScopeId="1">
<C op="I" PK="44">
<User UserId="44" Role="3" UserName="Dummy1" />
</C>
<C op="I" PK="45">
<User UserId="45" Role="3" UserName="Dummy2" />
</C>
<C op="I" PK="46">
<User UserId="46" Role="3" UserName="Dummy3" />
</C>
</ChangeSet>'
-- this works fine
SELECT [SyncTable].Col.query('User')
FROM #xml.nodes('/ChangeSet/C[#op=''I'']') as [SyncTable](Col)
FOR XML AUTO
-- this does not work
DECLARE #tableName NVARCHAR(MAX) = 'User'
SELECT [SyncTable].Col.query('sql:variable(''#tableName'')')
FROM #xml.nodes('/ChangeSet/C[#op=''I'']') as [SyncTable](Col)
FOR XML AUTO
The first returns:
<SyncTable><User UserId="44" Role="3" UserName="Dummy1"/></SyncTable><SyncTable><User UserId="45" Role="3" UserName="Dummy2"/></SyncTable><SyncTable><User UserId="46" Role="3" UserName="Dummy3"/></SyncTable>
The second returns:
<SyncTable>User</SyncTable><SyncTable>User</SyncTable><SyncTable>User</SyncTable>
I'm trying to do this in a procedure where the table name is a parameter. Is there a way to do what I'm trying to achieve?
SQL Server 2008 R2
TIA

SQL variable value passed to the xquery expression as literal string, and AFAICS there is no way to inject literal string as xquery/xpath step expression.
However, there is a way around this, namely, filtering element having name equals specific string. Here, specific string is the literal string from SQL variable, for example :
DECLARE #tableName NVARCHAR(MAX) = 'User'
SELECT [SyncTable].Col.query('*[local-name()=sql:variable("#tableName")]')
FROM #xml.nodes('/ChangeSet/C[#op="I"]') as [SyncTable](Col)
FOR XML AUTO
SQL Fiddle Demo
This part *[local-name()=sql:variable("#tableName")] reads : select any child of current context element, having local-name equals value of #tableName variable.

Related

Query xml using xquery in SQL Server 2016

I have my XML in following format:
<resultset xmlns="qm_system_resultset" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<result>
<result_id>F5</result_id>
<exception>NO</exception>
<recurring_count>0</recurring_count>
<defect>NO</defect>
<unresolved>NO</unresolved>
<exception_approval />
<comments />
<exception_expiration>3000-01-01</exception_expiration>
<exception_stat_only>NO</exception_stat_only>
<result_data>
<phraseprefix>rx</phraseprefix>
<phrasenumber>0001</phrasenumber>
<languagedesc>Khmer</languagedesc>
<englishphrase> each time.</englishphrase>
<phrasedesc> គ្រាប់ក្នុងមួយដង។</phrasedesc>
<qm_translatedphrase>day.</qm_translatedphrase>
</result_data>
</result>
<result>
<result_id>26</result_id>
<exception>NO</exception>
<recurring_count>0</recurring_count>
<defect>NO</defect>
<unresolved>NO</unresolved>
<exception_approval />
<comments />
<exception_expiration>3000-01-01</exception_expiration>
<exception_stat_only>NO</exception_stat_only>
<result_data>
<phraseprefix>hold</phraseprefix>
<phrasenumber>0001</phrasenumber>
<languagedesc>Hmong</languagedesc>
<englishphrase>Hold than 160.</englishphrase>
<phrasedesc>Tsis 160.</phrasedesc>
<qm_translatedphrase>Do not use </qm_translatedphrase>
</result_data>
</result>
Using TSQL/XML query how do I achieve this RESULT
[phraseprefix][phrasenumber]
rx 0001
hold 0001
...
I tried the following query, but I got null values for both the columns:
DECLARE #input XML = (SELECT result_xml
FROM QM_Data_Audit.QM_Package.test_results
WHERE result_id = 2446338)
SELECT
resultset.value('(phraseprefix)[1]', 'varchar(max)') AS 'phrasenumber',
resultset.value('(phrasenumber)[1]', 'int') AS 'phrasenumber'
FROM #input.nodes('/resultset/result/result_data') AS List(resultset)
My apologies if the question is asked previously, I am new to querying XML.
Appreciate your help.
Your xml has a namespace declared so you need to provide this when querying it. In this example this can be acheived with the WITH XMLNAMESPACES statement:
DECLARE #input XML = (SELECT result_xml
FROM QM_Data_Audit.QM_Package.test_results
WHERE result_id = 2446338);
WITH XMLNAMESPACES(DEFAULT 'qm_system_resultset')
SELECT
resultset.value('(phraseprefix)[1]', 'varchar(max)') AS 'phrasenumber',
resultset.value('(phrasenumber)[1]', 'varchar(max)') AS 'phrasenumber'
FROM #input.nodes('/resultset/result/result_data') AS List(resultset)
You'll want to set the data type for phrasenumber to varchar as well to preserve the leading 0s if you need them.

Creating xml for SQL Server stored procedure

I have a function to insert an item into the database. It takes a lot of values as input and the values are passed as XML.
Consider a sample item XML:
<ROOT>
<Item
ItemName="CarlsApplication"
ItemTypeID="2">
<TSDefaultDescription DefaultitemDescription="C:\t.text"/>
<ItemSellers>
<ComputerObject Alias="" DisplayName="" ServiceName="" UserAccount="" />
<ComputerObject Alias="" DisplayName="" ServiceName="" UserAccount="" />
</ItemSellers>
<ItemOwners>
<ItemOwner Alias="rafchen" FirstName="Rafael" LastName="Chenkov"/>
</ItemOwners>
</Item>
</ROOT>
This has to be passed to stored procedure.
Now, each of these individual values in this XML, I have to extract from somewhere else. I can get the individual values like Item name etc, but how do I organize them into an XML that can be passed?
How do I construct this XML from the values I have?
I guess I will have to make some sort of template with this format and then put variables in that template and fill the variables to prepare the template.
Any help is greatly appreciated.
If I understand what you really want, You can use a query like this to generate that XML:
select
ItemName 'Item/#ItemName', --> Node:`Item` Attribute: `ItemName`
ItemTypeId 'Item/#ItemTypeId',
cast((
select
Alias 'ComputerObject/#Alias',
DisplayName 'ComputerObject/#DisplayName',
ServiceName 'ComputerObject/#ServiceName',
UserAccount 'ComputerObject/#UserAccount'
from
ItemSellers
where
ItemSellers.ItemId = Item.ItemId
for xml path('')) as xml) 'Item/ItemSellers', --> Node:`Item` Sub-Node:`ItemSellers`
cast((
select
Alias 'ItemOwner/#Alias',
FirstName 'ItemOwner/#FirstName',
LastName 'ItemOwner/#LastName'
from
ItemOwners
where
ItemOwners.ItemId = Item.ItemId
for xml path('')) as xml) 'Item/ItemOwners'
from
Item
for xml path('ROOT');
SQL Fiddle Demo

SQL Server: How to get the value of a XML element specifying an attribute?

For the usage in a SQL query I need to get the value of a specific XML element. The XML element is specified by its attribute.
My XML elements looks like this:
<translations>
<value lang="en-US">example</value>
<value lang="de-DE">Beispiel</value>
</translations>
and the value I am looking for would be "example" when I specify lang to be "en-US".
I found a way to get this value by using the query() function and afterwards the value() function.
declare #S varchar(max)
set #S =
'<translations>
<value lang="en-US">example</value>
<value lang="de-DE">Beispiel</value>
</translations>'
declare #X xml
set #X = CAST(#S as xml)
select #X.query('/translations/value[#lang="en-US"]').value('.','varchar(max)')
This select statement return the value "example" I am looking for by using the query() and value() function. But is there also a - more convenient - way to only use value() OR query()?
Thank you in advance!
Sure there is...
You also can shorten the declaration:
declare #X xml=
'<translations>
<value lang="en-US">example</value>
<value lang="de-DE">Beispiel</value>
</translations>';
select #X.value('(/translations/value[#lang="en-US"])[1]','varchar(max)');
The point is, that you need a singleton result when you are using .value(). You achieve this by putting the XPath in paranthesis and force the first element to be taken (in this case it's the only element).
Btw: If you need this (and sooner or later you will need this...), you might put the "en-US" as parameter into your query like this:
declare #prm VARCHAR(10)='en_US';
select #X.value('(/translations/value[#lang=sql:variable("#prm")])[1]','varchar(max)');
You can reach the similar, but with a value of the actual query by using sql:column().

Parse the XML in SQL Server

<ROOT>
<arn>arn001</arn>
<arn>arn002</arn>
</ROOT>
Tried the following code though
SELECT
ARN.value('(//arn/text())[1]','VARCHAR(100)') AS arns --TAG
FROM
#xml.nodes('/ROOT')AS TEMPTABLE(ARN)
It returns only first value
Try this way :
declare #xml xml = '<ROOT>
<arn>arn001</arn>
<arn>arn002</arn>
</ROOT>'
SELECT
X.value('.','VARCHAR(100)') AS arns
FROM
#xml.nodes('/ROOT/arn')AS T(X)
SQL Fiddle

No return value on using OpenXML command in SQL Server 2008

This is my XML parameter that I set to #XMLSave parameter and send to a stored procedure
<ROOT>
<P>
<ID>123456789</ID>
<Name>admin</Name>
</P>
<Group>
<GroupCardID>14</GroupCardID>
</Group>
</ROOT>
and I try to get ID value with this command
EXEC sp_xml_preparedocument #idoc OUTPUT, #XMLSave
but when I select values return no value
select *
from OPENXML (#idoc,'/Root/P',2) With(ID int)
Try this:
DECLARE #XmlParameter XML = '<ROOT>
<P>
<ID>123456789</ID>
<Name>admin</Name>
</P>
<Group>
<GroupCardID>14</GroupCardID>
</Group>
</ROOT>'
SELECT
#XmlParameter.value('(/ROOT/P/ID)[1]', 'int')
I always prefer the native XQuery support over the clunky old OPENXML stuff.....
I Found the answer finally:
OpenXML parameter is case sensitive :
my XML value start with "ROOT" and openxml parameter was "Root"