<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>sqlity.net &#187; XML</title>
	<atom:link href="http://sqlity.net/en/topic/general/xml/feed/" rel="self" type="application/rss+xml" />
	<link>http://sqlity.net/en</link>
	<description>Quality for SQL</description>
	<lastBuildDate>Fri, 18 May 2012 13:05:28 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.2</generator>
<xhtml:meta xmlns:xhtml="http://www.w3.org/1999/xhtml" name="robots" content="noindex" />
		<item>
		<title>Selecting the entire Database as XML String &#8211; 2</title>
		<link>http://sqlity.net/en/626/selecting-the-entire-database-as-xml-string-2/</link>
		<comments>http://sqlity.net/en/626/selecting-the-entire-database-as-xml-string-2/#comments</comments>
		<pubDate>Wed, 01 Feb 2012 17:11:49 +0000</pubDate>
		<dc:creator>Sebastian</dc:creator>
				<category><![CDATA[General]]></category>
		<category><![CDATA[XML]]></category>

		<guid isPermaLink="false">http://sqlity.net/en/?p=626</guid>
		<description><![CDATA[About two weeks ago I wrote about how to get the content of the entire database into an XML document. Today Daniel commented, that he would like the XML to be in a compacter format. In this post I am going to explain how to get there. While WordPress&#8482; conveniently ate the example XML Daniel <a href="http://sqlity.net/en/626/selecting-the-entire-database-as-xml-string-2/#more-'" class="more-link">more »</a>]]></description>
			<content:encoded><![CDATA[<div>
<p>
About two weeks ago I wrote about <a href="http://sqlity.net/en/577/selecting-the-entire-database-as-xml-string/">how to get the content of the entire database into an XML document</a>. Today <a href="http://sqlity.net/en/577/selecting-the-entire-database-as-xml-string/#comment-18" title="Daniel's comment">Daniel commented</a>, that he would like the XML to be in a compacter format. In this post I am going to explain how to get there.
</p>
<p>
While WordPress&trade; conveniently ate the example XML Daniel tried to post, I will assume for this article that he was going for this format:
</p>
<div>
<pre class="brush: xml; title: ; notranslate">
&lt;tables&gt;
  &lt;table name=&quot;[dbo].[T1366]&quot;&gt;
    &lt;row id=&quot;1&quot; c1=&quot;1366&quot; c2=&quot;2732&quot; c3=&quot;4098&quot; c4=&quot;5464&quot; c5=&quot;6830&quot; c6=&quot;8196&quot; /&gt;
    &lt;row id=&quot;2&quot; c1=&quot;1366&quot; c2=&quot;2732&quot; c3=&quot;4098&quot; c4=&quot;5464&quot; c5=&quot;6830&quot; c6=&quot;8196&quot; /&gt;
  &lt;/table&gt;
  &lt;table name=&quot;[dbo].[T127]&quot;&gt;
    &lt;row id=&quot;1&quot; c1=&quot;127&quot; c2=&quot;254&quot; c3=&quot;381&quot; c4=&quot;508&quot; c5=&quot;635&quot; c6=&quot;762&quot; c7=&quot;889&quot; /&gt;
    &lt;row id=&quot;2&quot; c1=&quot;127&quot; c2=&quot;254&quot; c3=&quot;381&quot; c4=&quot;508&quot; c5=&quot;635&quot; c6=&quot;762&quot; c7=&quot;889&quot; /&gt;
  &lt;/table&gt;
&lt;/tables&gt;
</pre>
</div>
<p>
Instead of all column values being sub-nodes of their &lt;row&gt; nodes they are now attributes of an empty &lt;row&gt; node. Also the &lt;data&gt; node between &lt;table&gt; and &lt;row&gt; is now missing, as it was kind of superfluous. And while I was changing the code anyway, I went ahead and added the previously missing root node as &lt;tables&gt;.
</p>
<p>
So how did I get there?
</p>
<p>
First let us look at the missing root node, which turns out to be the simplest of all the changes. When you select rows for a table specifying the FOR XML PATH('NodeName') directive, every row is going to be represented as a node with the passed in name. Those nodes are just hanging together without an enclosing root node. To make the output a valid XML document you can just specify the ROOT clause next to the PATH clause like this:
</p>
<div>
<pre class="brush: sql; title: ; notranslate">
  SELECT * 
    FROM dbo.Table
  FOR XML PATH('rowNodeName'),ROOT('rootNodeName'),TYPE
</pre>
</div>
<p>
The TYPE directive tells SQL Server to return the XML as a value with the XML type. If you leave it out the XML gets returned as a string, which can create problems if you want to continue to work with it in T-SQL.
</p>
<p>
The next step was, to get rid of the &lt;data&gt; node. When you specify an XML value in a select statement that is in turn using FOR XML PATH, that value is wrapped in a node with the value's column name. The generated SQL in my original solution looked like this:
</p>
<div>
<pre class="brush: sql; title: ; notranslate">
SELECT * FROM(
SELECT '[dbo].[t1]' [@name],(SELECT * FROM dbo.t1 FOR XML PATH('row'),TYPE) data
UNION ALL
SELECT '[dbo].[t2]' [@name],(SELECT * FROM dbo.t2 FOR XML PATH('row'),TYPE) data
)X FOR XML PATH('table'),TYPE;
</pre>
</div>
<p>
The data column in the UNION ALL query contains XML values, so the outer SELECT * ... FOR XML PATH('table') is going to wrap each one into a &lt;data&gt; node like this:
</p>
<div>
<pre class="brush: xml; title: ; notranslate">
&lt;table name=&quot;[dbo].[t1]&quot;&gt;
  &lt;data&gt;
    &lt;row&gt;
      &lt;id&gt;1&lt;/id&gt;
      &lt;c1&gt;1&lt;/c1&gt;
    &lt;/row&gt;
    &lt;row&gt;
      &lt;id&gt;2&lt;/id&gt;
      &lt;c1&gt;1&lt;/c1&gt;
    &lt;/row&gt;
  &lt;/data&gt;
&lt;/table&gt;
&lt;table name=&quot;[dbo].[t2]&quot;&gt;
  &lt;data&gt;
    &lt;row&gt;
      &lt;id&gt;1&lt;/id&gt;
      &lt;c1&gt;2&lt;/c1&gt;
      &lt;c2&gt;4&lt;/c2&gt;
    &lt;/row&gt;
    &lt;row&gt;
      &lt;id&gt;2&lt;/id&gt;
      &lt;c1&gt;2&lt;/c1&gt;
      &lt;c2&gt;4&lt;/c2&gt;
    &lt;/row&gt;
  &lt;/data&gt;
&lt;/table&gt;
</pre>
</div>
<p>
To remove the additional node we can use the fact that SQL Sever will inline the value of a column that does not have a name. So we need to select the data column without specifying its name. To do that we will use a trick:
</p>
<div>
<pre class="brush: sql; title: ; notranslate">
SELECT [@name],(SELECT data) FROM(
SELECT '[dbo].[t1]' [@name],(SELECT * FROM dbo.t1 FOR XML PATH('row'),TYPE) data
UNION ALL
SELECT '[dbo].[t2]' [@name],(SELECT * FROM dbo.t2 FOR XML PATH('row'),TYPE) data
)X FOR XML PATH('table'),TYPE;
</pre>
</div>
<p>
By wrapping the data column in its own SELECT it loses its name property for the outer SELECT statement. The output it generates now looks like this:
</p>
<div>
<pre class="brush: sql; title: ; notranslate">
&lt;table name=&quot;[dbo].[t1]&quot;&gt;
  &lt;row&gt;
    &lt;id&gt;1&lt;/id&gt;
    &lt;c1&gt;1&lt;/c1&gt;
  &lt;/row&gt;
  &lt;row&gt;
    &lt;id&gt;2&lt;/id&gt;
    &lt;c1&gt;1&lt;/c1&gt;
  &lt;/row&gt;
&lt;/table&gt;
&lt;table name=&quot;[dbo].[t2]&quot;&gt;
  &lt;row&gt;
    &lt;id&gt;1&lt;/id&gt;
    &lt;c1&gt;2&lt;/c1&gt;
    &lt;c2&gt;4&lt;/c2&gt;
  &lt;/row&gt;
  &lt;row&gt;
    &lt;id&gt;2&lt;/id&gt;
    &lt;c1&gt;2&lt;/c1&gt;
    &lt;c2&gt;4&lt;/c2&gt;
  &lt;/row&gt;
&lt;/table&gt;
</pre>
</div>
<p>
 The last thing we need to accomplish is to make the column values attributes of each &lt;row&gt; node instead of sub-nodes. If you specify a column name with a leading "@" sign, FOR XML PATH will make that value an attribute with that name (without the "@"):
</p>
<div>
<pre class="brush: sql; title: ; notranslate">
SELECT id AS [@id] FROM dbo.t1 FOR XML PATH('row'),TYPE;
</pre>
<div>
<p>
The output of above statement looks like this:
<div>
<pre class="brush: xml; title: ; notranslate">
&lt;row id=&quot;1&quot; /&gt;
&lt;row id=&quot;2&quot; /&gt;
</pre>
</div>
<p>
So instead of a SELECT * FROM for each table, we need to list all columns in the format shown above. To get this specially formatted column list we are going to use <a href="http://sqlity.net/en/400/t-sql-tuesday-22-data-presentation/">XML concatenation</a> one more time:
</p>
<div>
<pre class="brush: sql; title: ; notranslate">
SELECT STUFF((SELECT ','+QUOTENAME(name)+' AS '+QUOTENAME('@'+name) 
                              FROM sys.columns c 
                             WHERE c.object_id = OBJECT_ID('dbo.t2')
                             ORDER BY column_id 
                            FOR XML PATH(''),TYPE).value('.','NVARCHAR(MAX)'),1,1,'');
</pre>
</div>
<p>
This produces the desired list:
<pre>[id] AS [@id],[c1] AS [@c1],[c2] AS [@c2]</pre>
</p>
<p>
With that we have all the parts collected to create the new "compact" solution. The last step is to put it all together:
</p>
<div>
<pre class="brush: sql; title: ; notranslate">
DECLARE @cmd NVARCHAR(MAX) ;
SET @cmd = 'SELECT [@name],(SELECT data) FROM('
    + STUFF(
(SELECT ' UNION ALL SELECT ''' + QUOTENAME(OBJECT_SCHEMA_NAME(object_id))
        + '.' + QUOTENAME(t.name) + ''' [@name],' + '(SELECT '+c.ColList+' FROM '
        + QUOTENAME(OBJECT_SCHEMA_NAME(object_id)) + '.' + QUOTENAME(t.name)
        + ' FOR XML PATH(''row''),TYPE) data'
 FROM   sys.tables t
 CROSS APPLY (SELECT STUFF((SELECT ','+QUOTENAME(name)+' AS '+QUOTENAME('@'+name) 
                              FROM sys.columns c 
                             WHERE c.object_id = t.object_id
                             ORDER BY column_id 
                            FOR XML PATH(''),TYPE).value('.','NVARCHAR(MAX)'),1,1,'')
             )c(ColList)
    FOR     XML PATH('') ,
                TYPE).value('.', 'NVARCHAR(MAX)'), 1, 11, '')
    + ')X FOR XML PATH(''table''),ROOT(''tables''),TYPE;' ;

EXEC(@cmd) ;
</pre>
</div>
<p>
This produces the desired output that was shown all the way at the beginning of this article. The size of the resulting XML document for my example database went from about 1.4 MB for the original solution to now about 0.5 MB &ndash; a significant improvement.
</p>
</div><div class="bottomcontainerBox" style="">
			<div style="float:left; width:85px;padding-right:10px; margin:4px 4px 4px 4px;height:30px;">
			<iframe src="http://www.facebook.com/plugins/like.php?href=http%3A%2F%2Fsqlity.net%2Fen%2F626%2Fselecting-the-entire-database-as-xml-string-2%2F&amp;layout=button_count&amp;show_faces=false&amp;width=85&amp;action=like&amp;font=verdana&amp;colorscheme=light&amp;height=21" scrolling="no" frameborder="0" allowTransparency="true" style="border:none; overflow:hidden; width:85px; height:21px;"></iframe></div>
			<div style="float:left; width:80px;padding-right:10px; margin:4px 4px 4px 4px;height:30px;">
			<g:plusone size="medium" href="http://sqlity.net/en/626/selecting-the-entire-database-as-xml-string-2/"></g:plusone>
			</div>
			<div style="float:left; width:95px;padding-right:10px; margin:4px 4px 4px 4px;height:30px;">
			<a href="http://twitter.com/share" class="twitter-share-button" data-url="http://sqlity.net/en/626/selecting-the-entire-database-as-xml-string-2/"  data-text="Selecting the entire Database as XML String &#8211; 2" data-count="horizontal" data-via="sqlity"></a>
			</div>			
			<div style="float:left; width:85px;padding-right:10px; margin:4px 4px 4px 4px;height:30px;"><script src="http://www.stumbleupon.com/hostedbadge.php?s=1&amp;r=http://sqlity.net/en/626/selecting-the-entire-database-as-xml-string-2/"></script></div>			
			</div><div style="clear:both"></div><div style="padding-bottom:4px;"></div>]]></content:encoded>
			<wfw:commentRss>http://sqlity.net/en/626/selecting-the-entire-database-as-xml-string-2/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>T-SQL Tuesday #22 &#8211; Data Presentation &#8211; XML Concatenation</title>
		<link>http://sqlity.net/en/400/t-sql-tuesday-22-data-presentation/</link>
		<comments>http://sqlity.net/en/400/t-sql-tuesday-22-data-presentation/#comments</comments>
		<pubDate>Tue, 13 Sep 2011 07:34:54 +0000</pubDate>
		<dc:creator>Sebastian</dc:creator>
				<category><![CDATA[General]]></category>
		<category><![CDATA[T-SQL Tuesday]]></category>
		<category><![CDATA[XML]]></category>

		<guid isPermaLink="false">http://sqlity.net/en/?p=400</guid>
		<description><![CDATA[It is T-SQL Tuesday again, the 22nd incarnation and this time the topic is the presentation of data, hosted by Robert Pearl (Blog&#124;Twitter). Every so often you run into the problem of having to display a list of items to the user. This could be a list of item numbers or a list of names. <a href="http://sqlity.net/en/400/t-sql-tuesday-22-data-presentation/#more-'" class="more-link">more »</a>]]></description>
			<content:encoded><![CDATA[<div style="position:relative;">
<div style="float:right;">
<a href="http://www.sqlservercentral.com/blogs/pearlknows/archive/2011/09/06/invitation-for-t-sql-tuesday-22-data-presentation.aspx"><strong><img style="background-image:none;border-right-width:0px;padding-left:0px;padding-right:0px;display:inline;float:right;border-top-width:0px;border-bottom-width:0px;border-left-width:0px;padding-top:0px;" title="T-SQL Tuesday" border="0" alt="SqlTuesday T SQL Tuesday #22   Data Presentation   XML Concatenation" align="right" src="http://images.sqlity.net/SqlTuesday.png" width="132" height="131" /></strong></a>
</div>
<p>
It is T-SQL Tuesday again, the 22nd incarnation and this time the topic is the presentation of data, hosted by Robert Pearl (<a href="http://www.sqlservercentral.com/blogs/pearlknows/default.aspx">Blog</a>|<a href="https://twitter.com/#!/PearlKnows">Twitter</a>).
</p>
Every so often you run into the problem of having to display a list of items to the user. This could be a list of item numbers or a list of names. 
</p>
<p>
Assume for example if you are trying to write a view that displays information about all the indexes in the database. 
You want this view to return one row per index. You also want to include the columns of the index. To make this happen you need to concatenate the information for the columns into one string.
</p>
<p>
This post is going to look at how to implement string concatenation in T-SQL.
</p>
<p>
In many other database management systems you have access to a function <a href="http://dev.mysql.com/doc/refman/5.0/en/group-by-functions.html#function_group-concat"><code>GROUP_CONCAT()</code></a> that provides just this functionality. In T-SQL it is not that easy yet. While Denali offers a new <a href="http://blogs.lessthandot.com/index.php/DataMgmt/DBProgramming/MSSQLServer/concat-function-in-sql-server"><code>CONCAT()</code></a> function, a <code>GROUP_CONCAT()</code> is not available in SQL Server up to version Denali CTP3.
</p>
<h4>XML to the rescue</h4>
<p>
There are several ways to go about this problem. For example you could write a UDF or you could rely on undocumented behavior<sup>1</sup>.
Most of those solutions seem complicated and also do not really address a real concatenation in a <code>GROUP BY</code> context.
</p>
<p>
There is one solution that I have found to be the easiest to use: FOR XML.
</p>
<p>
Using the <code>FOR XML</code> clause, SQL Server allows the output of any select to be a single XML Document:
</p>
<pre class="brush: sql; title: ; notranslate">
SELECT  name
FROM    master.sys.tables
FOR     XML PATH('row');
</pre>
<p>returns something like</p>
<pre class="brush: xml; title: ; notranslate">
&lt;row&gt;
  &lt;name&gt;spt_fallback_db&lt;/name&gt;
&lt;/row&gt;
&lt;row&gt;
  &lt;name&gt;spt_fallback_dev&lt;/name&gt;
&lt;/row&gt;
&lt;row&gt;
  &lt;name&gt;spt_fallback_usg&lt;/name&gt;
&lt;/row&gt;
&lt;row&gt;
  &lt;name&gt;spt_monitor&lt;/name&gt;
&lt;/row&gt;
&lt;row&gt;
  &lt;name&gt;spt_values&lt;/name&gt;
&lt;/row&gt;
&lt;row&gt;
  &lt;name&gt;MSreplication_options&lt;/name&gt;
&lt;/row&gt;
</pre>
<p> Every row gets wrapped into a <code>&lt;row&gt;</code> tag and every column in a tag that matches the columns name.
</p>
<p>
To eliminate the row tag we can pass in an empty string to the <code>PATH()</code> function. The column tags are eliminated by naming the column <code>&#91;text()]</code>.
</p>
<p>
So our example would look like this:
</p>
<pre class="brush: sql; title: ; notranslate">
SELECT  name AS [text()]
FROM    master.sys.tables
FOR     XML PATH('');
</pre>
<p>It's output looks like this:</p>
<pre class="brush: xml; title: ; notranslate">
spt_fallback_dbspt_fallback_devspt_fallback_usgspt_monitorspt_valuesMSreplication_options
</pre>
<p>
That looks already very promising. You probably would like to add separators in between the strings. How you can do that we will get to a little later.
There are a few things that I would like to address first. 
</p>
<h4>Special Characters</h4>
<p>
Let's look at characters that have a special meaning in XML like &lsquo;&lt;&rsquo;:
</p>
<pre class="brush: sql; title: ; notranslate">
SELECT '&lt;&amp;&gt;' AS [text()]
FOR XML PATH('');
</pre>
<p>Output:</p>
<pre class="brush: xml; title: ; notranslate">
&amp;lt;&amp;amp;&amp;gt;
</pre>
<p>
That is not what we wanted. To get those characters unescaped, we need to use one of the XML datatype functions:
</p>
<pre class="brush: sql; title: ; notranslate">
SELECT (SELECT '&lt;&amp;&gt;'
        FOR XML PATH(''), TYPE
       ).value('.','NVARCHAR(MAX)');
</pre>
<p>
This has the expected output: &lsquo;&lt;&amp;&gt;&rsquo;. You might have noticed the missing column name. If the column name is not specified at all (explicitly or otherwise), it has the same effect as if the <code>&#91;text()]</code> name is given.  The additional <code>TYPE</code> keyword causes the XML to be returned as an <code>XML</code> datatype result instead of as an <code>NVARCHAR(MAX)</code> datatype result. The <code>.value()</code> function is defined on the <code>XML</code> datatype and takes two parameters. The first one is using the XPath syntax and describes what we want to get back. The '.' here means everything. The second one specifies the datatype to which we want the result to be converted to.
</p>
<h4>Illegal Characters</h4>
<p>
The next problem is not that easy to solve. The SQL Server <code>XML</code> datatype cannot handle specific characters at all:
</p>
<pre class="brush: sql; title: ; notranslate">
SELECT CHAR(1)
FOR XML PATH('');
</pre>
This is handled and escaped correctly to <code>&amp;#x01;</code> however, it falls apart once we add the necessary <code>TYPE</code> keyword back in:
</p>
<pre class="brush: sql; title: ; notranslate">
SELECT CHAR(1)
FOR XML PATH(''), TYPE;
</pre>
<pre style="color:#F00;">
Msg 6841, Level 16, State 1, Line 1
FOR XML could not serialize the data for node 'NoName' because it contains a character (0x0001) which is not allowed in XML. To retrieve this data using FOR XML, convert it to binary, varbinary or image data type and use the BINARY BASE64 directive.
</pre>
<p>
There is a total of 2079 single character values that will cause this error. How to figure out which ones exactly will have to wait for another blog post. For now, if you think you might run ito any of them, you can use the following code to replace the most common of them with a question mark:
</p>
<pre class="brush: sql; title: ; notranslate">
SELECT REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE( 
       N'the text that is to be cleaned here' 
,NCHAR(1),N'?'),NCHAR(2),N'?'),NCHAR(3),N'?'),NCHAR(4),N'?'),NCHAR(5),N'?'),NCHAR(6),N'?'),NCHAR(7),N'?'),NCHAR(8),N'?'),NCHAR(11),N'?'),NCHAR(12),N'?'),NCHAR(14),N'?'),NCHAR(15),N'?'),NCHAR(16),N'?'),NCHAR(17),N'?'),NCHAR(18),N'?'),NCHAR(19),N'?'),NCHAR(20),N'?'),NCHAR(21),N'?'),NCHAR(22),N'?'),NCHAR(23),N'?'),NCHAR(24),N'?'),NCHAR(25),N'?'),NCHAR(26),N'?'),NCHAR(27),N'?'),NCHAR(28),N'?'),NCHAR(29),N'?'),NCHAR(30),N'?'),NCHAR(31),N'?');
</pre>
<p>
This replacement has to happen before the text is converted to XML. The following examples are going to skip this step for readability.
</p> 
<h4>Separators</h4>
<p>
Now we know how to concatenate string values together. To make our initial example of a select statement (or view) that returns one row per index and includes a comma separated column list work, two more steps are missing. First, the separator needs to be inserted between the values but not in front of the first one. This is not possible. But it is fairly simple to remove the additional separator after adding one in front of every item:
</p>
<pre class="brush: sql; title: ; notranslate">
SELECT  STUFF((SELECT   ', ' + name
               FROM     master.sys.tables
               FOR XML PATH('') ,TYPE
              ).value('.', 'NVARCHAR(MAX)'), 
              1, 2, ''
             );
</pre>
<p>
The <code>STUFF</code> function helps us with this problem. The first three parameters work just like the ones in the <code>SUBSTRING</code> function. But instead of returning that substring, the <code>STUFF</code> function replaces it with the value passed in as fourth parameter and then returns the complete string.
</p>
<h4>Putting it all together</h4>
<p>
The last step is to do this all inside a <CODE>GROUP BY</code> query. For that we have to use the <code>CROSS APPLY</code> functionality to create the column list for each group value in a correlated sub-query. Putting this all together looks like this:
</p>
<pre class="brush: sql; title: ; notranslate">
SELECT  t.name AS TblName ,
        i.name AS IdxName ,
        Columns.List AS Columns
FROM    sys.tables t
        JOIN sys.indexes i ON i.object_id = t.object_id
        CROSS APPLY ( SELECT    STUFF((SELECT   ', ' + c.name
                                                + CASE WHEN ic.is_descending_key = 1
                                                       THEN ' DESC'
                                                       ELSE ''
                                                  END
                                       FROM     sys.index_columns ic
                                                JOIN sys.columns c ON ic.object_id = c.object_id
                                                              AND ic.column_id = c.column_id
                                       WHERE    i.object_id = ic.object_id
                                                AND i.index_id = ic.index_id
                                       ORDER BY ic.index_column_id
                                       FOR   XML PATH('') ,
                                          TYPE
                                      ).value('.', 'NVARCHAR(MAX)')
                                      , 1, 2, ''
                                     )
                    ) Columns ( List ) ;
</pre>
<p>
This query returns the table name, the index name and a comma separated list of all columns for each index in the database. It also marks descending columns with the <code>DESC</code> keyword. What it does not do is separate out included columns. I'll leave that as an exercise for the reader. 
</p>
<p style="background:#CCC;font-size:0.8em;">1) One method that relies on undocumented behavior would be to continually add to a single variable within a single multirow select.</p>
</div><div class="bottomcontainerBox" style="">
			<div style="float:left; width:85px;padding-right:10px; margin:4px 4px 4px 4px;height:30px;">
			<iframe src="http://www.facebook.com/plugins/like.php?href=http%3A%2F%2Fsqlity.net%2Fen%2F400%2Ft-sql-tuesday-22-data-presentation%2F&amp;layout=button_count&amp;show_faces=false&amp;width=85&amp;action=like&amp;font=verdana&amp;colorscheme=light&amp;height=21" scrolling="no" frameborder="0" allowTransparency="true" style="border:none; overflow:hidden; width:85px; height:21px;"></iframe></div>
			<div style="float:left; width:80px;padding-right:10px; margin:4px 4px 4px 4px;height:30px;">
			<g:plusone size="medium" href="http://sqlity.net/en/400/t-sql-tuesday-22-data-presentation/"></g:plusone>
			</div>
			<div style="float:left; width:95px;padding-right:10px; margin:4px 4px 4px 4px;height:30px;">
			<a href="http://twitter.com/share" class="twitter-share-button" data-url="http://sqlity.net/en/400/t-sql-tuesday-22-data-presentation/"  data-text="T-SQL Tuesday #22 &#8211; Data Presentation &#8211; XML Concatenation" data-count="horizontal" data-via="sqlity"></a>
			</div>			
			<div style="float:left; width:85px;padding-right:10px; margin:4px 4px 4px 4px;height:30px;"><script src="http://www.stumbleupon.com/hostedbadge.php?s=1&amp;r=http://sqlity.net/en/400/t-sql-tuesday-22-data-presentation/"></script></div>			
			</div><div style="clear:both"></div><div style="padding-bottom:4px;"></div>]]></content:encoded>
			<wfw:commentRss>http://sqlity.net/en/400/t-sql-tuesday-22-data-presentation/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>

