This seemed like a great idea on Friday afternoon but I'm having a bit of trouble. I've not used SQL XML querying before so I may of just done something incredibly stupid. Basically I want to pass a series of strings to query a table into a Stored Procedure.
I thought about this for a bit, considered using a CSV and then decided to attempt to do this using XML. So My XML looks like:
<Root>
<string>value</string>
<string>value</string>
<string>value</string>
<string>value</string>
</Root>
I'm passing this into a stored proc as an XML value type:
CREATE PROCEDURE usp_UpdateHotelImages
-- Add the parameters for the stored procedure here
#hotelID int,
#imageIDs xml
AS
BEGIN
so I want to shred the XML into a table of strings.
My SQL looks like this:
SELECT Child.value('(string)[1]', 'varchar(200)')
FROM #imageIDs.nodes('/Root/') AS N(Child))
But I keep getting the error message XQuery [nodes()]: Syntax error near '<eof>', expected a "node test".
I may well be doing something incredibly stupid here so any help will be gratefully received.
Update
I've broken it down into a single query to help:
DECLARE #imageIDs xml
SET #imageIDs = '<Root>
<string>value</string>
<string>value</string>
<string>value</string>
<string>value</string>
</Root>'
SELECT Child.value('(string)[1]', 'varchar(200)')
FROM #imageIDs.nodes('/Root/') AS N(Child)
The problem is the last / in the nodes function.
SELECT Child.value('(string)[1]', 'varchar(200)')
FROM #imageIDs.nodes('/Root') AS N(Child)
or alternatively
SELECT Child.value('(.)[1]', 'varchar(200)')
FROM #imageIDs.nodes('/Root/*') AS N(Child)
Depending on what you're trying to achieve.
The error is because of trailing / in your nodes expressions. It should just be /Root.
BTW, I think you are looking for a SELECT to return the values as a table which is achieved by the following:
DECLARE #imageIDs XML
SELECT #imageIDs = '
<Root>
<string>value</string>
<string>value2</string>
<string>value3</string>
<string>value4</string>
</Root>'
SELECT
Child.value('(.)[1]', 'varchar(200)')
FROM #imageIDs.nodes('/Root/string') AS N(Child)
Results:
value
value2
value3
value4
(4 row(s) affected)
Related
I'm trying to get the result of an executed stored procedure to be retrieved as a XML of the table the result is shown as originally.
What I'm trying to do is somthing like this.
exec dbo.StoredProcedure FOR XML RAW, ROOT ('root_name').
Lets say exec dbo.StoredProcedure returns the table in the Stored Procedure,
I want the FOR XML RAW, ROOT ('root_name') to return the XML value of that whole result.
How do I achieve this In SQL server?
One method is to insert the proc results into a temp table or variable using INSERT...EXEC and then select from that table with the desired FOR XML query:
DECLARE #results AS TABLE(col1 int, col2 int);
INSERT INTO #results EXEC dbo.StoredProcedure;
SELECT col1, col2
FROM #results
FOR XML RAW, ROOT ('root_name');
As per this question, you should not select from the stored procedure. Also if you dig into that question, you will find a link to an interesting article describing options you have with stored procedures.
If I were you I would either return an XML with an output parameter, or insert-exec into a table and then query it with for xml.
I have the following xml stored in my database table.
I am trying to extract the Productid from the xml , I have been unsuccessful.
Could you tell me what changes I need to make to make the query work ?
XML :
DECLARE #Response VARCHAR(MAX) = '<Response xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<ProductId xsi:type="xsd:long" xmlns="http://nn.service.eservice_v1">30061</ProductId>
</Response>'
Sql Query :
select
CONVERT(XML,CONVERT(NVARCHAR(max),#Response)).value('(/Response/ProductId)[1]','nvarchar(500)') as ProviderId
You want to store the XML in an XML type instead of converting from varchar. If you are able to strip out all the namespace stuff, the following will work.
DECLARE #Response XML = '<Response><ProductId>30061</ProductId></Response>'
SELECT #Response.value('(//ProductId)[1]','nvarchar(500)') as ProviderId
If you are not able to strip out all the namespace stuff, then you will need to include the WITH XMLNAMESPACES clause
DECLARE #Response XML = '<Response xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<ProductId xsi:type="xsd:long" xmlns="http://nn.service.eservice_v1">30061</ProductId>
</Response>'
;WITH XMLNAMESPACES ('http://nn.service.eservice_v1' as e,
'http://www.w3.org/2001/XMLSchema-instance' as xsi)
SELECT #Response.value('(/Response/e:ProductId)[1]','nvarchar(500)') as ProviderId
I am having an issue in a SQL procedure and I can't seem to find the proper solution.
The stored procedure is containing one parameter of the XML datatype (name = #data).
An example of the incoming message is the following (the actual message is containing a lot more nodes, but I left them out for simplicity):
<Suppliers xmlns="">
<Supplier>
<IDCONO>3</IDCONO>
<IDSUNO>009999</IDSUNO>
<IDSUTY>0</IDSUTY>
</Supplier>
</Suppliers>
In my SQL database I have a table called "Supplier" and it contains the exact same columns as the nodes in the XML (IDCONO, IDSUNO, IDSUTY,..)
I need to loop over the nodes and insert the data in the columns.
I have implemented the procedure below, but this is giving me a lot of perfomance issues on the bigger files (long processing time, even timeouts):
INSERT INTO SUPPLIER
(IDCONO
,IDSUNO
,IDSUTY)
SELECT
T.C.value('IDCONO[1]', 'VARCHAR(50)') as IDCONO,
T.C.value('IDSUNO[1]', 'VARCHAR(50)') as IDSUNO,
T.C.value('IDSUTY[1]', 'VARCHAR(50)') as IDSUTY
from #data.nodes('/Suppliers/Supplier') T(C)
Any help is appreciated!
Note that the SQL version is SQL server 2012.
Thanks in advance.
The first I would try is the specify the text() node when using the XML datatype to prevent SQL Server from doing a deep search for text elements.
INSERT INTO SUPPLIER
(IDCONO
,IDSUNO
,IDSUTY)
SELECT
T.C.value('(IDCONO/text())[1]', 'VARCHAR(50)') as IDCONO,
T.C.value('(IDSUNO/text())[1]', 'VARCHAR(50)') as IDSUNO,
T.C.value('(IDSUTY/text())[1]', 'VARCHAR(50)') as IDSUTY
FROM #data.nodes('/Suppliers/Supplier') T(C)
If that is not good enough I would try OPENXML instead.
DECLARE #idoc INT
EXEC sp_xml_preparedocument #idoc OUT, #data
INSERT INTO SUPPLIER
(IDCONO
,IDSUNO
,IDSUTY)
SELECT IDCONO, IDSUNO, IDSUTY
FROM OPENXML(#idoc, '/Suppliers/Supplier', 2) WITH
(IDCONO VARCHAR(50),
IDSUNO VARCHAR(50),
IDSUTY VARCHAR(50))
EXEC sp_xml_removedocument #idoc
I have a sample table in SQL Server 2012. I am running some queries against but the .modify() XQuery method is executing but not updating.
Here is the table
For this just trying to update settings to 'NewTest'
This will execute but nothing is updating! Thanks for any help!
Since there is a XML namespace (xmlns:dev="http://www.w3.org/2001/XMLSchema") in your XML document, you must inlcude that in your UPDATE statement!
Try this:
;WITH XMLNAMESPACES(DEFAULT 'http://www.w3.org/2001/XMLSchema')
UPDATE XmlTable
SET XmlDocument.modify('replace value of (/Doc/#Settings)[1] with "NewTest"')
WHERE XmlId = 1
You should declare a namespace in your update syntax .Try the below syntax
Declare #Sample table
(xmlCol xml)
Insert into #Sample
values
('<dev:Doc xmlns:dev="http://www.w3.org/2001/XMLSchema"
SchemaVersion="0.1" Settings="Testing" Ttile="Ordering">
<Person id="1">
<FirstName>Name</FirstName>
</Person>
</dev:Doc>')
Select * from #Sample
Update #Sample
SET xmlCol.modify(
'declare namespace ns="http://www.w3.org/2001/XMLSchema";
replace value of (/ns:Doc/#Settings)[1]
with "NewTest"')
Select * from #Sample
I have been hearing the podcast blog for a while, I hope I dont break this.
The question is this: I have to insert an xml to a database. This will be for already defined tables and fields. So what is the best way to accomplish this? So far I am leaning toward programatic. I have been seeing varios options, one is Data Transfer Objects (DTO), in the SQL Server there is the sp_xml_preparedocument that is used to get transfer XMLs to an object and throught code.
I am using CSharp and SQL Server 2005. The fields are not XML fields, they are the usual SQL datatypes.
In an attempt to try and help, we may need some clarification. Maybe by restating the problem you can let us know if this is what you're asking:
How can one import existing xml into a SQL 2005 database, without relying on the built-in xml type?
A fairly straight forward solution that you already mentioned is the sp_xml_preparedocument, combined with openxml.
Hopefully the following example illustrates the correct usage. For a more complete example checkout the MSDN docs on Using OPENXML.
declare #XmlDocumentHandle int
declare #XmlDocument nvarchar(1000)
set #XmlDocument = N'<ROOT>
<Customer>
<FirstName>Will</FirstName>
<LastName>Smith</LastName>
</Customer>
</ROOT>'
-- Create temp table to insert data into
create table #Customer
(
FirstName varchar(20),
LastName varchar(20)
)
-- Create an internal representation of the XML document.
exec sp_xml_preparedocument #XmlDocumentHandle output, #XmlDocument
-- Insert using openxml allows us to read the structure
insert into #Customer
select
FirstName = XmlFirstName,
LastName = XmlLastName
from openxml ( #XmlDocumentHandle, '/ROOT/Customer',2 )
with
(
XmlFirstName varchar(20) 'FirstName',
XmlLastName varchar(20) 'LastName'
)
where ( XmlFirstName = 'Will' and XmlLastName = 'Smith' )
-- Cleanup xml document
exec sp_xml_removedocument #XmlDocumentHandle
-- Show the data
select *
from #Customer
-- Drop tmp table
drop table #Customer
If you have an xml file and are using C#, then defining a stored procedure that does something like the above and then passing the entire xml file contents to the stored procedure as a string should give you a fairly straight forward way of importing xml into your existing table(s).
If your XML conforms to a particular XSD schema, you can look into using the "xsd.exe" command line tool to generate C# object classes that you can bind the XML to, and then form your insert statements using the properties of those objects: MSDN XSD Doc
Peruse this document and it will give you the options:
MSDN: XML Options in Microsoft SQL Server 2005
You may want to use XSLT to transfer your XML into SQL statements... ie
<xml type="user">
<data>1</data>
<data>2</data>
<xml>
Then the XSLT would look like
<xsl:template match="xml">
INSERT INTO <xsl:value-of select="#type" /> (data1, data2) VALUES (
'<xsl:value-of select="data[1]" />',
'<xsl:value-of select="data[2]" />');
</xsl:template>
The match statement most likely won't be the root node, but hopefully you get the idea. You may also need to wrap the non xsl:value-of parts in xsl:text to prevent extra characters from being dumped into the query. And you'd have to make sure the output of the XSLT was text. That said you could get a list of SQL statements that you could run through the DB. or you could use XSLT to output a T-SQL statement that you could load as a stored procedure.