I have a SQL Server table with a column of type XML
. The XML data represents multiple allowable selections for a given field. An example of the XML data is as follows.
<Values>
<Value>Valid Value 1</Value>
<Value>Valid Value 2</Value>
<Value>Valid Value 3</Value>
<Value>Valid Value 4</Value>
<Value>Valid Value 5</Value>
<Value>Valid Value 6</Value>
...
</Values>
I am using the following code to extract the data from the XML
column and transforming it into rows that can be inserted into a new table.
DECLARE @XmlStuff VARCHAR(4000);
DECLARE @iXmlStuff int;
SELECT @XmlStuff = CAST(C.ValidValues AS VARCHAR(4000))
FROM dbo.ColumnValidations C
WHERE C.[ColumnName] = 'Something';
EXEC sp_xml_preparedocument @iXmlStuff OUTPUT, @XmlStuff;
SELECT *
FROM OPENXML(@iXmlStuff, '/Values/Value', 2)
WITH ([Value] VARCHAR(100) '.');
EXEC sp_xml_removedocument @iXmlStuff;
This code is correctly returning the following
Value
----------------
Valid Value 1
Valid Value 2
Valid Value 3
Valid Value 4
Valid Value 5
Valid Value 6
...
Is this the best way of doing this?
What I have here, I think, will need to be in a stored procedure. Ideally I am looking for a way of doing this where I don't have to worry about losing data because of a buffer overflow due to an unforeseen quantity of data contained in the xml column.
OPENXML()
, and its companions sp_xml_preparedocument/sp_xml_removedocument
is a proprietary Microsoft API. It is kept just for backward
compatibility with the obsolete SQL Server 2000. SQL Server 2005 onwards supports w3c's XQuery 1.0, XPath 2.0, and XSD 1.0.
SQL
-- DDL and sample data population, start
DECLARE @tbl Table (ID INT IDENTITY PRIMARY KEY, xmldata XML);
INSERT INTO @tbl (xmldata) VALUES
(N'<Values>
<Value>Valid Value 1</Value>
<Value>Valid Value 2</Value>
<Value>Valid Value 3</Value>
<Value>Valid Value 4</Value>
<Value>Valid Value 5</Value>
<Value>Valid Value 6</Value>
</Values>');
-- DDL and sample data population, end
SELECT ID
, c.value('.','VARCHAR(100)') AS Result
FROM @tbl CROSS APPLY xmldata.nodes('/Values/Value/text()') AS t(c);
Output
+----+---------------+
| ID | Result |
+----+---------------+
| 1 | Valid Value 1 |
| 1 | Valid Value 2 |
| 1 | Valid Value 3 |
| 1 | Valid Value 4 |
| 1 | Valid Value 5 |
| 1 | Valid Value 6 |
+----+---------------+