<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:copyright="http://blogs.law.harvard.edu/tech/rss" xmlns:image="http://purl.org/rss/1.0/modules/image/">
    <channel>
        <title>Code Library - C# / VB.NET</title>
        <link>http://weblogs.sqlteam.com/jeffs/category/242.aspx</link>
        <description>Windows forms controls, classes, methods and more that you might find useful in general .NET programming.</description>
        <language>en-US</language>
        <copyright>Jeff Smith</copyright>
        <managingEditor>smith_jeffreyt@yahoo.com</managingEditor>
        <generator>Subtext Version 1.9.4.0</generator>
        <item>
            <title>Simple DataViewReader class that implements IDataReader for a DataView</title>
            <link>http://weblogs.sqlteam.com/jeffs/archive/2008/02/28/DataViewReader.aspx</link>
            <description>I &lt;a href="http://weblogs.sqlteam.com/jeffs/archive/2008/02/22/60528.aspx"&gt;previously wrote&lt;/a&gt; that the .NET 2.0 &lt;a href="http://msdn2.microsoft.com/en-us/library/system.data.datatablereader.aspx" target="_blank"&gt;DataTableReader class&lt;/a&gt; is really handy, but unfortunately there is no DataViewReader class.   Thus, the only way to use the IDataReader interface with a sorted/filtered DataView was to first use the ToRows() method of the view to create a brand new DataTable, and then call CreateDataReader() on that new table.   This is not the most efficient process when all you want to do is enumerate a DataView.&lt;br /&gt;
