To give some background to this problem first, I am rewriting some code that currently loops through some xml, doing an insert to a table at the end of each loop - replacing with a single sp that takes an xml parameter and does the insert in one go, 'shredding' the xml into a table.
The main shred has been done successfully,but currently one of the columns is used to store the entire node. I have been able to work out the query necessary for this (almost), but it misses out the root part of the node. I have come to the conclusion that my query is as good as I can get it, and I am looking at a way to then do an update statement to get the root node back in there.
So my xml is of the form;
<xml>
<Items>
<Item>
<node1>...</node1><node2>..<node2>.....<noden>...<noden>
<Item>
<Item>
<node1>...</node1><node2>..<node2>.....<noden>...<noden>
<Item>
<Item>
<node1>...</node1><node2>..<node2>.....<noden>...<noden>
<Item>
......
<Items>
</xml>
So the basic shredding puts the value from node1 into column1, node2 into column2 etc. The insert statement looks something like;
INSERT INTO mytable col1, col2,...etc.....,wholenodecolumn
Select
doc.col.value('node1[1]', 'int') column1,
doc.col.value('node2[1]', 'varchar(50)') column2,
....etc......,
doc.col.query('*')--this is the query for getting the whole node
FROM @xml.nodes('//Items/Item') doc(col)
The XML that ends up in wholenodecolumn is of the form;
<node1>...</node1><node2>..<node2>.....<noden>...<noden>
but I need it to be of the form
<Item><node1>...</node1><node2>..<node2>.....<noden>...<noden></Item>
There is existing code (a lot of it) that depends on the xml in this column being of the correct form.
So can someone maybe see how to modify the doc.col.query('*')
to get the desired result?
Anyway, I gave up on modifying the query, and tried to think of other ways to accomplish the end result. What I am now looking at is an Update after the insert- something like;
update mytable set wholenodecolumn.modify('insert <Item> as first before * ')
If I could do this along with
.modify('insert </Item> as last after * ')
that would be fine, but doing 1 at a time isn't an option as the XML is then invalid
XQuery [mytable.wholenodecolumn.modify()]: Expected end tag 'Item'
and doing both together I don't know if it's possible but I've tried various syntax and can't get to work.
Any other approaches to the problem also gratefully received
Modifies the contents of an XML document. Use this method to modify the content of an xml type variable or column. This method takes an XML DML statement to insert, update, or delete nodes from XML data. The modify() method of the xml data type can only be used in the SET clause of an UPDATE statement.
You should use the query() Method if you want to get a part of your XML. If you want the value from a specific node you should use value() Method. Update: If you want to shred your XML to multiple rows you use nodes() Method.
To update data in an XML column, use the SQL UPDATE statement. Include a WHERE clause when you want to update specific rows. The entire column value will be replaced. The input to the XML column must be a well-formed XML document.
While a properly formed XML file can only have a single root element, an XSD or DTD file can contain multiple roots. If one of the roots matches that in the XML source file, that root element is used, otherwise you need to select one to use. Choose the root to display. Select the root element you want to use.
I beleive you can specifiy the Root Node name by using the FOR clause.
For example:
select top 1 *
from HumanResources.Department
for XML AUTO, ROOT('RootNodeName')
Take a looks at books online for more details:
http://msdn.microsoft.com/en-us/library/ms190922.aspx
Answering my own question here! - this follows on from the comments to the one of the other attempted answers where I said:
I am currently looking into FLWOR Xquery constructs in the query.
col.query('for $item in * return <Item> {$item} </item>')
is almost there, but puts around each node, rather than around all the nodes
I was almost there with the syntax, a small tweak has given me what I needed;
doc.col.query('<Item> { for $item in * return $item } </item>'
Thankyou to everyone that helped. I have further related issues now but I'll post as separate questions
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With