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

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

Related

Xml file node reading and inserting as seperate rows in a table

I am new bee in learning microsoft technologies.
I struck with an issue in sql server where I need your help.
Well, I have a XML file with below format,
please see it for your reference
<Permissions><Denied><User/><Roles/><Groups/></Denied><Allowed><Users/><Roles>admin,user,reader,writer,</Roles><Groups/></Allowed></Permissions>
In which I need to read Roles node values and insert those comma separated values as single row where I I will pass permissionid as a parameter in stored procedure.
here is the table columns (I need to insert single role for single row in test table based on transitionid)
create table test
(
empid int identity(1,1),
roles varchar(40),
transitionid int
)
You have two problems here: getting the data from the XML and splitting it.
If you're using SQL 2016 you're in luck - there's a new STRING_SPLIT function. You could use that like so:
declare #xml xml = '<Permissions><Denied><User/><Roles/><Groups/></Denied><Allowed><Users/><Roles>admin,user,reader,writer,</Roles><Groups/></Allowed></Permissions>';
declare #test table
(
empid int identity(1,1),
roles varchar(40),
transitionid int
)
INSERT #test (roles)
select b.value
FROM #xml.nodes('//Roles/text()')x(csv)
CROSS APPLY STRING_SPLIT(CAST(x.csv.query('.') AS VARCHAR(MAX)), ',')b
where b.value <> ''
select * from #test
Otherwise, you'll have to do something similar using a custom string splitting method, which you can find more about How do I split a string so I can access item x? or https://sqlperformance.com/2012/07/t-sql-queries/split-strings - basically, both require either writing a custom T-SQL function or CLR code that is imported into SQL Server. You could then use the same method as above (replacing STRING_SPLIT with the name of your custom string splitting function).

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

Accessing text fields in a stored procedure and insert to another table

I am trying to access a “text” type and inserting that value into another table viw a stored procedure. I’ve tried to cast it, convert it, but nothing works.
My code looks somethings like this:
Declare #Critique varchar(max), #Feedback varchar(max)
…
…
…
SELECT #Critique = CAST(comments as varchar(max)), #Feedback = CAST(public_critique as varchar(max)) FROM ASCO_vEXTERNAL_REVIEW_APPLICATIONS_LIST WHERE wf_task_assignment_id = #WfTaskAssignmentIDP1
– comments and public_critique are defined as text in view (also tried with table) ASCO_vEXTERNAL_REVIEW_APPLICATIONS_LIST
…
…
…
insert into WF_TASK_ASSIGNMENT_REVIEW (wf_task_assignment_review_id, wf_task_assignment_id, grantee_project_id, comments, public_critique) values (#NewID1, #WfTaskAssignmentIDP2, #GranteeProjectID, #Critique, #Feedback)
Can you please help me with this as soon as possible. I would really appreciate this.
Thanks,
Harish
I'm assuming that the WF_TASK_ASSIGNMENT_REVIEW is the one containing the text column you're trying to write into.
The text type is now deprecated in SQL 2005 and 2008. If at all possible try and upgrade the WF_TASK_ASSIGNMENT_REVIEW table to use the nvarchar(max) type instead.
If not, the only way is to use the WRITETEXT statement to write into the target column, in a loop (since WRITETEXT has an upper limit). See the WRITETEXT statement example in the SQL Server docs.
Your question is not sound good to understand .
Dont use text ,it wont support in many cases like where ,group by etc , so try use varchar
This is just an example
Declare #Critique varchar(max)
set #Critique = (select public_critique from ASCO_vEXTERNAL_REVIEW_APPLICATIONS_LIST
where convert(varchar(50), wf_task_assignment_id ) =#WfTaskAssignmentIDP1)