&lt;br /&gt;
So, here's a solution: a simple, efficient, mostly-complete &lt;span style="font-weight: bold;"&gt;DataViewReader &lt;/span&gt;class.   Just create a new instance of it passing in the source DataView and off you go.  This will be much more efficient than creating a brand new DataTable from the DataView, since we just use the default enumerator of the DataView and do not need to copy/create any more things in memory.&lt;br /&gt;
&lt;br /&gt;
Most methods are implemented but a few aren't, feel free to complete the class if you need the missing functionality.  It's pretty simple and straightforward.  &lt;br /&gt;
&lt;br /&gt;
If you find any bugs or have any suggestions for improvement, please let me know.&lt;br /&gt;
&lt;br /&gt;
&lt;div style="background: white none repeat scroll 0% 50%; font-family: Verdana; font-size: 8pt; line-height: 10pt; color: black; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;"&gt;  &lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;class&lt;/span&gt; &lt;span style="color: rgb(43, 145, 175);"&gt;DataViewReader&lt;/span&gt; :  &lt;span style="color: rgb(43, 145, 175);"&gt;IDataReader&lt;/span&gt; &lt;br /&gt;
    {&lt;br /&gt;
        &lt;span style="color: rgb(43, 145, 175);"&gt;DataView&lt;/span&gt; _source;&lt;br /&gt;
        &lt;span style="color: rgb(43, 145, 175);"&gt;IEnumerator&lt;/span&gt; _enum;&lt;br /&gt;
        &lt;span style="color: blue;"&gt;bool&lt;/span&gt; _closed = &lt;span style="color: blue;"&gt;true&lt;/span&gt;;&lt;br /&gt;
 &lt;br /&gt;
        &lt;span style="color: blue;"&gt;public&lt;/span&gt; DataViewReader(&lt;span style="color: rgb(43, 145, 175);"&gt;DataView&lt;/span&gt; source)&lt;br /&gt;
        {&lt;br /&gt;
            _source = source;&lt;br /&gt;
        }&lt;br /&gt;
 &lt;br /&gt;
        &lt;span style="color: rgb(43, 145, 175);"&gt;DataRowView&lt;/span&gt; current&lt;br /&gt;
        {&lt;br /&gt;
            &lt;span style="color: blue;"&gt;get&lt;/span&gt;&lt;br /&gt;
            {&lt;br /&gt;
                &lt;span style="color: blue;"&gt;return&lt;/span&gt; (&lt;span style="color: rgb(43, 145, 175);"&gt;DataRowView&lt;/span&gt;)_enum.Current;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
 &lt;br /&gt;
&lt;span style="color: blue;"&gt;        #region&lt;/span&gt; IDataReader Members&lt;br /&gt;
 &lt;br /&gt;
        &lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;void&lt;/span&gt; Close()&lt;br /&gt;
        {&lt;br /&gt;
            _closed = &lt;span style="color: blue;"&gt;true&lt;/span&gt;;&lt;br /&gt;
            &lt;span style="color: blue;"&gt;return&lt;/span&gt;;&lt;br /&gt;
        }&lt;br /&gt;
 &lt;br /&gt;
        &lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;int&lt;/span&gt; Depth&lt;br /&gt;
        {&lt;br /&gt;
            &lt;span style="color: blue;"&gt;get&lt;/span&gt; { &lt;span style="color: blue;"&gt;throw&lt;/span&gt; &lt;span style="color: blue;"&gt;new&lt;/span&gt; &lt;span style="color: rgb(43, 145, 175);"&gt;Exception&lt;/span&gt;(&lt;span style="color: rgb(163, 21, 21);"&gt;"The method or operation is not implemented."&lt;/span&gt;); }&lt;br /&gt;
        }&lt;br /&gt;
 &lt;br /&gt;
        &lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: rgb(43, 145, 175);"&gt;DataTable&lt;/span&gt; GetSchemaTable()&lt;br /&gt;
        {&lt;br /&gt;
            &lt;span style="color: blue;"&gt;return&lt;/span&gt; _source.Table;&lt;br /&gt;
        }&lt;br /&gt;
 &lt;br /&gt;
        &lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;bool&lt;/span&gt; IsClosed&lt;br /&gt;
        {&lt;br /&gt;
            &lt;span style="color: blue;"&gt;get&lt;/span&gt; { &lt;span style="color: blue;"&gt;return&lt;/span&gt; _closed; }&lt;br /&gt;
        }&lt;br /&gt;
 &lt;br /&gt;
        &lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;bool&lt;/span&gt; NextResult()&lt;br /&gt;
        {&lt;br /&gt;
            &lt;span style="color: blue;"&gt;return&lt;/span&gt; false;&lt;br /&gt;
        }&lt;br /&gt;
 &lt;br /&gt;
        &lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;bool&lt;/span&gt; Read()&lt;br /&gt;
        {&lt;br /&gt;
            &lt;span style="color: blue;"&gt;if&lt;/span&gt; (_closed)&lt;br /&gt;
                _enum = _source.GetEnumerator();&lt;br /&gt;
 &lt;br /&gt;
            _closed = &lt;span style="color: blue;"&gt;false&lt;/span&gt;;&lt;br /&gt;
            &lt;span style="color: blue;"&gt;return&lt;/span&gt; _enum.MoveNext();&lt;br /&gt;
        }&lt;br /&gt;
 &lt;br /&gt;
        &lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;int&lt;/span&gt; RecordsAffected&lt;br /&gt;
        {&lt;br /&gt;
            &lt;span style="color: blue;"&gt;get&lt;/span&gt; { &lt;span style="color: blue;"&gt;throw&lt;/span&gt; &lt;span style="color: blue;"&gt;new&lt;/span&gt; &lt;span style="color: rgb(43, 145, 175);"&gt;Exception&lt;/span&gt;(&lt;span style="color: rgb(163, 21, 21);"&gt;"The method or operation is not implemented."&lt;/span&gt;); }&lt;br /&gt;
        }&lt;br /&gt;
 &lt;br /&gt;
&lt;span style="color: blue;"&gt;        #endregion&lt;/span&gt;&lt;br /&gt;
 &lt;br /&gt;
&lt;span style="color: blue;"&gt;        #region&lt;/span&gt; IDisposable Members&lt;br /&gt;
 &lt;br /&gt;
        &lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;void&lt;/span&gt; Dispose()&lt;br /&gt;
        {&lt;br /&gt;
            _source.Dispose();&lt;br /&gt;
        }&lt;br /&gt;
 &lt;br /&gt;
&lt;span style="color: blue;"&gt;        #endregion&lt;/span&gt;&lt;br /&gt;
 &lt;br /&gt;
&lt;span style="color: blue;"&gt;        #region&lt;/span&gt; IDataRecord Members&lt;br /&gt;
 &lt;br /&gt;
        &lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;int&lt;/span&gt; FieldCount&lt;br /&gt;
        {&lt;br /&gt;
            &lt;span style="color: blue;"&gt;get&lt;/span&gt; { &lt;span style="color: blue;"&gt;return&lt;/span&gt; _source.Table.Columns.Count; }&lt;br /&gt;
        }&lt;br /&gt;
 &lt;br /&gt;
        &lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;bool&lt;/span&gt; GetBoolean(&lt;span style="color: blue;"&gt;int&lt;/span&gt; i)&lt;br /&gt;
        {&lt;br /&gt;
            &lt;span style="color: blue;"&gt;return&lt;/span&gt; (&lt;span style="color: blue;"&gt;bool&lt;/span&gt;)current[i];&lt;br /&gt;
        }&lt;br /&gt;
 &lt;br /&gt;
        &lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;byte&lt;/span&gt; GetByte(&lt;span style="color: blue;"&gt;int&lt;/span&gt; i)&lt;br /&gt;
        {&lt;br /&gt;
            &lt;span style="color: blue;"&gt;return&lt;/span&gt; (&lt;span style="color: blue;"&gt;byte&lt;/span&gt;)current[i];&lt;br /&gt;
        }&lt;br /&gt;
 &lt;br /&gt;
        &lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;long&lt;/span&gt; GetBytes(&lt;span style="color: blue;"&gt;int&lt;/span&gt; i, &lt;span style="color: blue;"&gt;long&lt;/span&gt; fieldOffset, &lt;span style="color: blue;"&gt;byte&lt;/span&gt;[] buffer, &lt;span style="color: blue;"&gt;int&lt;/span&gt; bufferoffset, &lt;span style="color: blue;"&gt;int&lt;/span&gt; length)&lt;br /&gt;
        {&lt;br /&gt;
            &lt;span style="color: blue;"&gt;throw&lt;/span&gt; &lt;span style="color: blue;"&gt;new&lt;/span&gt; &lt;span style="color: rgb(43, 145, 175);"&gt;Exception&lt;/span&gt;(&lt;span style="color: rgb(163, 21, 21);"&gt;"The method or operation is not implemented."&lt;/span&gt;);&lt;br /&gt;
        }&lt;br /&gt;
 &lt;br /&gt;
        &lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;char&lt;/span&gt; GetChar(&lt;span style="color: blue;"&gt;int&lt;/span&gt; i)&lt;br /&gt;
        {&lt;br /&gt;
            &lt;span style="color: blue;"&gt;return&lt;/span&gt; (&lt;span style="color: blue;"&gt;char&lt;/span&gt;)current[i];&lt;br /&gt;
        }&lt;br /&gt;
 &lt;br /&gt;
        &lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;long&lt;/span&gt; GetChars(&lt;span style="color: blue;"&gt;int&lt;/span&gt; i, &lt;span style="color: blue;"&gt;long&lt;/span&gt; fieldoffset, &lt;span style="color: blue;"&gt;char&lt;/span&gt;[] buffer, &lt;span style="color: blue;"&gt;int&lt;/span&gt; bufferoffset, &lt;span style="color: blue;"&gt;int&lt;/span&gt; length)&lt;br /&gt;
        {&lt;br /&gt;
            &lt;span style="color: blue;"&gt;throw&lt;/span&gt; &lt;span style="color: blue;"&gt;new&lt;/span&gt; &lt;span style="color: rgb(43, 145, 175);"&gt;Exception&lt;/span&gt;(&lt;span style="color: rgb(163, 21, 21);"&gt;"The method or operation is not implemented."&lt;/span&gt;);&lt;br /&gt;
        }&lt;br /&gt;
 &lt;br /&gt;
        &lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: rgb(43, 145, 175);"&gt;IDataReader&lt;/span&gt; GetData(&lt;span style="color: blue;"&gt;int&lt;/span&gt; i)&lt;br /&gt;
        {&lt;br /&gt;
            &lt;span style="color: blue;"&gt;throw&lt;/span&gt; &lt;span style="color: blue;"&gt;new&lt;/span&gt; &lt;span style="color: rgb(43, 145, 175);"&gt;Exception&lt;/span&gt;(&lt;span style="color: rgb(163, 21, 21);"&gt;"The method or operation is not implemented."&lt;/span&gt;);&lt;br /&gt;
        }&lt;br /&gt;
 &lt;br /&gt;
        &lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;string&lt;/span&gt; GetDataTypeName(&lt;span style="color: blue;"&gt;int&lt;/span&gt; i)&lt;br /&gt;
        {&lt;br /&gt;
            &lt;span style="color: blue;"&gt;return&lt;/span&gt; current[i].GetType().Name;&lt;br /&gt;
        }&lt;br /&gt;
 &lt;br /&gt;
        &lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: rgb(43, 145, 175);"&gt;DateTime&lt;/span&gt; GetDateTime(&lt;span style="color: blue;"&gt;int&lt;/span&gt; i)&lt;br /&gt;
        {&lt;br /&gt;
            &lt;span style="color: blue;"&gt;return&lt;/span&gt; (&lt;span style="color: rgb(43, 145, 175);"&gt;DateTime&lt;/span&gt;)current[i];&lt;br /&gt;
        }&lt;br /&gt;
 &lt;br /&gt;
        &lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;decimal&lt;/span&gt; GetDecimal(&lt;span style="color: blue;"&gt;int&lt;/span&gt; i)&lt;br /&gt;
        {&lt;br /&gt;
            &lt;span style="color: blue;"&gt;return&lt;/span&gt; (&lt;span style="color: rgb(43, 145, 175);"&gt;Decimal&lt;/span&gt;)current[i];&lt;br /&gt;
        }&lt;br /&gt;
 &lt;br /&gt;
        &lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;double&lt;/span&gt; GetDouble(&lt;span style="color: blue;"&gt;int&lt;/span&gt; i)&lt;br /&gt;
        {&lt;br /&gt;
            &lt;span style="color: blue;"&gt;return&lt;/span&gt; (&lt;span style="color: rgb(43, 145, 175);"&gt;Double&lt;/span&gt;)current[i];&lt;br /&gt;
        }&lt;br /&gt;
 &lt;br /&gt;
        &lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: rgb(43, 145, 175);"&gt;Type&lt;/span&gt; GetFieldType(&lt;span style="color: blue;"&gt;int&lt;/span&gt; i)&lt;br /&gt;
        {&lt;br /&gt;
            &lt;span style="color: blue;"&gt;return&lt;/span&gt; current[i].GetType();&lt;br /&gt;
        }&lt;br /&gt;
 &lt;br /&gt;
        &lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;float&lt;/span&gt; GetFloat(&lt;span style="color: blue;"&gt;int&lt;/span&gt; i)&lt;br /&gt;
        {&lt;br /&gt;
            &lt;span style="color: blue;"&gt;return&lt;/span&gt; (&lt;span style="color: blue;"&gt;float&lt;/span&gt;)current[i];&lt;br /&gt;
        }&lt;br /&gt;
 &lt;br /&gt;
        &lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: rgb(43, 145, 175);"&gt;Guid&lt;/span&gt; GetGuid(&lt;span style="color: blue;"&gt;int&lt;/span&gt; i)&lt;br /&gt;
        {&lt;br /&gt;
            &lt;span style="color: blue;"&gt;return&lt;/span&gt; (&lt;span style="color: rgb(43, 145, 175);"&gt;Guid&lt;/span&gt;)current[i];&lt;br /&gt;
        }&lt;br /&gt;
 &lt;br /&gt;
        &lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;short&lt;/span&gt; GetInt16(&lt;span style="color: blue;"&gt;int&lt;/span&gt; i)&lt;br /&gt;
        {&lt;br /&gt;
            &lt;span style="color: blue;"&gt;return&lt;/span&gt; (&lt;span style="color: blue;"&gt;short&lt;/span&gt;)current[i];&lt;br /&gt;
        }&lt;br /&gt;
 &lt;br /&gt;
        &lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;int&lt;/span&gt; GetInt32(&lt;span style="color: blue;"&gt;int&lt;/span&gt; i)&lt;br /&gt;
        {&lt;br /&gt;
            &lt;span style="color: blue;"&gt;return&lt;/span&gt; (&lt;span style="color: blue;"&gt;int&lt;/span&gt;)current[i];&lt;br /&gt;
        }&lt;br /&gt;
 &lt;br /&gt;
        &lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;long&lt;/span&gt; GetInt64(&lt;span style="color: blue;"&gt;int&lt;/span&gt; i)&lt;br /&gt;
        {&lt;br /&gt;
            &lt;span style="color: blue;"&gt;return&lt;/span&gt; (&lt;span style="color: blue;"&gt;long&lt;/span&gt;)current[i];&lt;br /&gt;
        }&lt;br /&gt;
 &lt;br /&gt;
        &lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;string&lt;/span&gt; GetName(&lt;span style="color: blue;"&gt;int&lt;/span&gt; i)&lt;br /&gt;
        {&lt;br /&gt;
            &lt;span style="color: blue;"&gt;return&lt;/span&gt; _source.Table.Columns[i].ColumnName;&lt;br /&gt;
        }&lt;br /&gt;
 &lt;br /&gt;
        &lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;int&lt;/span&gt; GetOrdinal(&lt;span style="color: blue;"&gt;string&lt;/span&gt; name)&lt;br /&gt;
        {&lt;br /&gt;
            &lt;span style="color: blue;"&gt;return&lt;/span&gt; _source.Table.Columns[name].Ordinal;&lt;br /&gt;
        }&lt;br /&gt;
 &lt;br /&gt;
        &lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;string&lt;/span&gt; GetString(&lt;span style="color: blue;"&gt;int&lt;/span&gt; i)&lt;br /&gt;
        {&lt;br /&gt;
            &lt;span style="color: blue;"&gt;return&lt;/span&gt; (&lt;span style="color: blue;"&gt;string&lt;/span&gt;)current[i];&lt;br /&gt;
        }&lt;br /&gt;
 &lt;br /&gt;
        &lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;object&lt;/span&gt; GetValue(&lt;span style="color: blue;"&gt;int&lt;/span&gt; i)&lt;br /&gt;
        {&lt;br /&gt;
            &lt;span style="color: blue;"&gt;return&lt;/span&gt; current[i];&lt;br /&gt;
        }&lt;br /&gt;
 &lt;br /&gt;
        &lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;int&lt;/span&gt; GetValues(&lt;span style="color: blue;"&gt;object&lt;/span&gt;[] values)&lt;br /&gt;
        {&lt;br /&gt;
            &lt;span style="color: blue;"&gt;int&lt;/span&gt; count = &lt;span style="color: rgb(43, 145, 175);"&gt;Math&lt;/span&gt;.Min(values.Length, FieldCount);&lt;br /&gt;
 &lt;br /&gt;
            &lt;span style="color: blue;"&gt;for&lt;/span&gt; (&lt;span style="color: blue;"&gt;int&lt;/span&gt; i = 0; i &amp;lt; count; i++)&lt;br /&gt;
                values[i] = current[i];&lt;br /&gt;
 &lt;br /&gt;
            &lt;span style="color: blue;"&gt;return&lt;/span&gt; count;&lt;br /&gt;
        }&lt;br /&gt;
 &lt;br /&gt;
        &lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;bool&lt;/span&gt; IsDBNull(&lt;span style="color: blue;"&gt;int&lt;/span&gt; i)&lt;br /&gt;
        {&lt;br /&gt;
            &lt;span style="color: blue;"&gt;return&lt;/span&gt; current[i] == &lt;span style="color: rgb(43, 145, 175);"&gt;DBNull&lt;/span&gt;.Value;&lt;br /&gt;
        }&lt;br /&gt;
 &lt;br /&gt;
        &lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;object&lt;/span&gt; &lt;span style="color: blue;"&gt;this&lt;/span&gt;[&lt;span style="color: blue;"&gt;string&lt;/span&gt; name]&lt;br /&gt;
        {&lt;br /&gt;
            &lt;span style="color: blue;"&gt;get&lt;/span&gt; { &lt;span style="color: blue;"&gt;return&lt;/span&gt; current[name]; }&lt;br /&gt;
        }&lt;br /&gt;
 &lt;br /&gt;
        &lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;object&lt;/span&gt; &lt;span style="color: blue;"&gt;this&lt;/span&gt;[&lt;span style="color: blue;"&gt;int&lt;/span&gt; i]&lt;br /&gt;
        {&lt;br /&gt;
            &lt;span style="color: blue;"&gt;get&lt;/span&gt; { &lt;span style="color: blue;"&gt;return&lt;/span&gt; current[i]; }&lt;br /&gt;
        }&lt;br /&gt;
 &lt;br /&gt;
&lt;span style="color: blue;"&gt;        #endregion&lt;/span&gt;&lt;br /&gt;
    }&lt;br /&gt;
&lt;/div&gt;&lt;img src="http://weblogs.sqlteam.com/jeffs/aggbug/60540.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Jeff Smith</dc:creator>
            <guid>http://weblogs.sqlteam.com/jeffs/archive/2008/02/28/DataViewReader.aspx</guid>
            <pubDate>Thu, 28 Feb 2008 15:34:22 GMT</pubDate>
            <wfw:comment>http://weblogs.sqlteam.com/jeffs/comments/60540.aspx</wfw:comment>
            <comments>http://weblogs.sqlteam.com/jeffs/archive/2008/02/28/DataViewReader.aspx#feedback</comments>
            <slash:comments>4</slash:comments>
            <wfw:commentRss>http://weblogs.sqlteam.com/jeffs/comments/commentRss/60540.aspx</wfw:commentRss>
            <trackback:ping>http://weblogs.sqlteam.com/jeffs/services/trackbacks/60540.aspx</trackback:ping>
        </item>
        <item>
            <title>Exporting data to a remote server with SQL Express</title>
            <link>http://weblogs.sqlteam.com/jeffs/archive/2008/02/27/60539.aspx</link>
            <description>I recently helped a friend out who only had access to &lt;a href="http://www.microsoft.com/downloads/details.aspx?FamilyID=c243a5ae-4bd1-4e3d-94b8-5a0f62bf7796&amp;amp;displaylang=en" target="_blank"&gt;SQL Server Management Studio Express&lt;/a&gt;, and he needed to copy a database locally from his PC to his remote web hosting company.  Normally, the process is a simple backup/restore, but his hosting company does not allow restoring databases.  Luckily, however, the company does allow direct access to his hosted database via client tools such as SSMS.  Unluckily, SSMS Express does not include any tools that allow you to export data to a remote server.&lt;br /&gt;
&lt;br /&gt;
So, here's what we did:  First, we scripted out the entire database, including all tables, indexes, constraints, views, functions, procs, etc, using SSMS Express.  This took some time to execute, but it was easy to do.&lt;br /&gt;
&lt;br /&gt;
Then, we ran that script remotely on the hosted database to create the environment.  Easy enough.&lt;br /&gt;
&lt;br /&gt;
The final step was potentially the hardest part: Now we had to copy all of the data in all of the tables from the local database to the remote database.  I thought about generating INSERT scripts, or even using a tool like MS Access (via linked tables) to get this done, but I decided against them because the INSERT script would be huge (there is a lot of data we are inserting) and any of these methods would require loading data in the exact order needed to satisfy FK constraints.  In addition, there was the issue of IDENTITY values and handling that.  All could be done, of course, but we were pressed for time and we needed something simple and efficient and that we could easily run again and again as needed.&lt;br /&gt;
&lt;br /&gt;
Then, I remembered my little friend &lt;a target="_blank" href="http://www.sqlteam.com/article/use-sqlbulkcopy-to-quickly-load-data-from-your-client-to-sql-server"&gt;SQLBulkCopy&lt;/a&gt;, the really handy .NET 2.0 class that facilitates quickly copying data to a SQL Server database.  I had forgotten it includes options to allow for identity values to be specified when bulk inserting, and for FK constraints to be be ignored as well.  So, the order that the tables are uploaded in doesn't matter, and identity values are handled fine as well.&lt;br /&gt;
&lt;br /&gt;
A few minutes later, a simple C# console app was written and we were ready to roll:&lt;br /&gt;
&lt;br /&gt;
&lt;div style="background: white none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; font-family: Verdana; font-size: 8pt; line-height: 10pt; color: black; margin-left: 40px;"&gt; &lt;span style="color: blue;"&gt;using&lt;/span&gt; System;&lt;br /&gt;
&lt;span style="color: blue;"&gt;using&lt;/span&gt; System.Data;&lt;br /&gt;
&lt;span style="color: blue;"&gt;using&lt;/span&gt; System.Collections.Generic;&lt;br /&gt;
&lt;span style="color: blue;"&gt;using&lt;/span&gt; System.Data.SqlClient;&lt;br /&gt;
&lt;span style="color: blue;"&gt;using&lt;/span&gt; System.Text;&lt;br /&gt;
 &lt;br /&gt;
&lt;span style="color: blue;"&gt;namespace&lt;/span&gt; CopyData&lt;br /&gt;
{&lt;br /&gt;
    &lt;span style="color: blue;"&gt;class&lt;/span&gt; &lt;span style="color: rgb(43, 145, 175);"&gt;Program&lt;/span&gt;&lt;br /&gt;
    {&lt;br /&gt;
        &lt;span style="color: blue;"&gt;static&lt;/span&gt; &lt;span style="color: blue;"&gt;void&lt;/span&gt; Main(&lt;span style="color: blue;"&gt;string&lt;/span&gt;[] args)&lt;br /&gt;
        {&lt;br /&gt;
            &lt;span style="color: blue;"&gt;string&lt;/span&gt; Src=&lt;span style="color: rgb(163, 21, 21);"&gt;"-- source connection string here--"&lt;/span&gt;;&lt;br /&gt;
            &lt;span style="color: blue;"&gt;string&lt;/span&gt; Dest = &lt;span style="color: rgb(163, 21, 21);"&gt;"-- dest connection string here --"&lt;/span&gt;;&lt;br /&gt;
            &lt;span style="color: blue;"&gt;int&lt;/span&gt; BatchSize = 500;&lt;br /&gt;
            &lt;span style="color: blue;"&gt;int&lt;/span&gt; NotifyAfter = 500;&lt;br /&gt;
 &lt;br /&gt;
            &lt;span style="color: rgb(43, 145, 175);"&gt;SqlBulkCopy&lt;/span&gt; c = &lt;span style="color: blue;"&gt;new&lt;/span&gt; &lt;span style="color: rgb(43, 145, 175);"&gt;SqlBulkCopy&lt;/span&gt;(Dest, &lt;span style="color: rgb(43, 145, 175);"&gt;SqlBulkCopyOptions&lt;/span&gt;.KeepIdentity | &lt;span style="color: rgb(43, 145, 175);"&gt;SqlBulkCopyOptions&lt;/span&gt;.TableLock);&lt;br /&gt;
            &lt;span style="color: rgb(43, 145, 175);"&gt;SqlConnection&lt;/span&gt; srcConn = &lt;span style="color: blue;"&gt;new&lt;/span&gt; &lt;span style="color: rgb(43, 145, 175);"&gt;SqlConnection&lt;/span&gt;(Src);&lt;br /&gt;
            srcConn.Open();&lt;br /&gt;
 &lt;br /&gt;
            &lt;span style="color: rgb(43, 145, 175);"&gt;SqlCommand&lt;/span&gt; cm = &lt;span style="color: blue;"&gt;new&lt;/span&gt; &lt;span style="color: rgb(43, 145, 175);"&gt;SqlCommand&lt;/span&gt;(&lt;span style="color: rgb(163, 21, 21);"&gt;"select * from sysobjects where type='u'"&lt;/span&gt;);&lt;br /&gt;
            cm.Connection = srcConn;&lt;br /&gt;
            cm.CommandType = &lt;span style="color: rgb(43, 145, 175);"&gt;CommandType&lt;/span&gt;.Text;&lt;br /&gt;
 &lt;br /&gt;
            &lt;span style="color: rgb(43, 145, 175);"&gt;DataTable&lt;/span&gt; AllTables = &lt;span style="color: blue;"&gt;new&lt;/span&gt; &lt;span style="color: rgb(43, 145, 175);"&gt;DataTable&lt;/span&gt;();&lt;br /&gt;
            &lt;span style="color: rgb(43, 145, 175);"&gt;SqlDataAdapter&lt;/span&gt; a = &lt;span style="color: blue;"&gt;new&lt;/span&gt; &lt;span style="color: rgb(43, 145, 175);"&gt;SqlDataAdapter&lt;/span&gt;(cm);&lt;br /&gt;
            a.Fill(AllTables);&lt;br /&gt;
            &lt;span style="color: rgb(43, 145, 175);"&gt;SqlDataReader&lt;/span&gt; dr;&lt;br /&gt;
 &lt;br /&gt;
            &lt;span style="color: blue;"&gt;int&lt;/span&gt; n = 0;&lt;br /&gt;
            &lt;span style="color: blue;"&gt;int&lt;/span&gt; tot = AllTables.Rows.Count;&lt;br /&gt;
 &lt;br /&gt;
            &lt;span style="color: rgb(43, 145, 175);"&gt;Console&lt;/span&gt;.WriteLine(&lt;span style="color: rgb(163, 21, 21);"&gt;"Found {0} Tables to copy."&lt;/span&gt;, tot);&lt;br /&gt;
            &lt;span style="color: rgb(43, 145, 175);"&gt;Console&lt;/span&gt;.WriteLine(&lt;span style="color: rgb(163, 21, 21);"&gt;""&lt;/span&gt;);&lt;br /&gt;
 &lt;br /&gt;
            c.SqlRowsCopied += &lt;span style="color: blue;"&gt;new&lt;/span&gt; &lt;span style="color: rgb(43, 145, 175);"&gt;SqlRowsCopiedEventHandler&lt;/span&gt;(c_SqlRowsCopied);&lt;br /&gt;
            &lt;span style="color: blue;"&gt;foreach&lt;/span&gt; (&lt;span style="color: rgb(43, 145, 175);"&gt;DataRow&lt;/span&gt; r &lt;span style="color: blue;"&gt;in&lt;/span&gt; AllTables.Rows)&lt;br /&gt;
            {&lt;br /&gt;
                &lt;span style="color: rgb(43, 145, 175);"&gt;Console&lt;/span&gt;.WriteLine(&lt;span style="color: rgb(163, 21, 21);"&gt;"Coping table {0} of {1}: {2}"&lt;/span&gt;, ++n, tot, r[&lt;span style="color: rgb(163, 21, 21);"&gt;"name"&lt;/span&gt;]);&lt;br /&gt;
                cm.CommandText = &lt;span style="color: rgb(43, 145, 175);"&gt;String&lt;/span&gt;.Format(&lt;span style="color: rgb(163, 21, 21);"&gt;"select * from [{0}]"&lt;/span&gt;, r[&lt;span style="color: rgb(163, 21, 21);"&gt;"name"&lt;/span&gt;]);&lt;br /&gt;
                dr = cm.ExecuteReader();&lt;br /&gt;
                c.BatchSize = BatchSize;&lt;br /&gt;
                c.DestinationTableName = r[&lt;span style="color: rgb(163, 21, 21);"&gt;"name"&lt;/span&gt;].ToString();&lt;br /&gt;
                c.NotifyAfter = NotifyAfter;&lt;br /&gt;
                c.WriteToServer(dr);&lt;br /&gt;
                dr.Close();&lt;br /&gt;
            }&lt;br /&gt;
 &lt;br /&gt;
            srcConn.Close();&lt;br /&gt;
            c.Close();&lt;br /&gt;
 &lt;br /&gt;
            &lt;span style="color: rgb(43, 145, 175);"&gt;Console&lt;/span&gt;.WriteLine(&lt;span style="color: rgb(163, 21, 21);"&gt;""&lt;/span&gt;);&lt;br /&gt;
            &lt;span style="color: rgb(43, 145, 175);"&gt;Console&lt;/span&gt;.WriteLine(&lt;span style="color: rgb(163, 21, 21);"&gt;"Done .. press any key."&lt;/span&gt;);&lt;br /&gt;
            &lt;span style="color: rgb(43, 145, 175);"&gt;Console&lt;/span&gt;.ReadLine();&lt;br /&gt;
        }&lt;br /&gt;
 &lt;br /&gt;
        &lt;span style="color: blue;"&gt;static&lt;/span&gt; &lt;span style="color: blue;"&gt;void&lt;/span&gt; c_SqlRowsCopied(&lt;span style="color: blue;"&gt;object&lt;/span&gt; sender, &lt;span style="color: rgb(43, 145, 175);"&gt;SqlRowsCopiedEventArgs&lt;/span&gt; e)&lt;br /&gt;
        {&lt;br /&gt;
            &lt;span style="color: rgb(43, 145, 175);"&gt;Console&lt;/span&gt;.WriteLine(&lt;span style="color: rgb(163, 21, 21);"&gt;" -- copied {0} rows ..."&lt;/span&gt;, e.RowsCopied);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;/div&gt;
&lt;br /&gt;
That's pretty much it... The app runs quicky, gives a nice progress report as it goes, and can easily be modified to use command line arguments or whatever else you need to make it simple and re-usable.&lt;br /&gt;
&lt;br /&gt;
So, if you are using SQL Express to develop an application, and you need to export that database to a hosted web server and a simple backup/restore is not an option, here's all you need to do:&lt;br /&gt;
&lt;br /&gt;
1) Create your destination database&lt;br /&gt;
2) Script out all objects in your source database&lt;br /&gt;
3) Run the script in your destination database&lt;br /&gt;
4) Create the C# console application shown above, enter in your connection strings in the first few lines where indicated, and run it.&lt;br /&gt;
&lt;br /&gt;
That's it!  Quick, simple and easy, and really not much harder than a backup/restore would be at all ... in fact, in some ways it is even easier than FTP'ing a backup to your hosted server and dealing with all that.&lt;br /&gt;
&lt;br /&gt;
If you are you using &lt;a target="_blank" href="http://www.microsoft.com/express/vwd/Default.aspx"&gt;Visual Web Developer&lt;/a&gt; to write your application, and therefore don't have the ability to write console applications like the one shown to do your export, you can do this by downloading &lt;a target="_blank" href="http://www.microsoft.com/express/vcsharp/"&gt;Visual C# Express&lt;/a&gt;.&lt;img src="http://weblogs.sqlteam.com/jeffs/aggbug/60539.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Jeff Smith</dc:creator>
            <guid>http://weblogs.sqlteam.com/jeffs/archive/2008/02/27/60539.aspx</guid>
            <pubDate>Wed, 27 Feb 2008 20:04:45 GMT</pubDate>
            <wfw:comment>http://weblogs.sqlteam.com/jeffs/comments/60539.aspx</wfw:comment>
            <comments>http://weblogs.sqlteam.com/jeffs/archive/2008/02/27/60539.aspx#feedback</comments>
            <slash:comments>6</slash:comments>
            <wfw:commentRss>http://weblogs.sqlteam.com/jeffs/comments/commentRss/60539.aspx</wfw:commentRss>
            <trackback:ping>http://weblogs.sqlteam.com/jeffs/services/trackbacks/60539.aspx</trackback:ping>
        </item>
        <item>
            <title>Splitting a single DataTable into Parent/Child DataTables for Hierarchical Processing (e.g., nested ASP.NET Repeater controls)</title>
            <link>http://weblogs.sqlteam.com/jeffs/archive/2007/11/02/parent-child-datatable-nested-repeaters.aspx</link>
            <description>In ASP.NET, we often would like to output "grouped" data on our web pages, like this:&lt;br /&gt;
&lt;br /&gt;
&lt;div style="margin-left: 40px;"&gt;&lt;span style="font-family: Courier New;"&gt;Customer Product     Sales&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;-------- ----------  -----&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;ABC Foundation&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;         Product 1   $200&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;         Product 2   $437&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;         Product 3   $523&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;        &lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;The XLZ Company&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;         Product 1   $240&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;         Product 2   $892&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;         Product 3   $395&lt;/span&gt;&lt;br /&gt;
&lt;/div&gt;
   &lt;br /&gt;
The easiest way to do this is with nested &lt;a href="http://msdn2.microsoft.com/en-us/library/system.web.ui.webcontrols.repeater(VS.80).aspx" target="_blank"&gt;Repeater&lt;/a&gt; controls; one for the outer group (Customers, this case), and within that Repeater's ItemTemplate we'd have another Repeater control for the details (Products).  &lt;br /&gt;
&lt;br /&gt;
To use nested repeaters, you would return two separate result sets from SQL:  &lt;br /&gt;
&lt;ol&gt;
    &lt;li&gt;A "Customers" result set, listing one row per Customer to display on the report&lt;/li&gt;
    &lt;li&gt;A "Products" result set, listing one row per Product to display.&lt;/li&gt;
&lt;/ol&gt;
You would put both of those results into a single DataSet as DataTables, and then create a relation between the two (on the CustomerID column).   Now, in our DataSet, we have a parent-child relation and each row in the parent Customers DataTable will have related child rows in the Products DataTable.&lt;br /&gt;
&lt;br /&gt;
Then, in ASP.NET, we create nested repeaters:  the outer repeater is bound to the Customers DataTable, and the inner repeater gets bound for each Customer row to the child rows in the Products DataTable.    There are lots of good examples detailing this technique &lt;a target="_blank" href="http://www.gridviewguy.com/ArticleDetails.aspx?articleID=185"&gt;here&lt;/a&gt; and &lt;a target="_blank" href="http://msdn2.microsoft.com/en-us/library/aa478959.aspx"&gt;here&lt;/a&gt;, so I won't get into specifics on that in this space.&lt;br /&gt;
&lt;br /&gt;
However -- what if you already have a stored procedure that returns this data in a single result set? The nested Repeater controls won't do you much good, since we need two separate (but related) DataTables.  Or, what if it is inefficient to return these results separately in SQL?  For example, suppose we want to output only the products for customers that have a total sales of greater than $200 for a specified time period.  We'd need to process the sales transactions table &lt;span style="font-style: italic;"&gt;twice&lt;/span&gt; in SQL to generate the list of Customers separate from the list of Products.  Thus, our SQL becomes twice as inefficient as it needs to be to use this technique.&lt;br /&gt;
&lt;br /&gt;
To accommodate those possibilities, I recently wrote a simple function in C# that takes a single DataTable and creates a related parent DataTable in the same DataSet based on specified parameters.  This is useful if you only have a single result set from SQL (or any other data source) and you'd like to break that data up into two separate parent-child DataTables in order to use nested repeaters or any other type of parent-child processing on the data.&lt;br /&gt;
&lt;br /&gt;
As an example, if you start with a single DataTable like this:&lt;br /&gt;
&lt;br /&gt;
&lt;div style="margin-left: 40px;"&gt;&lt;span style="font-family: Courier New;"&gt;Products:&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;CustomerID  CustomerName    Product     Sales&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;----------  --------------- ----------  -----&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;1           ABC Foundation  Product 1   $200&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;1           ABC Foundation  Product 2   $437&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;1           ABC Foundation  Product 3   $523&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;2           The XLZ Company Product 1   $240&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;2           The XLZ Company Product 2   $892&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;2           The XLZ Company Product 3   $395&lt;/span&gt;&lt;br /&gt;
&lt;/div&gt;
&lt;br /&gt;
We can pass that DataTable to the CreateParentTable() function and you would end up with two related DataTables in the DataSet, like this:&lt;br /&gt;
&lt;br /&gt;
&lt;div style="margin-left: 40px;"&gt;&lt;span style="font-family: Courier New;"&gt;Customers:&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;CustomerID  CustomerName    &lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;----------  --------------- &lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;1           ABC Foundation  &lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;2           The XLZ Company&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;Products:&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;CustomerID  Product     Sales&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;----------  ----------  -----&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;1           Product 1   $200&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;1           Product 2   $437&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;1           Product 3   $523&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;2           Product 1   $240&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;2           Product 2   $892&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;2           Product 3   $395&lt;/span&gt;&lt;br /&gt;
&lt;/div&gt;
&lt;br /&gt;
Then we can simply bind the outer Repeater to the Customers DataTable, and then bind the inner Repeater to a call to each DataRow's GetChildRows() method to get the related products.  All from a single SQL result set.&lt;br /&gt;
&lt;br /&gt;
Also, notice that the function removes the CustomerName column from the Products DataTable, but leaves the CustomerID column for the relation.  &lt;br /&gt;
&lt;br /&gt;
Here's the function:&lt;br /&gt;
&lt;br style="font-family: Courier New;" /&gt;
&lt;div style="margin-left: 40px;"&gt;&lt;span style="font-family: Courier New; color: rgb(51, 153, 102);"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;&lt;br style="font-family: Courier New; color: rgb(51, 153, 102);" /&gt;
&lt;span style="font-family: Courier New; color: rgb(51, 153, 102);"&gt;///   Creates a parent DataTable within the DataSet using distinct rows from&lt;/span&gt;&lt;br style="font-family: Courier New; color: rgb(51, 153, 102);" /&gt;
&lt;span style="font-family: Courier New; color: rgb(51, 153, 102);"&gt;///   an existing "source" DataTable, based on the column(s) specified.&lt;/span&gt;&lt;br style="font-family: Courier New; color: rgb(51, 153, 102);" /&gt;
&lt;span style="font-family: Courier New; color: rgb(51, 153, 102);"&gt;///   The source table then becomes the "child" table of the newly created &lt;/span&gt;&lt;br style="font-family: Courier New; color: rgb(51, 153, 102);" /&gt;
&lt;span style="font-family: Courier New; color: rgb(51, 153, 102);"&gt;///   parent. A DataRelation is also created between the parent table and the &lt;/span&gt;&lt;br style="font-family: Courier New; color: rgb(51, 153, 102);" /&gt;
&lt;span style="font-family: Courier New; color: rgb(51, 153, 102);"&gt;///   child table, using the column(s) specified.&lt;/span&gt;&lt;br style="font-family: Courier New; color: rgb(51, 153, 102);" /&gt;
&lt;span style="font-family: Courier New; color: rgb(51, 153, 102);"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;&lt;br style="font-family: Courier New; color: rgb(51, 153, 102);" /&gt;
&lt;span style="font-family: Courier New; color: rgb(51, 153, 102);"&gt;/// &amp;lt;param name="sourceTable"&amp;gt;&lt;br /&gt;
///    The source DataTable, which must be within a DataSet.   &lt;br /&gt;
///    This source table will become the "child" table.&lt;br /&gt;
/// &amp;lt;/param&amp;gt;&lt;/span&gt;&lt;br style="font-family: Courier New; color: rgb(51, 153, 102);" /&gt;
&lt;span style="font-family: Courier New; color: rgb(51, 153, 102);"&gt;/// &amp;lt;param name="parentTableName"&amp;gt;&lt;br /&gt;
///    This name will be assigned to the parent table once it is created.&lt;br /&gt;
/// &amp;lt;/param&amp;gt;&lt;/span&gt;&lt;br style="font-family: Courier New; color: rgb(51, 153, 102);" /&gt;
&lt;span style="font-family: Courier New; color: rgb(51, 153, 102);"&gt;/// &amp;lt;param name="relationColumns"&amp;gt;&lt;br /&gt;
///    Specify the columns used to relate the parent table to the child table.&lt;br /&gt;
/// &amp;lt;/param&amp;gt;&lt;/span&gt;&lt;br style="font-family: Courier New; color: rgb(51, 153, 102);" /&gt;
&lt;span style="font-family: Courier New; color: rgb(51, 153, 102);"&gt;/// &amp;lt;param name="additionalColumns"&amp;gt;&lt;br /&gt;
///    Any additional column(s) in the source table that will be extracted to the &lt;br /&gt;
///    parent table.  These columns will be removed from the source table.&lt;br /&gt;
/// &amp;lt;/param&amp;gt;&lt;/span&gt;&lt;br style="font-family: Courier New; color: rgb(51, 153, 102);" /&gt;
&lt;span style="font-family: Courier New; color: rgb(51, 153, 102);"&gt;/// &amp;lt;param name="relationName"&amp;gt;&lt;br /&gt;
///    The name of the relation that will be created between the parent and &lt;br /&gt;
///    the child table.&lt;br /&gt;
/// &amp;lt;/param&amp;gt;&lt;/span&gt;&lt;br style="font-family: Courier New; color: rgb(51, 153, 102);" /&gt;
&lt;span style="font-family: Courier New;"&gt;&lt;span style="color: rgb(51, 153, 102);"&gt;/// &lt;/span&gt;&lt;br /&gt;
&lt;/span&gt;&lt;span style="font-family: Courier New;"&gt;public static void AddParentTable(DataTable sourceTable, string parentTableName, &lt;br /&gt;
     string[] relationColumns, string[] additionalColumns, string relationName)&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;{&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;    DataSet dataSet = sourceTable.DataSet;&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;    if (dataSet == null)&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;    {&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;        throw new Exception("The source DataTable must be contained in a DataSet");&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;    }&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New; color: rgb(51, 153, 102);"&gt;    // generate the set of columns to use to create the Parent table:&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;    string[] cols = new string[relationColumns.Length+additionalColumns.Length];&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;    relationColumns.CopyTo(cols,0);&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;    additionalColumns.CopyTo(cols,relationColumns.Length);&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New; color: rgb(51, 153, 102);"&gt;    // create the parent table, copying unique rows from the Child table:&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;    DataTable parent = sourceTable.DefaultView.ToTable(parentTableName, true, cols);&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;    &lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New; color: rgb(51, 153, 102);"&gt;    // add the parent table to the DataSet:&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;    dataSet.Tables.Add(parent);&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New; color: rgb(51, 153, 102);"&gt;    // remove the additional columns from the child table that were &lt;br /&gt;
    // copied to the parent table:&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;    foreach (string s in additionalColumns)&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;        sourceTable.Columns.Remove(s);&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New; color: rgb(51, 153, 102);"&gt;    // create the relation between the new parent table and the child table:&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;    DataColumn[] parentColumns = new DataColumn[relationColumns.Length];&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;    DataColumn[] childColumns = new DataColumn[relationColumns.Length];&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;    for (int i=0; i&amp;lt; relationColumns.Length;i++)&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;    {&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;        parentColumns[i] = parent.Columns[relationColumns[i]];&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;        childColumns[i] = sourceTable.Columns[relationColumns[i]];&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;    }&lt;br /&gt;
&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New; color: rgb(51, 153, 102);"&gt;    // And, finally, add the relation to the parent table:&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;    parent.ChildRelations.Add(relationName, parentColumns, childColumns);&lt;/span&gt;&lt;span style="font-family: Courier New;"&gt;&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;}&lt;/span&gt;&lt;br /&gt;
&lt;/div&gt;
&lt;br /&gt;
The parameters are all explained in the XML documentation.  Feel free to make modifications or overloads of this function.  Some good overloads might be one that accepts a single relation column name, or that accepts a parameter that determines whether or not columns are removed from the child table.&lt;br /&gt;
    &lt;br /&gt;
Using our example, we'd call it like this:&lt;br /&gt;
&lt;br /&gt;
&lt;div style="margin-left: 40px;"&gt;&lt;span style="font-family: Courier New;"&gt;SqlConnection cn = new SqlConnection(&lt;span style="font-style: italic;"&gt;&amp;lt;... your connection string ...&amp;gt;&lt;/span&gt;)&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;SqlCommand cm = new SqlCommand(&lt;span style="font-style: italic;"&gt;&amp;lt;... the name of the stored proc ...&amp;gt;&lt;/span&gt;, cn);&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;cm.CommandType= CommandType.StoredProcedure;&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;cn.Open();&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;SqlDataAdapter da = new SqlDataAdapter(cm);&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;DataSet ds = new DataSet();&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;da.Fill(ds, "Products");&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;CreateParentTable(ds.Tables["Products"], "Customers", new string[] {"CustomerID"}, &lt;br /&gt;
    new string[] {"CustomerName"}, "CustomerProducts")&lt;/span&gt;&lt;br /&gt;
&lt;/div&gt;
&lt;br /&gt;
After that is executed, the DataSet now contains an additional "Customers" table, and a relation called "CustomerProducts" to the "Products" table.   The relation is on "CustomerID", and the "Customers" table also includes the "CustomerName" column.  &lt;br /&gt;
&lt;br /&gt;
Thus, if we had nested repeaters in our ASP.NET code like this:&lt;br /&gt;
&lt;br /&gt;
&lt;div style="margin-left: 40px;"&gt;&lt;span style="font-family: Courier New;"&gt; &amp;lt;table&amp;gt;&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;    &amp;lt;tr&amp;gt;&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;        &amp;lt;th&amp;gt;Customer&amp;lt;/th&amp;gt;&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;       &amp;lt;th&amp;gt;Product&amp;lt;/th&amp;gt; &lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;       &amp;lt;th&amp;gt;Sales&amp;lt;/th&amp;gt;&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;    &amp;lt;/tr&amp;gt;&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;&amp;lt;asp:Repeater runat="server" ID="rpt1"&amp;gt;&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;    &amp;lt;ItemTemplate&amp;gt;&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;       &amp;lt;tr&amp;gt;&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;            &amp;lt;td colspan="3"&amp;gt;&amp;lt;%# ((System.Data.DataRowView) Container.DataItem)["CustomerName"] %&amp;gt;&amp;lt;/td&amp;gt;&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;       &amp;lt;/tr&amp;gt; &lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;       &amp;lt;asp:Repeater runat="server" ID="rpt2"  &lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;          DataSource='&amp;lt;%# ((System.Data.DataRowView) Container.DataItem).Row.GetChildRows("CustomerProducts") %&amp;gt;'&amp;gt;&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;            &amp;lt;ItemTemplate&amp;gt;&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;            &amp;lt;tr&amp;gt;&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;                &amp;lt;td&amp;gt;&amp;lt;/td&amp;gt;&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;                &amp;lt;td&amp;gt; &amp;lt;%# ((System.Data.DataRow) Container.DataItem)["Product"] %&amp;gt;&amp;lt;/td&amp;gt;&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;                &amp;lt;td&amp;gt; &amp;lt;%# ((System.Data.DataRow) Container.DataItem)["Sales"] %&amp;gt;&amp;lt;/td&amp;gt;&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;            &amp;lt;/tr&amp;gt;&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;        &amp;lt;/ItemTemplate&amp;gt; &lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;       &amp;lt;/asp:Repeater&amp;gt;&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;    &amp;lt;/ItemTemplate&amp;gt;&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;&amp;lt;/asp:Repeater&amp;gt;&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;&amp;lt;/table&amp;gt; &lt;/span&gt;&lt;br /&gt;
&lt;/div&gt;
&lt;span style="font-family: Courier New;"&gt;&lt;br /&gt;
&lt;/span&gt; we can simply assign rpt1's DataSource to our DataSet, set its DataMember as "Customers", call DataBind(), and we are good to go:&lt;span style="font-family: Courier New;"&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;div style="margin-left: 40px;"&gt;&lt;span style="font-family: Courier New;"&gt;rpt1.DataSource = ds;&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;rpt1.DataMember = "Customers";&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;rpt1.DataBind();&lt;/span&gt;&lt;br /&gt;
&lt;/div&gt;
&lt;br /&gt;
&lt;/span&gt; A couple of more notes:
&lt;ol&gt;
    &lt;li&gt;The outer Repeater's DataItems are DataRowView objects, but the inner Repeater's DataItems are DataRows.  This is because we called the DataRowView's DataRow's GetChildRows() method, and not the DataRowView's CreateChildView() method.  I have found that this provides much better performance.  For small results, you may wish to call CreateChildView().&lt;br /&gt;
    &lt;br /&gt;
    &lt;/li&gt;
    &lt;li&gt;Instead of databinding in the HTML markup, you may wish to bind the inner Repeaters during the outer Repeater's DataBinding() event.  This keeps your HTML markup a little cleaner and shorter.&lt;br /&gt;
    &lt;br /&gt;
    &lt;/li&gt;
    &lt;li&gt;This function only works in .NET 2.0 or above, since it uses ToTable() method of the DataRowView class. &lt;/li&gt;
&lt;/ol&gt;
For more on nested repeaters, see:&lt;br /&gt;
&lt;ul&gt;
    &lt;li&gt;&lt;a target="_blank" href="http://support.microsoft.com/default.aspx/kb/326338"&gt;http://support.microsoft.com/default.aspx/kb/326338&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a target="_blank" href="http://msdn2.microsoft.com/en-us/library/aa478959.aspx"&gt;http://msdn2.microsoft.com/en-us/library/aa478959.aspx&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a target="_blank" href="http://www.gridviewguy.com/ArticleDetails.aspx?articleID=185"&gt;http://www.gridviewguy.com/ArticleDetails.aspx?articleID=185&lt;/a&gt;&lt;br /&gt;
    &lt;/li&gt;
&lt;/ul&gt;
Note that all of those example use two separate SQL result sets.  Using the function provided, we can do the same with a single result.&lt;br /&gt;
&lt;br /&gt;
&lt;span style="font-style: italic;"&gt;see also:&lt;/span&gt;&lt;br /&gt;
&lt;ul&gt;
    &lt;li&gt;&lt;a id="ctl00_pageContent_Editor_Results_rprSelectionList_ctl02_HyperLink1" title="View Entry" href="../../../../jeffs/archive/2007/10/17/60375.aspx"&gt;Some HTML / ASP.NET Thoughts ...&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a title="View Entry" href="../../../../jeffs/archive/2007/10/09/csv-strings-database-or-presentation.aspx"&gt;Creating CSV strings in SQL: Should Concatenation and Formatting Be Done at the Database Layer?&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a title="View Entry" href="../../../../jeffs/archive/2007/03/28/60144.aspx"&gt;ASP.NET 1.1 -- Appsettings in Web.config&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a id="ctl00_pageContent_Editor_Results_rprSelectionList_ctl06_HyperLink1" title="View Entry" href="../../../../jeffs/archive/2006/07/11/10572.aspx"&gt;Minimizing the ViewState for an ASP.NET 1.1 DataGrid&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;img src="http://weblogs.sqlteam.com/jeffs/aggbug/60391.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Jeff Smith</dc:creator>
            <guid>http://weblogs.sqlteam.com/jeffs/archive/2007/11/02/parent-child-datatable-nested-repeaters.aspx</guid>
            <pubDate>Fri, 02 Nov 2007 16:16:21 GMT</pubDate>
            <wfw:comment>http://weblogs.sqlteam.com/jeffs/comments/60391.aspx</wfw:comment>
            <comments>http://weblogs.sqlteam.com/jeffs/archive/2007/11/02/parent-child-datatable-nested-repeaters.aspx#feedback</comments>
            <wfw:commentRss>http://weblogs.sqlteam.com/jeffs/comments/commentRss/60391.aspx</wfw:commentRss>
            <trackback:ping>http://weblogs.sqlteam.com/jeffs/services/trackbacks/60391.aspx</trackback:ping>
        </item>
        <item>
            <title>Regular Expression Replace in SQL 2005  (via the CLR)</title>
            <link>http://weblogs.sqlteam.com/jeffs/archive/2007/04/27/SQL-2005-Regular-Expression-Replace.aspx</link>
            <description>I had to do some data clean up the other day, and really needed some regular expression replacements to do the job.  Since .NET has a great RegularExpressions namespace, and since SQL 2005 allows you to integrate .NET CLR functions in your T-SQL code, I thought I'd go ahead and experiment with creating a RegExReplace() function.   &lt;br&gt;&lt;br&gt;&lt;a href="http://weblogs.sqlteam.com/jeffs/archive/2007/04/27/SQL-2005-Regular-Expression-Replace.aspx"&gt;read more...&lt;/a&gt;&lt;img src="http://weblogs.sqlteam.com/jeffs/aggbug/60190.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Jeff Smith</dc:creator>
            <guid>http://weblogs.sqlteam.com/jeffs/archive/2007/04/27/SQL-2005-Regular-Expression-Replace.aspx</guid>
            <pubDate>Fri, 27 Apr 2007 20:20:43 GMT</pubDate>
            <comments>http://weblogs.sqlteam.com/jeffs/archive/2007/04/27/SQL-2005-Regular-Expression-Replace.aspx#feedback</comments>
            <slash:comments>4</slash:comments>
            <wfw:commentRss>http://weblogs.sqlteam.com/jeffs/comments/commentRss/60190.aspx</wfw:commentRss>
            <trackback:ping>http://weblogs.sqlteam.com/jeffs/services/trackbacks/60190.aspx</trackback:ping>
        </item>
        <item>
            <title>Sorting Columns with the C# Pivot Function</title>
            <link>http://weblogs.sqlteam.com/jeffs/archive/2007/04/20/60182.aspx</link>
            <description>Time for another exciting edition of the &lt;a href="http://weblogs.sqlteam.com/jeffs/contact.aspx"&gt;mailbag&lt;/a&gt;!&lt;br /&gt;
&lt;br /&gt;
Maxime writes:&lt;br /&gt;
&lt;br /&gt;
&lt;div style="margin-left: 40px;"&gt;&lt;span style="font-style: italic;"&gt;Hi,&lt;/span&gt;&lt;br style="font-style: italic;" /&gt;
&lt;br style="font-style: italic;" /&gt;
&lt;span style="font-style: italic;"&gt;First of all, your class is really nice and it handles my problem &lt;/span&gt;&lt;span style="font-style: italic;"&gt;really well.&lt;/span&gt;&lt;br style="font-style: italic;" /&gt;
&lt;br style="font-style: italic;" /&gt;
&lt;span style="font-style: italic;"&gt;I would like to ask you something about the class.  I would like to &lt;/span&gt;&lt;span style="font-style: italic;"&gt;order the pivot columns by column name but I'm unable to do that yet.  Do &lt;/span&gt;&lt;span style="font-style: italic;"&gt;you think you could help me with that ?&lt;/span&gt;&lt;br style="font-style: italic;" /&gt;
&lt;br style="font-style: italic;" /&gt;
&lt;span style="font-style: italic;"&gt;Thank you in advance for your time and sorry to bother you with this &lt;/span&gt;&lt;span style="font-style: italic;"&gt;question but I've tried to post in forums but didn't get any results.&lt;/span&gt;&lt;br style="font-style: italic;" /&gt;
&lt;br style="font-style: italic;" /&gt;
&lt;span style="font-style: italic;"&gt;Maxime &lt;/span&gt;&lt;br /&gt;
&lt;/div&gt;
&lt;br /&gt;
(Note: Maxime is referring to my simple Pivot function discussed &lt;a href="http://weblogs.sqlteam.com/jeffs/archive/2005/05/11/5101.aspx"&gt;here&lt;/a&gt;.  The idea is, as always, to let SQL focus on returning raw, summarized and filtered &lt;span style="font-style: italic;"&gt;data&lt;/span&gt; in a standard row/column result, and to let your very &lt;a href="http://weblogs.sqlteam.com/jeffs/archive/2005/05/12/5127.aspx"&gt;capable and efficient presentation layer&lt;/a&gt; handle all formatting -- which also happens to include pivoting data from rows to columns.)&lt;br /&gt;
&lt;br /&gt;
Sure thing, Maxime, that's a reasonable request and a great idea for improving the code.&lt;br /&gt;
&lt;br /&gt;
If you are using .NET 2.0, you can easily re-arrange columns in a DataTable, but this is not so easy in 1.1.  By using the setOrdinal method of a DataColumn, we can ensure that we are creating those new columns in the proper place.&lt;br /&gt;
&lt;br /&gt;
All you need to do is take the existing code for the Pivot function shown &lt;a href="http://weblogs.sqlteam.com/jeffs/archive/2005/05/11/5091.aspx"&gt;here&lt;/a&gt; and change just this line:&lt;br /&gt;
&lt;br /&gt;
&lt;p style="margin: 0in 0in 0pt; font-family: Courier New;" class="MsoNormal"&gt;      if (!tmp.Columns.Contains(s))&lt;/p&gt;
                      &lt;span style="font-family: Courier New;"&gt;tmp.Columns.Add(s, dataValues.GetFieldType(pValIndex));&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
To:&lt;br /&gt;
&lt;br /&gt;
&lt;div style="margin-left: 40px;"&gt;&lt;span style="font-family: Courier New;"&gt;if (!tmp.Columns.Contains(s))&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New; font-weight: bold;"&gt;{&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New; font-weight: bold;"&gt;  DataColumn c = tmp.Columns.Add(s, dataValues.GetFieldType(pValIndex));&lt;/span&gt;&lt;br style="font-family: Courier New; font-weight: bold;" /&gt;
&lt;span style="font-family: Courier New; font-weight: bold;"&gt;  // set the index so that it is sorted properly:&lt;/span&gt;&lt;br style="font-family: Courier New; font-weight: bold;" /&gt;
&lt;span style="font-family: Courier New; font-weight: bold;"&gt;  int newOrdinal = c.Ordinal;&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt; &lt;span style="font-weight: bold;"&gt; for (i = newOrdinal - 1; i &amp;gt;= dataValues.FieldCount - 2; i--)&lt;/span&gt;&lt;/span&gt;&lt;br style="font-family: Courier New; font-weight: bold;" /&gt;
&lt;span style="font-family: Courier New; font-weight: bold;"&gt;    if (c.ColumnName.CompareTo(tmp.Columns[i].ColumnName) &amp;lt; 0)&lt;/span&gt;&lt;br style="font-family: Courier New; font-weight: bold;" /&gt;
&lt;span style="font-family: Courier New; font-weight: bold;"&gt;      newOrdinal = i;&lt;/span&gt;&lt;br style="font-family: Courier New; font-weight: bold;" /&gt;
&lt;span style="font-family: Courier New; font-weight: bold;"&gt;  c.SetOrdinal(newOrdinal);&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New; font-weight: bold;"&gt;}&lt;/span&gt;&lt;br /&gt;
&lt;/div&gt;
&lt;br /&gt;
That should result in "sorted" pivot columns.  Use similar tricks if necessary to move other columns around in any DataTable as needed.  To sort the columns in descending order, change the CompareTo() method to compare with &amp;gt; 0.  In addition, keep in mind that this is a regular text comparison; if you need to sort numeric or date column headers, you should first convert those strings to proper datatypes before doing the compare, or at the very least to a string format that compares and sorts you way you'd like.  &lt;br /&gt;
&lt;br /&gt;
If you are using .NET 1.1, your only options are to a) move the data from this DataTable to &lt;span style="font-style: italic;"&gt;another&lt;/span&gt; one, with columns that are properly sorted as the new table is created, or b) gather the column names in advance and pass those to the function and create the DataTable with those columns already added and ready to be filled in the proper order.&lt;br /&gt;
&lt;br /&gt;
I hope this helps, and congratulations on writing simple, clear, short and efficient SQL code while letting your presentation layer do its job!&lt;br /&gt;
&lt;br /&gt;
&lt;span style="font-style: italic;"&gt;see also:&lt;br /&gt;
&lt;/span&gt;
&lt;ul&gt;
    &lt;li&gt;&lt;a href="../../../../jeffs/archive/2003/10/24/363.aspx" title="View Entry"&gt;Keep those SQL Crosstabs flexible!&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="../../../../jeffs/archive/2005/05/11/5101.aspx" title="View Entry"&gt;.NET CrossTabs: Transforming a Normalized DataReader into a Pivoted DataTable&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="../../../../jeffs/archive/2005/05/12/5127.aspx" title="View Entry" id="ctl00_pageContent_Editor_Results_rprSelectionList_ctl04_HyperLink1"&gt;.NET CrossTabs versus SQL Server CrossTabs&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="../../../../jeffs/archive/2005/05/15/5175.aspx" title="View Entry"&gt;ASP and ADO Pivots -- Old School CrossTabs&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="../../../../jeffs/archive/2007/07/12/60253.aspx" title="View Entry"&gt;SQL 2005 PIVOT Operator (link)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;img src="http://weblogs.sqlteam.com/jeffs/aggbug/60182.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Jeff Smith</dc:creator>
            <guid>http://weblogs.sqlteam.com/jeffs/archive/2007/04/20/60182.aspx</guid>
            <pubDate>Fri, 20 Apr 2007 16:05:42 GMT</pubDate>
            <comments>http://weblogs.sqlteam.com/jeffs/archive/2007/04/20/60182.aspx#feedback</comments>
            <slash:comments>2</slash:comments>
            <wfw:commentRss>http://weblogs.sqlteam.com/jeffs/comments/commentRss/60182.aspx</wfw:commentRss>
            <trackback:ping>http://weblogs.sqlteam.com/jeffs/services/trackbacks/60182.aspx</trackback:ping>
        </item>
        <item>
            <title>.NET CrossTabs versus SQL Server CrossTabs </title>
            <link>http://weblogs.sqlteam.com/jeffs/archive/2005/05/12/5127.aspx</link>
            <description>As promised in my last post, here is some performance testing to help you determine the performance benefits (if any) of performing your crosstabs at the presentation or code layer, as opposed to forcing SQL Server to do this.
