{"id":1253,"date":"2011-12-08T00:00:00","date_gmt":"2011-12-08T00:00:00","guid":{"rendered":"https:\/\/test.simple-talk.com\/uncategorized\/the-xml-methods-in-sql-server\/"},"modified":"2026-04-30T09:21:08","modified_gmt":"2026-04-30T09:21:08","slug":"the-xml-methods-in-sql-server","status":"publish","type":"post","link":"https:\/\/www.red-gate.com\/simple-talk\/databases\/sql-server\/learn\/the-xml-methods-in-sql-server\/","title":{"rendered":"SQL Server XML Methods: query(), value(), exist(), nodes(), modify()"},"content":{"rendered":"<div id=\"pretty\">\n<p><strong>SQL Server&#8217;s XML data type supports five built-in methods for working with XML content: query() returns a subset of XML matching an XQuery expression; value() returns a scalar value from a specific XML node converted to a T-SQL data type; exist() returns 1 or 0 indicating whether a node or value exists; nodes() shreds XML into a relational rowset that can be joined or aggregated; modify() updates XML in place with insert, replace, or delete operations. <\/strong><\/p>\n<p><strong>All five methods take an XQuery expression as their argument; value() also takes a T-SQL type, and nodes() also takes a table alias. This article demonstrates each method with a working example against a sample Stores table containing both typed and untyped XML columns.<\/strong><\/p>\n<p>In my last article, &#8220;<a href=\"http:\/\/www.simple-talk.com\/sql\/learn-sql-server\/working-with-the-xml-data-type-in-sql-server\/\">Working with the XML Data Type in SQL Server<\/a>,&#8221; I included examples that returned data from columns and variables of the <b><code>XML<\/code><\/b> data type. Based on those examples, it might seem that retrieving XML data is similar to retrieving objects configured with other data types. However, that&#8217;s true only when returning the entire XML value. If instead you want to work with individual components within an XML instance, such as \u00a0when retrieving the value of a single attribute, you must use one of the five methods that available to the <b><code>XML<\/code><\/b> data type-<b><code>query()<\/code><\/b>, <b><code>value()<\/code><\/b>, <b><code>exist()<\/code><\/b>, <b><code>nodes()<\/code><\/b>, or <b><code>modify()<\/code><\/b>.<\/p>\n<p>To use an <b><code>XML<\/code><\/b> method, you call it in association with the database object configured with the <b><code>XML<\/code><\/b> data type, as the following syntax illustrates:<\/p>\n<pre>DbObject.XmlMethod('XQuery'[, 'SqlType']) [AS TableAlias(ColumnAlias)]\n<\/pre>\n<p>The <i>DbObject <\/i>placeholder refers to a column, variable, or parameter configured with the <b><code>XML<\/code><\/b> data type. After the object name, you add a period, following by the name of the <b><code>XML<\/code><\/b> method. Next you provide, in parentheses, the arguments required for the specific method.<\/p>\n<p>Most of the <b><code>XML<\/code><\/b> methods require only one argument: an XQuery expression that identifies the XML components to be retrieved or modified, and any actions to be taken on those components. XQuery, a powerful scripting language used specifically to access XML data, contains the elements necessary to create complex expressions that can include functions, operators, variables, and values. MSDN provides a complete <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/ms189075.aspx\">XQuery language reference<\/a> that you can refer to while you work with the <b><code>XML<\/code><\/b> methods.<\/p>\n<p>In addition to the XQuery expression, an <b><code>XML<\/code><\/b> method might also require a Transact-SQL data type as a second argument or a table and column alias tagged on after the arguments. As we work through the article, you&#8217;ll see when and why these additional components are necessary.<\/p>\n<p>To demonstrate how the various <b><code>XML<\/code><\/b> methods work, I&#8217;ve written a number of examples that use the methods to retrieve and modify data. The examples are based on the <b><code>Stores<\/code><\/b> table, which I created and populated with the following Transact-SQL script:<\/p>\n<pre class=\"theme:ssms2012 lang:tsql\">USE AdventureWorks2008R2\nGO\n\u00a0\nIF OBJECT_ID('Stores') IS NOT NULL\nDROP TABLE Stores\nGO\n\u00a0\nCREATE TABLE Stores\n(\n\u00a0 StoreID INT PRIMARY KEY,\n\u00a0 Survey_untyped XML,\n\u00a0 Survey_typed XML(Sales.StoreSurveySchemaCollection)\n);\n\u00a0\n\u00a0INSERT INTO Stores\n\u00a0VALUES\n\u00a0(\n\u00a0\u00a0 292,\n\u00a0 '&lt;StoreSurvey&gt;\n\u00a0\u00a0\u00a0 &lt;AnnualSales&gt;800000&lt;\/AnnualSales&gt;\n\u00a0\u00a0\u00a0 &lt;AnnualRevenue&gt;80000&lt;\/AnnualRevenue&gt;\n\u00a0\u00a0\u00a0 &lt;BankName&gt;United Security&lt;\/BankName&gt;\n\u00a0\u00a0\u00a0 &lt;BusinessType&gt;BM&lt;\/BusinessType&gt;\n\u00a0\u00a0\u00a0 &lt;YearOpened&gt;1996&lt;\/YearOpened&gt;\n\u00a0\u00a0\u00a0 &lt;Specialty&gt;Mountain&lt;\/Specialty&gt;\n\u00a0\u00a0\u00a0 &lt;SquareFeet&gt;21000&lt;\/SquareFeet&gt;\n\u00a0\u00a0\u00a0 &lt;Brands&gt;2&lt;\/Brands&gt;\n\u00a0\u00a0\u00a0 &lt;Internet&gt;ISDN&lt;\/Internet&gt;\n\u00a0\u00a0\u00a0 &lt;NumberEmployees&gt;13&lt;\/NumberEmployees&gt;\n\u00a0\u00a0\u00a0 &lt;Products Type=\"Bikes\"&gt;\n\u00a0\u00a0\u00a0\u00a0\u00a0 &lt;Product&gt;Mountain&lt;\/Product&gt;\n\u00a0\u00a0\u00a0\u00a0\u00a0 &lt;Product&gt;Road&lt;\/Product&gt;\n\u00a0\u00a0\u00a0\u00a0\u00a0 &lt;Product&gt;Racing&lt;\/Product&gt;\n\u00a0\u00a0\u00a0 &lt;\/Products&gt;\n\u00a0\u00a0\u00a0 &lt;Products Type=\"Clothes\"&gt;\n\u00a0\u00a0\u00a0\u00a0\u00a0 &lt;Product&gt;Jerseys&lt;\/Product&gt;\n\u00a0\u00a0\u00a0\u00a0\u00a0 &lt;Product&gt;Jackets&lt;\/Product&gt;\n\u00a0\u00a0\u00a0\u00a0\u00a0 &lt;Product&gt;Shorts&lt;\/Product&gt;\n\u00a0\u00a0\u00a0 &lt;\/Products&gt;\n\u00a0 &lt;\/StoreSurvey&gt;',\n\u00a0 (SELECT Demographics FROM Sales.Store\n\u00a0\u00a0 WHERE BusinessEntityID = 292)\n);\n\u00a0\n<\/pre>\n<p>Notice that the table includes the <b><code>Survey_untyped<\/code><\/b> column, which is an <b><code>XML<\/code><\/b> untyped column, and the <b><code>Survey_typed<\/code><\/b> column, which is an <b><code>XML<\/code><\/b> typed column. The schema collection I associated with the typed column is already included in the <b><code>AdventureWorks2008R2<\/code><\/b> database, which is where I&#8217;ve created the table. The <b><code>INSERT<\/code><\/b> statement in the Transact-SQL above also shows the XML document that I added to the untyped column. For the typed column, I retrieved the following XML document from the <b><code>Demographics<\/code><\/b> column (a typed <b><code>XML<\/code><\/b> column) in the <b><code>Sales.Store<\/code><\/b> table in the <b><code>AdventureWorks2008R2<\/code><\/b> database:<\/p>\n<pre class=\"theme:ssms2012 lang:tsql\">&lt;StoreSurvey xmlns=\"http:\/\/schemas.microsoft.com\/sqlserver\/2004\/07\/adventure-works\/StoreSurvey\"&gt;\n\u00a0 &lt;AnnualSales&gt;800000&lt;\/AnnualSales&gt;\n\u00a0 &lt;AnnualRevenue&gt;80000&lt;\/AnnualRevenue&gt;\n\u00a0 &lt;BankName&gt;United Security&lt;\/BankName&gt;\n\u00a0 &lt;BusinessType&gt;BM&lt;\/BusinessType&gt;\n\u00a0 &lt;YearOpened&gt;1996&lt;\/YearOpened&gt;\n\u00a0 &lt;Specialty&gt;Mountain&lt;\/Specialty&gt;\n\u00a0 &lt;SquareFeet&gt;21000&lt;\/SquareFeet&gt;\n\u00a0 &lt;Brands&gt;2&lt;\/Brands&gt;\n\u00a0 &lt;Internet&gt;ISDN&lt;\/Internet&gt;\n\u00a0 &lt;NumberEmployees&gt;13&lt;\/NumberEmployees&gt;\n&lt;\/StoreSurvey&gt;\n\u00a0\n<\/pre>\n<p>Notice that the XML includes the schema associated with that data. The schema comes from the same schema collection I used when I created the typed column in the <b><code>Stores<\/code><\/b> table.<\/p>\n<p>The data I added to the untyped column is nearly identical to the typed XML. The untyped XML doesn&#8217;t include the namespace information, of course. However, it does include additional product information, which we&#8217;ll use to demonstrate the <b><code>XML<\/code><\/b> methods. So now that we have setup out of the way, let&#8217;s look at how those methods work.<\/p>\n<h1>The query() method<\/h1>\n<p>The <b><code>query()<\/code><\/b> method retrieves a subset of untyped XML from the target XML instance. It&#8217;s probably the simplest and most straightforward of the XML methods. You need only specify the database object, the method name, and an XQuery expression, as shown in the following syntax:<\/p>\n<pre>DbObject.query('XQuery')\n<\/pre>\n<p>You&#8217;ll notice that the XQuery expression is entirely enclosed in single quotes and those are enclosed in parentheses. The trick with any XML method is to get the XQuery expression right. But at its simplest, the expression must define the path of the element you want to retrieve.<\/p>\n<p>In the following example, I use the <b><code>query()<\/code><\/b> method to return data from the <b><code>&lt;StoreSurvey&gt;<\/code><\/b> element in both the typed and untyped columns:<\/p>\n<pre class=\"theme:ssms2012 lang:tsql\">SELECT\n\u00a0 Survey_untyped.query('\/StoreSurvey') \n\u00a0\u00a0\u00a0 AS Info_untyped,\n\u00a0 Survey_typed.query('declare namespace \n\u00a0\u00a0\u00a0 ns=\"http:\/\/schemas.microsoft.com\/sqlserver\/2004\/07\/adventure-works\/StoreSurvey\";\n\u00a0\u00a0\u00a0 \/ns:StoreSurvey') AS Info_typed\nFROM\n\u00a0 Stores;\n\u00a0\n<\/pre>\n<p>For the untyped column, I specified the column name (<b><code>Survey_untyped<\/code><\/b>) followed by a period and then the method name (<b><code>query<\/code><\/b>). Within the parentheses and single quotes, I defined the XQuery expression (<b><code>\/StoreSurvey<\/code><\/b>). That&#8217;s all there is to it. Because the <b><code>&lt;StoreSurvey&gt;<\/code><\/b> element is the root node, the entire XML document is returned.<\/p>\n<p>The XQuery expression for the <b><code>Survey_typed<\/code><\/b> column is a bit more complex. Because it is a typed column, the expression should be preceded by a namespace declaration. The namespace must be the same as the one referenced within the XML document stored in the typed column.<\/p>\n<p>To declare a namespace, you specify the <b><code>declare namespace<\/code><\/b> keywords, followed by the alias name (in this case, <b><code>ns<\/code><\/b>). After the alias, you include an equal sign (<b><code>=<\/code><\/b>) and then the schema path and name. You then end the declaration with a semi-colon (<b><code>;<\/code><\/b>) to separate it from the main body of the XQuery expression. After you declare the namespace, you can use the alias within the expression to reference that namespace.<\/p>\n<p>The expression itself is nearly identical to the one used for the untyped column, except that you must precede the element name with the namespace alias and a colon (<b><code>ns:<\/code><\/b>). As with the untyped column, the expression will return the entire XML document because it specifies only the root node.<\/p>\n<p>Although the preceding example is helpful in demonstrating the basics of using the <b><code>query()<\/code><\/b> method, it&#8217;s not much use beyond that because you can just as easily retrieve all the column contents simply by specifying the column name. However, in the following example, I get more specific by limiting the results to the <b><code>&lt;AnnualSales&gt;<\/code><\/b> child element:<\/p>\n<pre class=\"theme:ssms2012 lang:tsql\">SELECT\n\u00a0 Survey_untyped.query('\/StoreSurvey\/AnnualSales') \n\u00a0\u00a0\u00a0 AS Info_untyped,\n\u00a0 Survey_typed.query('declare namespace \n\u00a0\u00a0\u00a0 ns=\"http:\/\/schemas.microsoft.com\/sqlserver\/2004\/07\/adventure-works\/StoreSurvey\";\n\u00a0\u00a0\u00a0 \/ns:StoreSurvey\/ns:AnnualSales') AS Info_typed\nFROM\n\u00a0 Stores;\n\u00a0\n<\/pre>\n<p>The only difference between this example and the preceding one is that I added <b><code>\/AnnualSales<\/code><\/b> to the XQuery expression for the untyped column and <b><code>\/ns:AnnualSales<\/code><\/b> to the expression for the typed column. The XQuery for the untyped column returns the following results.<\/p>\n<pre>&lt;AnnualSales&gt;800000&lt;\/AnnualSales&gt;\n<\/pre>\n<p>And the XQuery for the typed column returns these results:<\/p>\n<pre>&lt;ns:AnnualSales xmlns:ns=\"http:\/\/schemas.microsoft.com\/sqlserver\/2004\/07\/adventure-works\/StoreSurvey\"&gt;800000&lt;\/ns:AnnualSales&gt;\n<\/pre>\n<p>The primary difference between the two is that the data returned by the typed column includes the namespace information. The element values themselves (800000) are the same in both columns. If the <b><code>&lt;AnnualSales&gt;<\/code><\/b> element had included its own child elements, those too would have been displayed. For instance, the following example retrieves the <b><code>&lt;Products&gt;<\/code><\/b> elements, which are child elements of <b><code>&lt;StoreSurvey&gt;<\/code><\/b>, just like <b><code>&lt;AnnualSales&gt;<\/code><\/b>:<\/p>\n<pre class=\"theme:ssms2012 lang:tsql\">SELECT\n\u00a0 Survey_untyped.query('\/StoreSurvey\/Products') \n\u00a0\u00a0\u00a0 AS Products\nFROM\n\u00a0 Stores;\n\u00a0\n<\/pre>\n<p>Because the XML document includes two <b><code>&lt;Products&gt;<\/code><\/b> elements and those elements each include several <b><code>&lt;Product&gt; <\/code><\/b>child elements, the <b><code>SELECT<\/code><\/b> statement returns all product-related elements, as shown in the following results:<\/p>\n<pre>&lt;Products Type=\"Bikes\"&gt;\n\u00a0 &lt;Product&gt;Mountain&lt;\/Product&gt;\n\u00a0 &lt;Product&gt;Road&lt;\/Product&gt;\n\u00a0 &lt;Product&gt;Racing&lt;\/Product&gt;\n&lt;\/Products&gt;\n&lt;Products Type=\"Clothes\"&gt;\n\u00a0 &lt;Product&gt;jerseys&lt;\/Product&gt;\n\u00a0 &lt;Product&gt;jackets&lt;\/Product&gt;\n\u00a0 &lt;Product&gt;shorts&lt;\/Product&gt;\n&lt;\/Products&gt;\n<\/pre>\n<p>If you want to return a specific element and its child elements, you can do so by referencing one of its attributes. For example, suppose you want to include only products from the Bikes category. To do so, you can modify your XQuery expression as follows:<\/p>\n<pre class=\"theme:ssms2012 lang:tsql\">SELECT\n\u00a0 Survey_untyped.query('\/StoreSurvey\/Products[@Type=\"Bikes\"]') \n\u00a0\u00a0\u00a0 AS BikeProducts\nFROM\n\u00a0 Stores;\n<\/pre>\n<p>Now the XQuery expression includes bracketed information that specifies the <b><code>Type<\/code><\/b> attribute and its value. The attribute name is preceded by the at (<b><code>@<\/code><\/b>) symbol, and the attribute value is preceded by an equal sign (<b><code>=<\/code><\/b>) and enclosed in double quotes. As a result, the <b><code>SELECT<\/code><\/b> statement now returns the following XML fragment:<\/p>\n<pre class=\"theme:ssms2012 lang:tsql\">&lt;Products Type=\"Bikes\"&gt;\n\u00a0 &lt;Product&gt;Mountain&lt;\/Product&gt;\n\u00a0 &lt;Product&gt;Road&lt;\/Product&gt;\n\u00a0 &lt;Product&gt;Racing&lt;\/Product&gt;\n&lt;\/Products&gt;\n\u00a0\n<\/pre>\n<p>As you would expect, only elements whose products are in the Bikes category are returned. You could have just as easily specified &#8220;Clothes&#8221; rather than &#8220;Bikes,&#8221; and you would have received the product elements related to clothing.<\/p>\n<h1>The value() method<\/h1>\n<p>The <b><code>value()<\/code><\/b> method returns a scalar value from the targeted XML document. The returned value is converted to the data type you specify when you call the method. The <b><code>value()<\/code><\/b> method makes it easier to work with individual values in order to compare or combine them, either with other XML values or values of different types.<\/p>\n<p>As the following syntax illustrates, when you call the <b><code>value()<\/code><\/b> method, you must specify the XQuery expression and the Transact-SQL data type for the returned data:<\/p>\n<pre>DbObject.value('XQuery', 'SqlType')\n<\/pre>\n<p>For example, suppose you want to pull the amount of sales from the <b><code>&lt;AnnualSales&gt;<\/code><\/b> element in either the typed or untyped column in the <b><code>Stores<\/code><\/b> table. You can specify the path in the XQuery expression plus a numerical data type as the second argument, as shown in the following <b><code>SELECT<\/code><\/b> statement:<\/p>\n<pre class=\"theme:ssms2012 lang:tsql\">SELECT\n\u00a0 Survey_untyped.value('(\/StoreSurvey\/AnnualSales)[1]', 'int') \n\u00a0\u00a0\u00a0 AS Sales_untyped,\n\u00a0 Survey_typed.value('declare namespace \n\u00a0\u00a0\u00a0 ns=\"http:\/\/schemas.microsoft.com\/sqlserver\/2004\/07\/adventure-works\/StoreSurvey\";\n\u00a0\u00a0\u00a0 (\/ns:StoreSurvey\/ns:AnnualSales)[1]', 'int') AS Sales_typed\nFROM\n\u00a0 Stores;\n\u00a0\n<\/pre>\n<p>For the untyped column, the XQuery expression includes the element path as you saw in earlier examples. However, after the path, you must add an integer in brackets that indicates which element of that name you should retrieve. More often than not, you will simply add <b><code>[1]<\/code><\/b>, as I&#8217;ve done here. This assures that, if there are multiple elements with the same name, only the first one will be returned. It also assures that only one element is being referenced at a time. In fact, even when there is only one element, as is the case with <b><code>&lt;AnnualSales&gt;<\/code><\/b>, you must still include the <b><code>[1]<\/code><\/b> because the <b><code>value()<\/code><\/b> method expects a singleton value.<\/p>\n<p>The second argument passed into the <b><code>value()<\/code><\/b> method is the name of the data type, in this case, <b><code>int<\/code><\/b>. That means an <b><code>int<\/code><\/b> value will be returned by the method. Note that the method&#8217;s two arguments must each be enclosed in single quotes and separated with a comma.<\/p>\n<p>As for the typed column, the namespace declaration and path are also similar to what you&#8217;ve seen in earlier examples. The only difference is that this expression must also include the <b><code>[1]<\/code><\/b>, just as we did it for the untyped column. As a result, for each column, the <b><code>SELECT<\/code><\/b> statement returns a single <b><code>int<\/code><\/b> value of <b><code>800000<\/code><\/b>, without any additional element information.<\/p>\n<p>You can also retrieve an attribute value, rather than an element value, by specifying the name of the attribute in your element path. For example, the following <b><code>SELECT<\/code><\/b> statement retrieves the value of the <b><code>Type<\/code><\/b> attribute for the second instance of the <b><code>&lt;Products&gt;<\/code><\/b> element:<\/p>\n<pre class=\"theme:ssms2012 lang:tsql\">SELECT\n\u00a0 Survey_untyped.value('(\/StoreSurvey\/Products\/@Type)[2]', 'varchar(10)')\n\u00a0\u00a0\u00a0 AS ProductType\nFROM\n\u00a0 Stores;\n\u00a0\n<\/pre>\n<p>The expression includes <b><code>[2]<\/code><\/b>, rather than <b><code>[1]<\/code><\/b>, in order to retrieve data from the second instance of <b><code>&lt;Products&gt;<\/code><\/b>. As a result, the <b><code>SELECT<\/code><\/b> statement now returns the <b><code>varchar<\/code><\/b> value <b><code>Clothes<\/code><\/b>.<\/p>\n<p>As stated earlier, the <b><code>value()<\/code><\/b> method is also handy if you want to combine or compare data. In the following example, I create a calculated column that&#8217;s based on two values returned from the untyped column:<\/p>\n<pre class=\"theme:ssms2012 lang:tsql\">SELECT\n\u00a0 Survey_untyped.value('(\/StoreSurvey\/AnnualSales)[1]', 'int') -\n\u00a0 Survey_untyped.value('(\/StoreSurvey\/AnnualRevenue)[1]', 'int')\n\u00a0\u00a0\u00a0 AS Expenses\nFROM\n\u00a0 Stores;\n\u00a0\n<\/pre>\n<p>The first instance of <b><code>value()<\/code><\/b> retrieves the <b><code>&lt;AnnualSales&gt;<\/code><\/b> value. The second <b><code>value()<\/code><\/b> instance retrieves the <b><code>&lt;AnnualRevenue&gt;<\/code><\/b> value. The second value is then subtracted from the first value to return a scalar value of <b><code>720000<\/code><\/b>.<\/p>\n<p>You can also use XQuery functions in your expressions. For instance, in the following example, I use the <b><code>concat<\/code><\/b> function to add a string to the <b><code>&lt;Specialty&gt;<\/code><\/b> value:<\/p>\n<pre class=\"theme:ssms2012 lang:tsql\">SELECT\n\u00a0 Survey_untyped.value('concat(\"Bike specialty: \",\n\u00a0\u00a0 (\/StoreSurvey\/Specialty)[1])', 'varchar(25)') \n\u00a0\u00a0 AS Specialty\nFROM\n\u00a0 Stores;\n\u00a0\n<\/pre>\n<p>When you use the <b><code>concat<\/code><\/b> function, you specify each element that you want to concatenate as an argument to the function and separate those arguments with a comma. The statement returns the value <b><code>Bike specialty: Mountain<\/code><\/b>.<\/p>\n<p>As you can see, the string has been concatenated with the <b><code>&lt;Specialty&gt;<\/code><\/b> value. I could have just as easily concatenated multiple element values or added more string values.<\/p>\n<h1>The exist() method<\/h1>\n<p>The <b><code>exist()<\/code><\/b> method lets you test for the existence of an element or one of its values. The method takes only one argument, the XQuery expression, as shown in the following syntax:<\/p>\n<pre>DbObject.exist('XQuery')\n<\/pre>\n<p>The key to using the <b><code>exist()<\/code><\/b> method is in understanding the values it returns. Unlike the <b><code>query() <\/code><\/b>and <b><code>value()<\/code><\/b> methods, the <b><code>exist()<\/code><\/b> method doesn&#8217;t return XML content. Rather, the method returns one of the following three values:<\/p>\n<ul>\n<li>A <b><code>BIT<\/code><\/b> value of <b><code>1<\/code><\/b> if the XQuery expression returns a nonempty result<\/li>\n<li>A <b><code>BIT<\/code><\/b> value of <b><code>0<\/code><\/b> if the XQuery expression returns an empty result.<\/li>\n<li>A <b><code>NULL<\/code><\/b> value if the XML data type instance is null.<\/li>\n<\/ul>\n<p>A good way to test how the <b><code>exist()<\/code><\/b> method works is to use a variable to capture the method&#8217;s results, as I&#8217;ve done in the following example:<\/p>\n<pre class=\"theme:ssms2012 lang:tsql\">DECLARE @xml XML;\nDECLARE @exist BIT;\nSET @xml = (SELECT Survey_untyped FROM Stores);\nSET @exist = @xml.exist('\/StoreSurvey[BusinessType=\"BM\"]');\nSELECT @exist;\n\u00a0\n<\/pre>\n<p>First, I declared the <b><code>@xml<\/code><\/b> variable as type <b><code>XML<\/code><\/b>. Then I declared the <b><code>@exist<\/code><\/b> variable as type <b><code>BIT<\/code><\/b>. I set the value of <b><code>@xml<\/code><\/b> to equal the XML document in the <b><code>Survey_untyped<\/code><\/b> column. I then used the <b><code>exist()<\/code><\/b> method on the <b><code>@xml<\/code><\/b> variable to test for the existence of <b><code>\/StoreSurvey[BusinessType=\"BM\"]<\/code><\/b> within the XML document. In other words, the <b><code>exist()<\/code><\/b> methods checks whether the <b><code>&lt;BusinessType&gt;<\/code><\/b> child element exists and whether it contains a value of &#8220;BM&#8221;.<\/p>\n<p>I then assigned the results returned by the <b><code>exist()<\/code><\/b> method to the <b><code>@exist<\/code><\/b> variable and used a <b><code>SELECT<\/code><\/b> statement to return the contents of the variable. Because the XML document contains this child element and that element has a value of &#8220;BM&#8221;, the method returns a value of <b><code>1<\/code><\/b>. However, if I change &#8220;BM&#8221; to &#8220;BMX&#8221;, as I&#8217;ve done in the following example, the method returns <b><code>0<\/code><\/b> because the element and value don&#8217;t exist exactly as specified:<\/p>\n<pre class=\"theme:ssms2012 lang:tsql\">DECLARE @xml2 XML;\nDECLARE @exist2 BIT;\nSET @xml2 = (SELECT Survey_untyped FROM Stores);\nSET @exist2 = @xml2.exist('\/StoreSurvey[BusinessType=\"BMX\"]');\nSELECT @exist2;\n\u00a0\n<\/pre>\n<p>Now that you have a sense of how the <b><code>exist()<\/code><\/b> method works, let&#8217;s look at how you might use it in your queries. In the following example, I include a <b><code>WHERE<\/code><\/b> clause that uses the <b><code>exist()<\/code><\/b> method to again test for the existence of <b><code>\/StoreSurvey[BusinessType=\"BM\"]<\/code><\/b>:<\/p>\n<pre class=\"theme:ssms2012 lang:tsql\">SELECT\n\u00a0 Survey_untyped.query('\/StoreSurvey\/Products[@Type=\"Bikes\"]') \n\u00a0\u00a0\u00a0 AS BikeProducts\nFROM\n\u00a0 Stores\nWHERE\n\u00a0 Survey_untyped.exist('\/StoreSurvey[BusinessType=\"BM\"]') = 1;\n\u00a0\n<\/pre>\n<p>The <b><code>WHERE<\/code><\/b> clause compares the results of the <b><code>exist()<\/code><\/b> method to the number 1. If the results equal 1, that is, if the XML contains the specified element and values, the <b><code>WHERE<\/code><\/b> clause evaluates to <b><code>True<\/code><\/b> and the <b><code>SELECT<\/code><\/b> statement returns the product information, as shown in the following results:<\/p>\n<pre class=\"theme:ssms2012 lang:tsql\">&lt;Products Type=\"Bikes\"&gt;\n\u00a0 &lt;Product&gt;Mountain&lt;\/Product&gt;\n\u00a0 &lt;Product&gt;Road&lt;\/Product&gt;\n\u00a0 &lt;Product&gt;Racing&lt;\/Product&gt;\n&lt;\/Products&gt;\n\u00a0\n<\/pre>\n<p>If the <b><code>exist()<\/code><\/b> method had specified a different <b><code>&lt;BusinessType&gt;<\/code><\/b> value, as it does in the following example, the <b><code>SELECT<\/code><\/b> statement would instead return an empty result set:<\/p>\n<pre class=\"theme:ssms2012 lang:tsql\">SELECT\n\u00a0 Survey_untyped.query('\/StoreSurvey\/Products[@Type=\"Bikes\"]') \n\u00a0\u00a0\u00a0 AS BikeProducts\nFROM\n\u00a0 Stores\nWHERE\n\u00a0 Survey_untyped.exist('\/StoreSurvey[BusinessType=\"BMX\"]') = 1;\n\u00a0\n<\/pre>\n<p>Again, the key to the <b><code>exist()<\/code><\/b> method is to remember that it returns only one of three values: <b><code>1<\/code><\/b>, <b><code>0<\/code><\/b>, or <b><code>NULL<\/code><\/b>.<\/p>\n<h1>The nodes() method<\/h1>\n<p>The <b><code>nodes()<\/code><\/b> method can be a bit more slippery to understand than the other <b><code>XML<\/code><\/b> methods. To begin with, rather than returning XML or scalar values, the <b><code>nodes()<\/code><\/b> method returns what is essentially a table that includes one column. That means you should use the method only in those parts of a statement that can handle rowset views, such as the <b><code>FROM<\/code><\/b> clause. It also means that, when you call the <b><code>nodes()<\/code><\/b> method, you must assign a table alias and column alias to the rowset view returned by the method, as shown in the following syntax:<\/p>\n<pre>DbObject.nodes('XQuery') AS TableAlias(ColumnAlias)<\/pre>\n<p>The table and column aliases let you reference the rowset view in other parts of the statement. The method is useful when you want to shred an XML document, that is, decompose the document into a relational format. To better understand how this works, let&#8217;s look at an example that uses the <b><code>nodes()<\/code><\/b> method on an <b><code>XML<\/code><\/b> variable:<\/p>\n<pre class=\"theme:ssms2012 lang:tsql\">DECLARE @bikes XML\nSET @bikes = \n\u00a0 '&lt;Products&gt;\n\u00a0\u00a0\u00a0 &lt;Product&gt;Mountain&lt;\/Product&gt;\n\u00a0\u00a0\u00a0 &lt;Product&gt;Road&lt;\/Product&gt;\n\u00a0\u00a0\u00a0 &lt;Product&gt;Racing&lt;\/Product&gt;\n\u00a0\u00a0 &lt;\/Products&gt;'\nSELECT \n\u00a0 Category.query('.\/text()')\n\u00a0\u00a0\u00a0 AS BikeTypes\nFROM \n\u00a0 @bikes.nodes('\/Products\/Product') \n\u00a0\u00a0\u00a0 AS Bike(Category);\n\u00a0\n<\/pre>\n<p>First, I declared the <b><code>@bikes<\/code><\/b> variable with the <b><code>XML<\/code><\/b> data type. Then I set its value to equal the XML fragment. In the <b><code>FROM<\/code><\/b> clause, I invoked the <b><code>nodes()<\/code><\/b> method on the variable to shred the <b><code>&lt;Product&gt;<\/code><\/b> elements. My goal was to retrieve the value from each instance of that element. I then provided a table alias (<b><code>Bike<\/code><\/b>) and a column alias (<b><code>Category<\/code><\/b>) to identify my rowset view. Now I essentially have a table with a single column that contains a row for each <b><code>&lt;Product&gt;<\/code><\/b> element.<\/p>\n<p>When you use the <b><code>nodes() <\/code><\/b>method to create a rowset view of the XML data, you have to use one of the other <b><code>XML<\/code><\/b> methods to retrieve the contents of that view. In this case, I used the <b><code>query()<\/code><\/b> method in the <b><code>SELECT<\/code><\/b> list to return the value of each row. Notice that to retrieve the value I used a period to reference the current context node and the <b><code>text()<\/code><\/b> node function to retrieve only the element values, as shown in the following results:<\/p>\n<pre>Mountain\nRoad\nRacing\n\u00a0\n<\/pre>\n<p>If you want to use the <b><code>nodes()<\/code><\/b> method to retrieve data from a table, you can use the <b><code>CROSS APPLY<\/code><\/b> operator in the <b><code>FROM<\/code><\/b> clause to associate the table with the rowset view returned by the method, as shown in the following example:<\/p>\n<pre class=\"theme:ssms2012 lang:tsql\">SELECT \n\u00a0 Category.query('.\/text()') \n\u00a0\u00a0\u00a0 AS BikeTypes\nFROM \n\u00a0 Stores CROSS APPLY \n\u00a0 Survey_untyped.nodes('\/StoreSurvey\/Products[@Type=\"Bikes\"]\/Product') \n\u00a0\u00a0\u00a0 AS Bike(Category);\n\u00a0\n<\/pre>\n<p>In this case, I specified the XQuery path as <b><code>StoreSurvey\/Products[@Type=\"Bikes\"]\/Product'<\/code><\/b> in order to return only the bike-related products from the <b><code>Survey_untyped<\/code><\/b> column. However the <b><code>SELECT<\/code><\/b> list itself is the same as the preceding example, so this statement returns the same results as that example.<\/p>\n<h1>The modify() method<\/h1>\n<p>The methods we&#8217;ve looked at up to this point have been concerned only with reading data in an XML document, but the <b><code>modify()<\/code><\/b> method lets you update that data. As the following syntax shows, the only argument you pass into the <b><code>modify()<\/code><\/b> method is the XQuery expression:<\/p>\n<pre>DbObject.modify('XQuery')\n<\/pre>\n<p>In this case, however, the XQuery expression is actually a special type of expression that uses the XML Data Modification Language (XML DML), which is a SQL Server extension to XQuery. The <b><code>modify()<\/code><\/b> method lets you define XML DML expressions that can add, update, or delete elements within an XML document.<\/p>\n<div class=\"note\">\n<p class=\"note\">NOTE: This section covers only the basics of the <b><code>modify()<\/code><\/b> method. You can find more information about the method and its uses in the <a href=\"http:\/\/www.simple-talk.com\/sql\/t-sql-programming\/xml-data-modification-language-workbench\/\">XML Data Modification Language Workbench<\/a>, which provides additional details and examples about modifying XML data.<\/p>\n<\/div>\n<h1><i>Adding components to XML data<\/i><\/h1>\n<p>To add components to your XML data, you must specify the <b><code>insert<\/code><\/b> keyword and target location in your expression. For instance, the following <b><code>UPDATE<\/code><\/b> statement adds the <b><code>&lt;Comments&gt;<\/code><\/b> element to the typed and untyped <b><code>XML<\/code><\/b> columns in the <b><code>Stores<\/code><\/b> table:<\/p>\n<pre class=\"theme:ssms2012 lang:tsql\">UPDATE Stores\nSET Survey_untyped.modify('\n\u00a0 insert(&lt;Comments&gt;Largest bike store in region&lt;\/Comments&gt;)\n\u00a0 after(\/StoreSurvey\/NumberEmployees)[1]'),\n\u00a0 Survey_typed.modify('declare namespace ns=\n\u00a0 \"http:\/\/schemas.microsoft.com\/sqlserver\/2004\/07\/adventure-works\/StoreSurvey\";\n\u00a0 insert(&lt;ns:Comments&gt;Largest bike store in region&lt;\/ns:Comments&gt;) \n\u00a0 after(\/ns:StoreSurvey\/ns:NumberEmployees)[1]')\nWHERE StoreID = 292;\n\u00a0\n<\/pre>\n<p>For the <b><code>Survey_untyped<\/code><\/b> column, I first specified the <b><code>modify()<\/code><\/b> method name, followed by the XML DML expression, which I enclosed in parentheses and single quotes, just like the other <b><code>XML<\/code><\/b> methods. Within the expression, I included the <b><code>insert<\/code><\/b> keyword and the element I wanted to add: (<b><code>&lt;Comments&gt;Largest bike store in region&lt;\/Comments&gt;<\/code><\/b>). Notice that I enclosed the element in parenthesis and included the element&#8217;s value.<\/p>\n<p>Next, I added the <b><code>after<\/code><\/b> keyword and specified the location of where to add the new element. I also included the <b><code>[1]<\/code><\/b> because the method requires a singleton value. Now the new element will be added after the first instance of the <b><code>\/StoreSurvey\/NumberEmployees<\/code><\/b> element.<\/p>\n<p>As you would expect, modifying the <b><code>Survey_typed<\/code><\/b> column followed the same process, except that I also included the namespace declaration and aliases. An important issue to consider, however, when working with typed <b><code>XML<\/code><\/b> columns is that any changes you make must conform to the schema that governs the XML content. For example, if I had tried to add the <b><code>&lt;Comments&gt;<\/code><\/b> element to any other location within the document, I would have received a violation error. However, if you&#8217;ve set up your statement properly and adhered to the schema, the new element should be added to the XML document with no problem.<\/p>\n<h1><i>Updating components in XML data<\/i><\/h1>\n<p>To use the <b><code>modify()<\/code><\/b> method to update XML data, you must include the <b><code>replace value of<\/code><\/b> keywords, rather than the <b><code>insert<\/code><\/b> keyword. You must then specify the component you want to update as well as the updated information. For example, in the following <b><code>UPDATE<\/code><\/b> statement, I change the value of the <b><code>&lt;Comments&gt;<\/code><\/b> element:<\/p>\n<pre class=\"theme:ssms2012 lang:tsql\">UPDATE Stores\nSET Survey_untyped.modify('\n\u00a0 replace value of (\/StoreSurvey\/Comments\/text())[1]\n\u00a0 with \"2nd largest bike store in region\" ')\nWHERE StoreID = 292;\n\u00a0\n<\/pre>\n<p>After I specified the <b><code>replace value of<\/code><\/b> keywords, I added the element path along with the <b><code>text()<\/code><\/b> node function, which let me change only the element&#8217;s value (without affecting the element itself). And as with the previous example, I also included a <b><code>[1]<\/code><\/b> because a singleton value is expected. Next, I specified the <b><code>with<\/code><\/b> keyword and the new element value, enclosed in double quotes. As a result, when I ran the statement, it replaced the old element value with the new one.<\/p>\n<h1><i>Deleting components from XML data<\/i><\/h1>\n<p>To use the <b><code>modify()<\/code><\/b> method to remove data from an XML document, you must specify the <b><code>delete<\/code><\/b> keyword, followed by the component you want to delete, as shown in the following example:<\/p>\n<pre class=\"theme:ssms2012 lang:tsql\">UPDATE Stores\nSET Survey_untyped.modify('delete(\/StoreSurvey\/Comments)[1]')\nWHERE StoreID = 292;\n\u00a0\n<\/pre>\n<p>In this case, it was simply a matter of specifying the path to the <b><code>&lt;Comments&gt;<\/code><\/b> element, in parentheses, after the <b><code>delete<\/code><\/b> keyword. Of course, all this was followed by <b><code>[1]<\/code><\/b> to keep the database engine happy.<\/p>\n<h1>The XML Methods<\/h1>\n<p>The methods available to the XML data type provide you with a set of powerful tools for working with XML data. And as you can see from the examples, most of that power rests in your ability to create XQuery expressions that target the information you want to access. Yet the expressions shown here are relatively basic when compared to how extensive the XQuery language is. In fact, to make the most of what the XML methods offer, you must invest the time necessary to understand the various elements that make up that language. Until then, what I&#8217;ve shown you here should provide you with the first steps necessary to start accessing and updating your XML data. Just know that there&#8217;s a much bigger universe out there waiting to be discovered.<\/p>\n<\/div>\n\n\n<section id=\"faq\" class=\"faq-block my-5xl\">\n    <h2>FAQs<\/h2>\n\n                        <h3 class=\"mt-4xl\">1. What are the five XML methods in SQL Server?<\/h3>\n            <div class=\"faq-answer\">\n                <p>SQL Server&#8217;s XML data type supports five methods: query() retrieves a subset of XML matching an XQuery expression; value() returns a scalar value from a single XML node, converted to a T-SQL data type; exist() tests whether a node or value exists, returning 1 or 0; nodes() shreds an XML document into a relational rowset suitable for joining or aggregating; and modify() performs in-place insert, replace, or delete operations on the XML content. Each method takes an XQuery expression as its primary argument.<\/p>\n            <\/div>\n                    <h3 class=\"mt-4xl\">2. How do I extract a scalar value from an XML column in SQL Server?<\/h3>\n            <div class=\"faq-answer\">\n                <p>Use the value() method. Syntax: XmlColumn.value(&#8216;XQuery expression&#8217;, &#8216;T-SQL data type&#8217;). The XQuery expression identifies a single XML node, and the second argument specifies the T-SQL data type the value should be returned as. Example: SELECT Survey.value(&#8216;(\/StoreSurvey\/AnnualSales)[1]&#8217;, &#8216;int&#8217;) FROM Stores. The [1] is required because XQuery paths return node sets &#8211; even when you know there is only one match, you must explicitly reference the first node.<\/p>\n            <\/div>\n                    <h3 class=\"mt-4xl\">3. What is the difference between query() and value() in SQL Server XML?<\/h3>\n            <div class=\"faq-answer\">\n                <p>query() returns XML &#8211; the result is itself an XML fragment matching the XQuery expression. value() returns a scalar of a specific T-SQL data type (int, varchar, datetime, etc.). Use query() when you need to extract a nested XML structure for further processing or display. Use value() when you need a typed scalar &#8211; for insertion into a non-XML column, use in a WHERE clause, or mathematical operation. query() can return zero, one, or many XML nodes; value() must return exactly one scalar value.<\/p>\n            <\/div>\n                    <h3 class=\"mt-4xl\">4. How do I shred XML into rows in SQL Server using nodes()?<\/h3>\n            <div class=\"faq-answer\">\n                <p>Use the nodes() method with CROSS APPLY. Syntax: SELECT T.C.value(&#8216;.\/Element[1]&#8217;, &#8216;varchar(50)&#8217;) FROM XmlTable CROSS APPLY XmlColumn.nodes(&#8216;\/Root\/Item&#8217;) AS T(C). The nodes() method returns a special rowset where each row corresponds to one matching XML node; CROSS APPLY joins this rowset to the original row. The T(C) alias is required &#8211; T is the table alias and C is the single column representing each matched node, which you then process with further XQuery methods (typically value()) to extract specific data.<\/p>\n            <\/div>\n                    <h3 class=\"mt-4xl\">5. How do I update XML data in SQL Server using modify()?<\/h3>\n            <div class=\"faq-answer\">\n                <p>modify() supports three operations, controlled by XQuery keywords: insert adds a new element or attribute, replace value of updates a single scalar value, and delete removes a node. modify() must be called inside an UPDATE statement&#8217;s SET clause, targeting a column of the XML data type. Example insert: UPDATE Stores SET Survey.modify(&#8216;insert value as last into (\/StoreSurvey)[1]&#8217;). Example update: UPDATE Stores SET Survey.modify(&#8216;replace value of (\/StoreSurvey\/AnnualSales\/text())[1] with &#8220;900000&#8221;&#8216;). Example delete: UPDATE Stores SET Survey.modify(&#8216;delete \/StoreSurvey\/BankName&#8217;).<\/p>\n            <\/div>\n            <\/section>\n","protected":false},"excerpt":{"rendered":"<p>The five SQL Server XML methods &#8211; query(), value(), exist(), nodes(), and modify() &#8211; explained with working AdventureWorks examples. Covers XQuery expressions, adding, updating, and deleting XML components, and typed vs untyped XML columns.&hellip;<\/p>\n","protected":false},"author":221841,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[143525],"tags":[4149,4150,5134,4151,4217],"coauthors":[6779],"class_list":["post-1253","post","type-post","status-publish","format-standard","hentry","category-learn","tag-learn-sql-server","tag-sql","tag-sql-prompt","tag-sql-server","tag-xml"],"acf":[],"_links":{"self":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/1253","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/users\/221841"}],"replies":[{"embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/comments?post=1253"}],"version-history":[{"count":5,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/1253\/revisions"}],"predecessor-version":[{"id":110216,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/1253\/revisions\/110216"}],"wp:attachment":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/media?parent=1253"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/categories?post=1253"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/tags?post=1253"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/coauthors?post=1253"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}