read from xml string in sql - sql

i want create stored proc to display last name of xml string ''
so i tried..... following script
Declare #xml_string xml
set #xml_string='<Contacts LastName="jonson"/>'
select Lastname =#xml_string.value('Contacts[1]/LastName[1]','varchar(50)')
select statement display NULL here .please help any one ....

This is the correct way on getting the attribute value from the xml.
Declare #xml_string xml set #xml_string='<Contacts LastName="jonson"/>'
select Lastname =#xml_string.value('Contacts[1]/#LastName[1]','varchar(50)')

Related

How to insert an attribute into xml data which is saved as nvarchar(max)

Let's say there is the following XML data and I want to add an attribute into salary like currency="INR":
<employee>
<salary amount="6000"/>
</employee>
If this data is stored in a column of type XML, then another attribute is being added easily just by using this code snippet:
UPDATE TABLENAME
SET COLUMNNAME.modify('insert attribute currency{"INR"} into (/employee/salary)[1]')
and if this data is stored in a column of type nvarchar(max), then the following query is not working even after casting the data as xml:
UPDATE TABLENAME
SET CAST(CAST(COLUMNNAME AS VARCHAR(MAX)) AS XML).modify('insert attribute currency{"INR"} into (/employee/salary)[1]')
So, help me to resolve second point as I have a column as nvarchar and I need to insert an attribute into saved xml data.
modify() Method works only with variable/column directly and can only used in the SET clause.
So, to solve this since you are storing your data as NVARCHAR, you have two choices:
Alter your table and add a new column with XML datatype, move the data to it from your column, and then UPDATE the data using modify()
Create/declare a table to store your data as XML and do the UPDATE.
Here is an example for what you provide:
CREATE TABLE T
(
Value NVARCHAR(MAX)
);
INSERT INTO T
SELECT N'<employee>
<salary amount="6000"/>
</employee>';
DECLARE #V XML;
SELECT #V = CAST(Value AS XML)
FROM T;
SET #V.modify('insert attribute currency{"INR"} into (/employee/salary)[1]');
UPDATE T
SET Value = CAST(#V AS NVARCHAR(MAX));
SELECT * FROM T;
Live demo

Insert multiline in varchar

Is it possible to save a multiline varchar in SQL Server?
DECLARE #SQL VARCHAR(256)
SELECT #SQL = 'SELECT
ID, Name
FROM
Cust'
INSERT INTO
MultiLineTBL (SQL)
VALUES
(#SQL)
So this query:
SELECT SQL From MultiLineTBL
will return:
SELECT
ID, Name
FROM
Cust
Not the straight line:
SELECT ID, NAME FROM Cust
How is it possible to store a multiline varchar?
Your sql query have syntex error:
DECLARE #SQL VARCHAR(256) ;
--please update query like that
set #SQL = 'insert into MultiLineTBL(col1,col2)
SELECT ID, Name FROM Cust';
--and execure like that:
exec(#SQL);
Yes, it is possible to store a multi-line varchar in a table. In fact, the value in your example is stored correctly.
As AlexK has correctly commented, multi-line values are not displayed correctly in SQL Server Management Studio when it is configured to return the results in a grid, and that (viewing the results in a grid) must be what gave you the wrong impression. As per my observation, SSMS replaces every control character, including CR (CHAR(13)) and LF (CHAR(10)), with a space in this display mode.
Try switching to Results to Text (Ctrl+T) before running the query and you will see that line delimiters are actually preserved.

Pass SQL parameter value to select xml data

Code:
DECLARE #dataxml XML = CONVERT(xml ,'<Parentnode><childnode><id>1</id></childnode></Parentnode>')
DECLARE #childnode VARCHAR(50)
SET #childnode = (SELECT DISTINCT
r.value('fn:local-name(.)', 'nvarchar(50)') as t
FROM #dataxml.nodes('//Parentnode/*') AS records(r))
SELECT #childnode
SELECT
t.value('id[1]', 'int') AS id
FROM
#dataxml.nodes('/Parentnode/*[local-name(.)=sql:variable("#childnode")]/*') AS XD(t)
Output is returned as NULL, but it should comes with id value in xml
What's wrong in this code?
You just need to remove the /* characters at the end of your last line, like this:
#dataxml.nodes('/Parentnode/*[local-name(.)=sql:variable("#childnode")]') AS XD(t)
Also I had to remove the $ character at the end of the FROM keyword, but I'm guessing that could just be a typo. I tested this is SQL Server 2012.

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.

Regarding Dynamic sql construction

when we load xml into cursor then we specify column name and their datatype and size. instead of specifying manually how could i make that area dynamic. suppose my tsql as follows
Exec sp_xml_preparedocument #XMLFormat OUTPUT, #DetailXml
-- Create Cursor from XML Table
Declare CurDetailRecord
Cursor For
Select productid,unit,rate,qty,amount
From Openxml (#XMLFormat, '/NewDataSet/PurchaseOrderDetail', 2)
With
(
productid Varchar(10),
unit Varchar(50),
rate decimal(18,2),
qty decimal(18,3),
amount decimal(18,2)
)
here as a example
productid Varchar(10),
unit Varchar(50)
etc i am specifying and also specify their data tyoe & size.
so how could i construct this area dynamically and fetch the column name and data type & size dynamically.
please guide me thanks.
You can get column names(which are nodes inside PurchasePrderDetail node) like this:
declare #xml xml='<NewDataSet><PurchaseOrderDetail>
<productid>19125</productid>
</PurchaseOrderDetail></NewDataSet>'
SELECT b.value('local-name(.)','nvarchar(128)')ColumnName,
LEN(b.value('.','nvarchar(128)'))MaxLength
FROM #xml.nodes('/NewDataSet/PurchaseOrderDetail/*') a(b)
So you can generate dynamic SQL statement to create cursor with appropriate column names and length like varchar(MaxLength).
But you can not get datatypes from XML without knowing real column names because data in xml is just text and f.e. "5" can be int type and also just a text.
EDIT
If you know table name, you can built dynamic SQL statement using metadata from that table using this:
; With cols as(
SELECT COLUMN_NAME,
UPPER(DATA_type)
+
case when data_type like '%char' then
case when CHARACTER_MAXIMUM_LENGTH=-1 THEN ' (MAX)'
else ' ('+CAST(CHARACTER_MAXIMUM_LENGTH as nvarchar)+')'
END
ELSE ''
END ColConv
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME='PurchaseOrderDetail'),
XMLS as(
SELECT b.value('local-name(.)','nvarchar(128)')ColumnName,
b.value('.','nvarchar(128)')Value
FROM #xml.nodes('/NewDataSet/PurchaseOrderDetail/*') a(b)
)
SELECT XMLS.ColumnName,'CAST ('''+XMLS.Value+''' AS '+ ColConv+''')' FROM XMLS
JOIN cols ON XMLS.ColumnName=cols.COLUMN_NAME
As output you will have column name and value with appropriate CAST clause. Then you can build dynamic statement what you need.
Usually the information of data types and field names are describes in the XSD file (XML Schema Definition).
So you need to have a valid XSD file for each of your XML file then you can retrieve the fields name and data type.
Here a link to understand better the XSD
And here how to deal with XSD and XML step by step
Hope it helps you