&lt;br&gt;&lt;br&gt;
&lt;a href="http://weblogs.sqlteam.com/jeffs/archive/2005/05/12/5127.aspx"&gt;read more...&lt;/a&gt;&lt;img src="http://weblogs.sqlteam.com/jeffs/aggbug/5127.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Jeff Smith</dc:creator>
            <guid>http://weblogs.sqlteam.com/jeffs/archive/2005/05/12/5127.aspx</guid>
            <pubDate>Thu, 12 May 2005 14:01:00 GMT</pubDate>
            <comments>http://weblogs.sqlteam.com/jeffs/archive/2005/05/12/5127.aspx#feedback</comments>
            <slash:comments>4</slash:comments>
            <wfw:commentRss>http://weblogs.sqlteam.com/jeffs/comments/commentRss/5127.aspx</wfw:commentRss>
            <trackback:ping>http://weblogs.sqlteam.com/jeffs/services/trackbacks/5127.aspx</trackback:ping>
        </item>
        <item>
            <title>.NET CrossTabs: Transforming a Normalized DataReader into a Pivoted DataTable</title>
            <link>http://weblogs.sqlteam.com/jeffs/archive/2005/05/11/5101.aspx</link>
            <description>&lt;p&gt;In my &lt;a href="http://weblogs.sqlteam.com/jeffs/archive/2005/05/02/4842.aspx"&gt;last post&lt;/a&gt;, I spoke briefly about how I felt that in general &lt;a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/acdata/ac_8_qd_14_04j7.asp"&gt;crosstabbing&lt;/a&gt; data is something that a presentation layer should do and not the database.  Consider the result of a crosstab operation -- the columns returned will vary depending on the data.  There is pretty much no further manipulation you can do with that result in T-SQL; in the relational database world, the column names of our database objects should be constants and not continually changing as the data changes.  Also, in T-SQL there is no easy way to dynamically pivot data, and even doing it with hard-coded pivot values results in long, complicated SELECT statements.  So, in my opinion there is really is no benefit of doing this transformation within SQL Server.  (Unless you are in the mood for some fun dynamic sql and cursors ...)&lt;/p&gt;
