SQL Server xml variable is not by reference - sql

the following query should append node to an exist xml.
based on the output xml variable is actually new node and not reference of the exists one.
can I use reference variable
please advise:
declare #a_bo_key_xml xml='<r><items><item><key>k1</key><value>v1</value></item></items></r>'
Declare #rowsBOK xml=#a_bo_key_xml.query('/r/items/item')
select #rowsBOK.value('(*/key)[1]','varchar(100)'), #rowsBOK.value('(*/value)[1]','varchar(100)')
set #rowsBOK.modify('insert <added>aaa</added> as first into (*)[1]')
select cast(#a_bo_key_xml as varchar(max))
select cast(#rowsBOK as varchar(max))
output:
<r><items><item><key>k1</key><value>v1</value></item></items></r>
<item><added>aaa</added><key>k1</key><value>v1</value></item>
expected:
<r><items><item><added>aaa</added><key>k1</key><value>v1</value></item></items></r>
<item><added>aaa</added><key>k1</key><value>v1</value></item>

XML variables take a new identity when re-assigned, there is no connection between one and the other.
Just modify the #a_bo_key_xml variable directly:
declare #a_bo_key_xml xml='<r><items><item><key>k1</key><value>v1</value></item></items></r>';
set #a_bo_key_xml.modify('insert <added>aaa</added> as first into (/r/items/item)[1]');
select #a_bo_key_xml;
db<>fiddle

Related

XML Query with a variable in WHERE

I have this code that works well. But I want to have a variable to change its value in run time. I want the output xml file in C#.
declare #MySearch nvarchar(50)
set #MySearch='بودان'
SELECT ID, Family
FROM Table_1
where freetext(Family, #MySearch, LANGUAGE 1025)
FOR XML RAW ('Employee'), ROOT ('Employees'), ELEMENTS XSINIL;
EDITED:
I ran this code and got this error:
Null or empty full-text predicate.
I want the output xml file in C#.
declare #MySearch nvarchar(50)
--set #MySearch=N'بودان'
SELECT ID, Family
FROM Table_1
where freetext(Family, #MySearch, LANGUAGE 1025)
FOR XML RAW ('Employee'), ROOT ('Employees'), ELEMENTS XSINIL;
The "N" makes the difference, and you need it twice...
Try this:
DECLARE #v1 VARCHAR(10)='بودان';
DECLARE #v2 VARCHAR(10)=N'بودان';
DECLARE #nv1 NVARCHAR(10)='بودان';
DECLARE #nv2 NVARCHAR(10)=N'بودان';
SELECT #v1,#v2,#nv1,#nv2;
The result
????? ????? ????? بودان
Only the very last attempt will show what you need...
The reason: A normal string SET #v='MyString' is not handled as UNICODE
It is neither enough to declare the variable as NVARCHAR nor is it enough to store a unicode literal like N'SomeText'.
EDIT:
After long disucussion in comments the final sentence to solve the issue was this:
Of course you must be connected with the DB to do this!
What ever you want to with your database, first you need an opened connection.

SQL Server Select XML Column Based on Content by User Input Values

I am developing an sql server 2012 based application.
I am a newbie to SQl server. But the requirement is to use it.
One of the table I am using contains an XML Datatype column. However the data containing in that column may vary as per the xml element. The only thing in common is the root: For instance this is a sample data:
<Tags>
<key1>Value1</key1>
<key2>Value2</key2>
<key3>Value3</key3>
<key4>Value4</key4>
<key5>Value5</key5>
<key6>Value6</key6>
</Tags>
What I want to do is to query the whole table and fetch records that will match a specific key and a specific values sent by the user.
Please assist me.
Well it sounds like you need to use some variables to build an XQuery, yes? So, assuming you build a stored procedure or something which takes a pair of string arguments for key and value you could use the following example I've knocked up in SQL Fiddle so you can try it out.
DECLARE #key nvarchar(20)
DECLARE #value nvarchar(20)
SET #key = N'key5'
SET #value = N'Value5'
SELECT
TagValue = T1.xmlcol.value('(/Tags/*[local-name()=sql:variable("#key")])[1]', 'varchar(10)')
FROM
dbo.T1
WHERE
T1.xmlcol.exist('/Tags/*[local-name()=sql:variable("#key")][text() = "Value5"]') = 1

Stored procedure parameter with XML query in MSSQL gives "argument must be string literal"

I'm trying to query a table with a column which is xml data with the query and value functions. When using regular string literals it's all okay, but if I put that in a stored procedure and try to use variables it doesn't work.
I suppose I'm not using the correct datatype, but after some searching I can't figure out what datatype the query function wants.
Example:
table contains
| Id | xmldata |
| 1 | <data><node>value</node></data> |
now, using the select query
select id
from table
where xmldata.query('/data/node').value('.', 'VARCHAR(50)') = 'value'
gets me the data I want. But, if I use this in a stored procedure and use a parameter #xpath varchar(100) and pass that to the query method as xmldata.query(#xpath)
i get the error
The argument 1 of the xml data type method "query" must be a string literal.
I guess varchar(100) is not correct, but what datatype can I use that would make MSSQL happy?
Update:
Okay, so. Apparently you can't pass a parameter to the query method "just like that", but one can use the sql:variable in conjunction with local-name to work a part of it out. So, for instance, this will work
declare #xpath VarChar(100)
set #xpath='node'
select objectData.query('/data/*[local-name() = sql:variable("#xpath")]')
.value('.', 'varchar(100)') as xmldata
from table
and value is selected in the column xmldata. But(!) it requires that the root node is the first value in the query function. The following will not work
declare #xpath VarChar(100)
set #xpath='/data/node'
select objectData.query('*[local-name() = sql:variable("#xpath")]')
.value('.', 'varchar(100)') as xmldata
from table
notice how the query path is "moved up" to the variable. I will continue my investigations..
A literal is the opposite of a variable. The message means that you cannot pass a variable as the first argument to query.
One way around that is dynamic SQL:
declare #sql varchar(max)
set #sql = 'select id from table where xmldata.query(''' + #path +
''').value(''.'', ''VARCHAR(50)'') = ''value'''
exec #sql
As you can see, dynamic SQL does not result in very readable code. I would certainly investigate alternatives.
EDIT: Your suggestion of local-name() works for node names.
declare #nodename varchar(max)
set #nodename = 'node'
...
where xmldata.query('//*[local-name()=sql:variable("#nodename")]')
.value('.', 'varchar(50)') = 'value'
There doesn't seem to be an equivalent for paths.

inserting a node into SQL 2008 xml datatype... checking if it exists first

I am reading through a plethora of articles at the moment to try to assist me.. just seems so many options and cannot seem to find a clean solution.. it probably is very basic so apologies in advance!
So I have an XML field in SQL 2008. It basically contains something like:
<root><id>1</id><id>4</id></root> and so on...
What I am hoping to do is pass a param in to a proc to insert an value IF it doesn't exist..
So rather than read the xml first and do this within say .NET code, is there a clean way of doing this within a stored proc/t-sql ???
Any help appreciated! I am sure this is a fairly common one!
An example using the value() method:
DECLARE
#x xml,
#param int
SET #x = '<root><id>1</id><id>2</id><id>3</id></root>'
SET #param = 1
IF NOT EXISTS (
SELECT * FROM #x.nodes('/root/id') n(x) WHERE x.value('.','int') = #param
)
PRINT 'Insert'
ELSE
PRINT 'Return'
You can use the .exist() XQuery function on your XML to find out if a given node exists or not.
Check out An Overview of XML Support in SQL Server 2005 - it's a great article on how to use the various XQuery functions available. Just after the middle of that page, you'll find this section:
Using the exist Method
The exist method takes an XPath
expression that selects a single node
within the XML document, and returns
either True (bit value 1) if the node
exists or False (bit value 0) if it
does not. If the source column is a
typed xml column (in which case you
must declare the namespace in your
query), and the element contains null,
the method returns NULL instead. So
the XQuery:
SELECT MyXml.exist('(/root/product[#id="304"])[1]' FROM MyTable
will return True if there is a product
with the id value "304" (a product
element with the attribute id="304"),
or False if not. You can also use the
exist method in the WHERE clause of a
SQL statement:
SELECT column1, column2, column3 FROM MyTable
WHERE MyXml.exist('(/root/product[#id="304"])[1]') = 1

How to get Sql Server XML variable into TEXT column

I need to update an XML document stored in a Microsoft SQL Server database, however the vendor of the product chose to store the XML in a TEXT column.
I've been able to extract the TEXT into an XML-type variable and perform the update I need on the xml within this variable, but when I try to UPDATE the column to push the change back to the database, I run into trouble.
Looking through the documentation it appears that it's not possible to simply CAST/CONVERT an XML type variable to insert it into a TEXT column, but I would think there is some way to extract the xml "string" from the XML-type variable and UPDATE the column using this value.
Any suggestions are appreciated, but I would like to keep the solution pure SQL that it can be run directly (no C# custom function, etc.); just to keep the impact on the database minimal.
(note: isn't it a bit absurd that you can't just CAST XML as TEXT? I'm just saying...)
Casting the XML as VARCHAR(MAX) works.
declare #xml xml
declare #tblTest table (
Id int,
XMLColumn text
)
insert into #tblTest
(Id, XMLColumn)
values
(1, '<MyTest><TestNode>A</TestNode></MyTest>')
set #xml = '<MyTest><TestNode>A</TestNode><TestNode>B</TestNode></MyTest>'
update #tblTest
set XMLColumn = cast(#xml as varchar(max))
where Id = 1
select Id, XMLColumn from #tblTest