• subscribe
September 28, 2009 12:00 AM

How SQL Server CLR and C# Can Solve a Common Problem

Need to transpose a query’s result set? The solution is cumbersome with traditional T-SQL, so give this interesting workaround a try
SQL Server Pro
InstantDoc ID #102631
Listing 1: The CLR/C# Transpose Stored Procedure

 using System;
using System.Data;
using System.Data.SqlClient;
using System.Data.SqlTypes;
using Microsoft.SqlServer.Server;

public partial class MyStoredProcedureClass
{
	[Microsoft.SqlServer.Server.SqlProcedure]
	public static void Transpose(SqlString queryParameter)	
	{
		// SECTION 1: Variable declarations
		//integers
		int maxNumberofRows = 2048; 
		int rowCount = 1;
		int columnCount = 0;  
		int transposedRowCount = 0;  
		int transposedColumnCount = 0; 
		int maxDataSize =100;
		//strings
		string callersQuery = queryParameter.ToString(); 
		string\[,] queryData;
		string\[,] transposedData;

		// .NET SQL objects. These objects will get instantiated later in the code. 
		SqlConnection conn;
		SqlCommand comm;
		SqlDataReader dataReader;
		SqlMetaData\[] transposedColumns;
		SqlDataRecord rowRecord;

		try
		{
			// SECTION 2 : Execute Caller's query and store data
BEGIN CALLOUT A
			conn = new SqlConnection("context connection=true;");
			comm = new SqlCommand(callersQuery, conn);
			conn.Open();
END CALLOUT A
BEGIN CALLOUT B
			dataReader = comm.ExecuteReader();
			columnCount = dataReader.FieldCount;
			queryData = new string\[maxNumberofRows, columnCount];
			for (int j = 0; j < columnCount; j++) 
			{
				queryData\[0,j] = dataReader.GetName(j);
			}
END CALLOUT B
BEGIN CALLOUT C
			while (dataReader.Read()) 
			{
				for (int j= 0;j < columnCount; j++)
				{
					queryData\[rowCount,j] = dataReader\[j].ToString();
				}
				rowCount++;
			}
			dataReader.Close();
			conn.Close();
END CALLOUT C

			// SECTION 3:  Transpose the data
BEGIN CALLOUT D
			transposedRowCount = columnCount;
			transposedColumnCount = rowCount;
			transposedData = new string\[transposedRowCount, transposedColumnCount];
END CALLOUT D

BEGIN CALLOUT E
			for (int i = 0; i < transposedRowCount; i++)
			{
				for (int j = 0; j < transposedColumnCount; j++)
				{
					transposedData\[i, j] = queryData\[j,i];
				}
			}
END CALLOUT E

			// SECTION 4: Ouput the data back to Caller
BEGIN CALLOUT F
			transposedColumns = new SqlMetaData\[transposedColumnCount];
			for (int j = 0; j < transposedColumnCount; j++)
			{
				transposedColumns\[j]
					= new SqlMetaData(transposedData\[0, j], SqlDbType.VarChar, maxDataSize);
			}
END CALLOUT F
BEGIN CALLOUT G
			rowRecord = new SqlDataRecord(transposedColumns);
			SqlContext.Pipe.SendResultsStart(rowRecord);
END CALLOUT G
BEGIN CALLOUT H
			for (int i = 1; i < transposedRowCount; i++) 
			{
				for (int j = 0; j < transposedColumnCount; j++) 
				{
					rowRecord.SetSqlString(j, transposedData\[i, j]);
				}
				SqlContext.Pipe.SendResultsRow(rowRecord);
			}
END CALLOUT H
BEGIN CALLOUT I
			SqlContext.Pipe.SendResultsEnd();
			SqlContext.Pipe.Send("Transpose complete.");
END CALLOUT I
		}

		// SECTION 5: Handle errors
BEGIN CALLOUT J
		catch (Exception e)
		{
			SqlContext.Pipe.Send("There was a problem. \n\nException Report: ");
			SqlContext.Pipe.Send(e.Message.ToString());
END CALLOUT J
		}
		return;
	}
};


ARTICLE TOOLS

Comments
  • louis315
    1 year ago
    Apr 26, 2011

    Two changes are necessary to correct the downloaded files:

    1) At line 78 of transpose.cs, change "transposedColumn" to "transposedColumns"

    2) At line 26 of "Create sample database[...].sql" change "EXEC sp_configure 'clr enabled' " to "EXEC sp_configure 'clr enabled',1"

    The c# code could also use better disposal for SQLconnection and SQLCommand objects, but this code is a good starting point.

  • Doug
    2 years ago
    Mar 06, 2010

    When I try to create the dll by entering the second command in a cmd window, the dll is not created and I get the following message: c:\\TransposeFolder\\Transpose.cs(78,43): error CS0103: The name 'transposedColumn' does not exist in the current context.
    How can I correct for this and get this dll created?

  • Jason
    2 years ago
    Jan 07, 2010

    Sorry about the missing download file! That zip file is now included on the first page. Thanks for reading!

  • Aaron
    3 years ago
    Oct 20, 2009

    Although the stored proc sounds interesting, you reference a download file that I don't see a link for. All I see is the source code that I have to copy and paste. You leave it up to me to do all the implementation work when it could have easily been included with the article.

You must log on before posting a comment.

Are you a new visitor? Register Here