&lt;p&gt;Almost all modern report designers allow you to quickly and easily crosstab a standard recordset from SQL Server, so be sure to learn how to use this feature and take advantage of it.  Some are more flexible than others, but for the most part they work as you'd expect.  Either way, for report-writing crosstabing data at the presentation layer should not be a concern.&lt;/p&gt;
&lt;p&gt;The main issue is programmers who are writing their own presentation layer.  Many programmers have difficulty writing code to do the transformation; I believe this may be why it is common to be tempted to force SQL Server to do all of the work.&lt;/p&gt;
&lt;p&gt;Here's a quick example of an easy way to implement a crosstab at the presentation layer using C#. To keep things short and simple, I have just written a small static function that accepts any object that implements IDataReader and returns a crosstabbed DataTable object.  The code for the function is &lt;a href="http://weblogs.sqlteam.com/jeffs/articles/5091.aspx"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;All you need to do is open up an IDataReader object that returns the data you wish to Pivot.  The data should be fully summarized by SQL Server already -- i.e., you should GROUP BY your pivot column plus any other columns you wish to return, and you should aggregate your pivot value accordingly.  The DataReader should also be sorted so that all rows which will be pivoted into one are sorted together.   &lt;/p&gt;
&lt;p&gt;For example, consider the Orders table in the Northwind database.  Suppose you want to display CompanyNames as rows, ProductNames as columns, and the total quantity of orders per CompanyName per ProductName in your crosstab.  The DataReader's recordset should be grouped by CompanyName and ProductName, it should include a SUM(Qty) calculation, and it should be sorted by CompanyName.  (see &lt;a href="http://weblogs.sqlteam.com/jeffs/articles/5093.aspx"&gt;the example&lt;/a&gt; for this exact scenario using Northwind).  &lt;/p&gt;
&lt;p&gt;What's nice is, this is all standard SQL and requires very little effort in terms of writing the SELECT and for the server to process and return the results.  We are letting the presentation layer handle the formatting.  Another benefit is that we can use this technique with &lt;em&gt;any&lt;/em&gt; datasource that ADO.NET can connect to, not just SQL Server.  (In fact, we can do this with anything that implements IDataReader)&lt;/p&gt;
&lt;p&gt;The arguments for the Pivot() function are as follows:&lt;/p&gt;
&lt;p&gt;&lt;font color="#000080"&gt;public static DataTable &lt;a href="http://weblogs.sqlteam.com/jeffs/articles/5091.aspx"&gt;Pivot &lt;/a&gt;(IDataReader &lt;em&gt;dataValues&lt;/em&gt;, string &lt;em&gt;keyColumn&lt;/em&gt;, string &lt;em&gt;pivotNameColumn&lt;/em&gt;, string &lt;em&gt;pivotValueColumn&lt;/em&gt;)&lt;/font&gt;&lt;/p&gt;
&lt;ul&gt;
    &lt;li&gt;&lt;em&gt;dataValues&lt;/em&gt; -- this is any open DataReader object, ready to be transformed and pivoted into a DataTable.  As mentioned, it should be fully grouped, aggregated, sorted and ready to go.   &lt;/li&gt;
    &lt;li&gt;&lt;em&gt;keyColumn&lt;/em&gt; -- This is the column in the DataReader which serves to identify each row.  In the previous example, this would be CustomerID.  Your DataReader's recordset should be grouped and sorted by this column as well.  &lt;/li&gt;
    &lt;li&gt;&lt;em&gt;pivotNameColumn -- &lt;/em&gt;This is the column in the DataReader that contains the values you'd like to transform from rows into columns.   In the example, this would be ProductName.  &lt;/li&gt;
    &lt;li&gt;&lt;em&gt;pivotValueColumn -- &lt;/em&gt;This is the column that in the DataReader that contains the values to pivot into the appropriate columns.  For our example, it would be Qty, which has been defined in the SELECT statement as SUM(Qty).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And, that's it.  You just call the Pivot() function on any object that implements IDataReader, specify the pivot information, and a DataTable is returned that you can use however you like.  The example uses this to fill up a DataGrid so you can see the results on a form.&lt;/p&gt;
