I've written a CLR assembly that exports a table's data to an XML file. Now I want to import this data into a temp table on another instance.
The XML file structure is like this:
<row>
<SystemInformationID>1</SystemInformationID>
<Database_x0020_Version>10.00.80404.00</Database_x0020_Version>
<VersionDate>2008-04-04T00:00:00</VersionDate>
<ModifiedDate>2008-04-04T00:00:00</ModifiedDate>
</row>
I want the XML to be parsed in the destination location and imported into a temp table. I have the main table there too, so I can get the table structure from there.
Is there a way? I use OPENXML but it seems not to be working correctly. I can read the XML file into a table, which will be stored in a column with XML data type. My problem is parsing the data in that column.
This is a temp attempt:
CREATE TABLE ##T (IntCol int, XmlCol xml)
GO
INSERT INTO ##T(XmlCol)
SELECT * FROM OPENROWSET(
BULK 'c:\HISOutput.xml',
SINGLE_CLOB) AS x
--works correctly up to this point
DECLARE #x xml
DECLARE #id int
SELECT #x=XmlCol FROM ##T
EXEC sp_xml_preparedocument #id OUTPUT, #x
SELECT *
FROM OPENXML (#id,'/row',2)
WITH
dbo.awbuildversion
--I used dbo.awbuildversion table from AdventureWorks DB for testing
this doesn't show the first column no matter how I change the OPENXML instruction.
tx in advance
I'm not quite sure what you want, because your comment to OMG Ponies' answer is different to your question. What is the problem with temp table/table structure?
Anyway, I wouldn't use OPENXML or sp_xml_preparedocument on SQL Server 2050 and above (which you have I assume because you mentioned CLR) because of the memory leak risk.
Also, if you need the table stucture then you could use INTO #tempTable
DECLARE #foo xml
SET #foo = '<row>
<SystemInformationID>1</SystemInformationID>
<Database_x0020_Version>10.00.80404.00</Database_x0020_Version>
<VersionDate>2008-04-04T00:00:00</VersionDate>
<ModifiedDate>2008-04-04T00:00:00</ModifiedDate>
</row>'
SELECT
bar.value('./SystemInformationID[1]','INT') AS 'SystemInformationID',
bar.value('./Database_x0020_Version[1]','VARCHAR(14)') AS 'Database_x0020_Version',
bar.value('./VersionDate[1]','DATETIME') AS 'VersionDate',
bar.value('./ModifiedDate[1]','DATETIME') AS 'ModifiedDate'
INTO #tempTable -- This?
FROM
#foo.nodes('/row') AS foo(bar) --use nodes not OPENXML
Related
I am reading data from XML into a table. When I do select from the table, the table is empty.
SET #INPUTXML = CAST(#Attribute AS XML)
EXEC Sp_xml_preparedocument #TestDoc OUTPUT, #INPUTXML
SELECT Row_Number() OVER (ORDER BY Name) AS Row, *
INTO #tData
FROM OPENXML(#TestDoc, N'/DocumentElement/dtData')
WITH (
ID VARCHAR(100) './ID'
, Name VARCHAR(100) './Name'
, Value VARCHAR(max) './Value'
, Column VARCHAR(100) './Column'
)
EXEC Sp_xml_removedocument #TestDoc
Below are my questions:
select * from #tData is empty table. Why is data not getting populated?
What does Sp_xml_preparedocument do? When I print #TestDoc, it gives me a number
What is Sp_xml_removedocument ?
To answer your questions though.
#tData is empty because your SELECT statement returned no data. A SELECT...INTO statement will still create the table, even if the SELECT returns no rows. Why your SELECT is returning no data is impossible for us to say, because we have no sample data. If you remove the INTO clause you will see that no rows are returned, so you need to fix your SELECT, FROM, etc. but that brings on to my statement in a minute (about using XQUERY)
sp_xml_preparedocument (Transact-SQL) explains better than I could. Really though, you shouldn't be using it anymore, as it was used to read XML back in SQL Server 2000 (maybe 2005) and prior. Certainly SQL Server 2008 supported XQUERY, which you must be at least using if you are using SSMS 2014. To quote the opening statement of the documentation though:
Reads the XML text provided as input, parses the text by using the MSXML parser (Msxmlsql.dll), and provides the parsed document in a state ready for consumption. This parsed document is a tree representation of the various nodes in the XML document: elements, attributes, text, comments, and so on.
sp_xml_removedocument (Transact-SQL), but again, you should be using XQUERY.
Removes the internal representation of the XML document specified by the document handle and invalidates the document handle.
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
I have an XML document containing data that I want to import into existing SQL server tables:
<?xml version="1.0" encoding="UTF-8"?>
<geia:GEIA-STD-0007 xmlns:geia="http://www.geia_STD_0007.com/2006/schema" xmlns:xsi=`enter code here`"http://www.w3.org/2001/XMLSchema-instance">
<geia:full_file>
<geia:XA_end_item_acronym_code_data>
<geia:end_item_acronym_code>ON565</geia:end_item_acronym_code>
<geia:logistics_support_analysis_control_number_structure>32222222</geia:logistics_support_analysis_control_number_structure>
</geia:XA_end_item_acronym_code_data>
<geia:XB_logistics_support_analysis_control_number_indentured_item_data>
<geia:end_item_acronym_code>ON565</geia:end_item_acronym_code>
<geia:logistics_support_analysis_control_number>E2C06CAAE</geia:logistics_support_analysis_control_number>
<geia:alternate_logistics_support_analysis_control_number_code>06</geia:alternate_logistics_support_analysis_control_number_code>
<geia:logistics_support_analysis_control_number_type>P</geia:logistics_support_analysis_control_number_type>
<geia:logistics_support_analysis_control_number_nomenclature>CABLE ASSEMBLY W5</geia:logistics_support_analysis_control_number_nomenclature>
<geia:reliability_availability_and_maintainability_indicator>Y</geia:reliability_availability_and_maintainability_indicator>
<geia:system_end_item_identifier>N</geia:system_end_item_identifier>
<geia:technical_manual_functional_group_code>41JE150</geia:technical_manual_functional_group_code>
</geia:XB_logistics_support_analysis_control_number_indentured_item_data>
<geia:XB_logistics_support_analysis_control_number_indentured_item_data>
<geia:end_item_acronym_code>ON565</geia:end_item_acronym_code>
<geia:logistics_support_analysis_control_number>E2C06CAAMZZ</geia:logistics_support_analysis_control_number>
<geia:alternate_logistics_support_analysis_control_number_code>06</geia:alternate_logistics_support_analysis_control_number_code>
<geia:logistics_support_analysis_control_number_type>P</geia:logistics_support_analysis_control_number_type>
<geia:logistics_support_analysis_control_number_nomenclature>CONSUMABLES</geia:logistics_support_analysis_control_number_nomenclature>
<geia:system_end_item_identifier>N</geia:system_end_item_identifier>
</geia:XB_logistics_support_analysis_control_number_indentured_item_data>
</geia:full_file>
</geia:GEIA-STD-0007>
I have been looking online for code that can help me accomplish this task but have not had much luck. So far this is the code I have been trying to use:
----step 1 Import XML data from an XML file into SQL Server table using the OPENROWSET function
drop table lsa.XMLwithOpenXML
CREATE TABLE lsa.XMLwithOpenXML
(
Id INT IDENTITY PRIMARY KEY,
XMLData XML,
LoadedDateTime DATETIME
)
INSERT INTO lsa.XMLwithOpenXML(XMLData, LoadedDateTime)
SELECT CONVERT(XML, BulkColumn) AS BulkColumn, GETDATE()
FROM OPENROWSET(BULK 'D:\Temp\e2c.xml', SINGLE_CLOB) AS x;
--SELECT * FROM lsa.XMLwithOpenXML
--get xmldata to shred
-------------------------------------------------------------------------
Declare #xmlData as xml
Select #xmlData = XMLData FROM lsa.XMLwithOpenXML
------------------------------------------------------------
--create variable to hold the int id of the xmldoc created by the sp
DECLARE #XMLdocId AS INT
--procedureName, outputId, InputData
EXEC sp_xml_preparedocument #XMLdocId OUTPUT, #xmlData , '<geia:GEIA-STD-0007 xmlns:geia="http://www.geia_STD_0007.com/2006/schema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">'
--create an OenXML query to shred the doc, or transfer it into rowsets
INSERT INTO [lsa].[XB]
(
[end_item_acronym_code])
Select end_item_acronym_code from
OpenXML(#XMLdocId, '/geia:XB_logistics_support_analysis_control_number_indentured_item_data',2)
;WITH XMLNAMESPACES ('xmlns:geia="http://www.geia_STD_0007.com/2006/schema' AS geia, DEFAULT 'http://www.w3.org/2001/XMLSchema-instance' )
SELECT
x.c( '.' ) AS result
FROM #xmlData.nodes('geia:GEIA-STD-0007/geia:full_file/geia:XB_logistics_support_analysis_control_number_indentured_item_data') x(c)
EXEC sp_xml_removedocument #XMLdocId
I realize that this code is very wrong. The path that I am passing to the OpenXML() function is wrong, but I have tried many iterations of it and none have been successful. I am also not 100% certain how to go about pulling out the different table data (ie XA, XB) but my plan is to pull from one table then reiterate the code for each additional table. This code will be used to import large amounts of data (I only posted a part of the xml file) with many different tables. If anyone has a better idea, then I would welcome it, as I am still learning.
My question is similar to this one: Choose a XML node in SQL Server based on max value of a child element
except that my column is NOT of type XML, it's of type nvarchar(max).
I want to extract the XML node values from a column that looks like this:
<Data>
<el1>1234</el1>
<el2>Something</el2>
</Data>
How can I extract the values '1234' and 'Something' ?
doing a convert and using the col.nodes is not working.
CONVERT(XML, table1.col1).value('(/Data/el1)[1]','int') as 'xcol1',
After that, I would like to do a compare value of el1 (1234) with another column, and update update el1 as is. Right now I'm trying to just rebuild the XML when passing the update:
ie
Update table set col1 ='<Data><el1>'+#col2+'</el1><el2>???</el2>
You've got to tell SQL Server the number of the node you're after, like:
(/Data/el1)[1]
^^^
Full example:
declare #t table (id int, col1 varchar(max))
insert #t values (1, '<Data><el1>1234</el1><el2>Something</el2></Data>')
select CAST(col1 as xml).value('(/Data/el1)[1]', 'int')
from #t
-->
1234
SQL Server provides a modify function to change XML columns. But I think you can only use it on columns with the xml type. Here's an example:
declare #q table (id int, col1 xml)
insert #q values (1, '<Data><el1>1234</el1><el2>Something</el2></Data>')
update #q
set col1.modify('replace value of (/Data/el1/text())[1] with "5678"')
select *
from #q
-->
<Data><el1>5678</el1><el2>Something</el2></Data>
At the end of the day, SQL Server's XML support makes simple things very hard. If you value maintainability, you're better off processing XML on the client side.
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