&lt;p&gt;Stay tuned for a performance comparison between this method and doing the crosstab transformation on the SQL Server .... You might be surprised by the results.&lt;/p&gt;
&lt;br /&gt;
&lt;span style="font-style: italic;"&gt;see also:&lt;br /&gt;
&lt;/span&gt;
&lt;ul&gt;
    &lt;li&gt;&lt;a href="../../../../jeffs/archive/2003/10/24/363.aspx" title="View Entry"&gt;Keep those SQL Crosstabs flexible!&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="../../../../jeffs/archive/2005/05/12/5127.aspx" title="View Entry" id="ctl00_pageContent_Editor_Results_rprSelectionList_ctl04_HyperLink1"&gt;.NET CrossTabs versus SQL Server CrossTabs&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="../../../../jeffs/archive/2005/05/15/5175.aspx" title="View Entry"&gt;ASP and ADO Pivots -- Old School CrossTabs&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="../../../../jeffs/archive/2007/04/20/60182.aspx" title="View Entry" id="ctl00_pageContent_Editor_Results_rprSelectionList_ctl02_HyperLink1"&gt;Sorting Columns with the C# Pivot Function&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="../../../../jeffs/archive/2007/07/12/60253.aspx" title="View Entry"&gt;SQL 2005 PIVOT Operator (link)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;img src="http://weblogs.sqlteam.com/jeffs/aggbug/5101.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Jeff Smith</dc:creator>
            <guid>http://weblogs.sqlteam.com/jeffs/archive/2005/05/11/5101.aspx</guid>
            <pubDate>Wed, 11 May 2005 19:49:00 GMT</pubDate>
            <comments>http://weblogs.sqlteam.com/jeffs/archive/2005/05/11/5101.aspx#feedback</comments>
            <slash:comments>21</slash:comments>
            <wfw:commentRss>http://weblogs.sqlteam.com/jeffs/comments/commentRss/5101.aspx</wfw:commentRss>
            <trackback:ping>http://weblogs.sqlteam.com/jeffs/services/trackbacks/5101.aspx</trackback:ping>
        </item>
    </channel>
</rss>