<?xml version="1.0"?><?xml-stylesheet type="text/xsl" href="http://www.codeplex.com/rss.xsl"?><rss version="2.0"><channel><title>SQL Server 2-D Matrix Builder</title><link>http://www.codeplex.com/SQL2DMatrixBuilder/Project/ProjectRss.aspx</link><description>This project is all about bringing a &amp;#42;2-D matrix builder&amp;#42; to Microsoft SQL Server 2005 &amp;#40;or later&amp;#41;. Why do we need this&amp;#63;       If you need to build a query where the returned resultset colums are not ac...</description><item><title>UPDATED WIKI: Home</title><link>http://www.codeplex.com/SQL2DMatrixBuilder/Wiki/View.aspx?title=Home&amp;version=44</link><description>&lt;div class="wikidoc"&gt;
&lt;h1&gt;
Introduction
&lt;/h1&gt; &lt;br /&gt;This project is all about bringing a &lt;b&gt;2-D matrix builder&lt;/b&gt; to &lt;b&gt;Microsoft SQL Server 2005&lt;/b&gt; (or later). So why do we need this? Consider the following schema:&lt;br /&gt; &lt;br /&gt;&lt;img src="http://www.codeplex.com/Project/Download/FileDownload.aspx?ProjectName=SQL2DMatrixBuilder&amp;amp;DownloadId=27479" alt="SQLMatrix1.png" /&gt;&lt;br /&gt; &lt;br /&gt;Now, what we would like to get as a &lt;b&gt;query result&lt;/b&gt; is the following :&lt;br /&gt; &lt;br /&gt;&lt;img src="http://www.codeplex.com/Project/Download/FileDownload.aspx?ProjectName=SQL2DMatrixBuilder&amp;amp;DownloadId=27480" alt="SQLMatrix2.png" /&gt;&lt;br /&gt; &lt;br /&gt;Notice that the headers are not &lt;i&gt;columns names&lt;/i&gt; but the &lt;b&gt;records&lt;/b&gt; available in the &lt;b&gt;Table_B&lt;/b&gt; table. So how do you get this natively with Microsoft SQL Server? Well, you can't! Unless you use the &lt;b&gt;SQL Server 2-D Matrix Builder&lt;/b&gt;.&lt;br /&gt; &lt;br /&gt;This project is all about using the &lt;b&gt;hosted .NET Common Langage Runtime&lt;/b&gt; in Microsoft SQL Server. All you have to do is uploading the &lt;b&gt;TheMatrixSqlClr.dll&lt;/b&gt; assembly into your SQL Server instance and use it. The next two chapters describe how to install this assembly into your SQL Server instance and how to reuse &lt;b&gt;TheMatrix&lt;/b&gt; stored procedure.&lt;br /&gt; &lt;br /&gt;This project was built by &lt;b&gt;Pascal Belaud&lt;/b&gt;, Developer Evangelist at &lt;b&gt;Microsoft France&lt;/b&gt; &lt;a href="http://blogs.msdn.com/Pascal" class="externalLink"&gt;French Blog (http://blogs.msdn.com/Pascal)&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;). Pascal is also the author of a &lt;b&gt;.NET code generator&lt;/b&gt; based on SQL Server 2005 called &lt;b&gt;OlyMars&lt;/b&gt; (&lt;a href="http://www.olymars.net" class="externalLink"&gt;http://www.olymars.net&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;).&lt;br /&gt; &lt;br /&gt; &lt;br /&gt;&lt;h1&gt;
Deployment
&lt;/h1&gt; &lt;br /&gt;&lt;pre&gt;
-- First you need to enable the use of .NET in your SLQ Server instance
exec sp_configure 'CLR Enabled', 1
reconfigure
GO
 
-- Since this assembly needs external access, your database needs to be TrustWorthy
Alter Database YourDatabase
Set Trustworthy On
GO
 
Use YourDatabase
GO
 
-- You need to deploy the assembly in your SQL Server instance
CREATE ASSEMBLY [TheSQLServerMatrix]
FROM '&amp;lt;Your path to the assembly here&amp;gt;\TheMatrixSqlClr.dll'
WITH PERMISSION_SET=EXTERNAL_ACCESS
GO
 
-- You need to declare a new User Defined Type
CREATE TYPE [QueryBuilder]
EXTERNAL NAME [TheSQLServerMatrix].[TheMatrixSqlClr.QueryBuilder]
GO
 
-- You need to declare a new stored procedure
CREATE PROCEDURE [TheMatrix]
  @rowsQuery [QueryBuilder]
, @rowsQuery_ValueMember nvarchar(max)
, @rowsQuery_DisplayMember nvarchar(max)
, @firstColumnHeader nvarchar(max)
, @columnsQuery [QueryBuilder]
, @columnsQuery_ValueMember nvarchar(max)
, @columnsQuery_DisplayMember nvarchar(max)
, @contentQuery [QueryBuilder]
, @contentQuery_ColumnValueMember nvarchar(max)
, @contentQuery_RowValueMember nvarchar(max)
, @contentQuery_DisplayName nvarchar(max)
, @contentQuery_MissingValue sql_variant
, @diagnose bit = 0
 
AS
EXTERNAL NAME [TheSQLServerMatrix].[TheMatrixSqlClr.StoredProcedures].[TheMatrix]
&lt;/pre&gt; &lt;br /&gt; &lt;br /&gt;&lt;h1&gt;
Usage
&lt;/h1&gt; &lt;br /&gt;Now that the assembly is declared in our instance, we can use &lt;b&gt;TheMatrix&lt;/b&gt; stored procedure like this:&lt;br /&gt; &lt;br /&gt;&lt;pre&gt;
-- Let's declare the first column rows
DECLARE @rowsQuery QueryBuilder
DECLARE @rowsQuery_ValueMember nvarchar(max)
DECLARE @rowsQuery_DisplayMember nvarchar(max)
SET @rowsQuery = QueryBuilder::New_QueryText('Select TableA_ID, TableA_Name From dbo.TableA Order by TableA_Name Asc')
SET @rowsQuery_ValueMember = 'TableA_ID'
SET @rowsQuery_DisplayMember = 'TableA_Name'
 
-- Let's declare the name of the first column header
DECLARE @firstColumnHeader nvarchar(max)
SET @firstColumnHeader = 'HEADER'
 
-- Let's declare the others columns headers
DECLARE @columnsQuery QueryBuilder
DECLARE @columnsQuery_ValueMember nvarchar(max)
DECLARE @columnsQuery_DisplayMember nvarchar(max)
SET @columnsQuery = QueryBuilder::New_QueryText('Select TableB_ID, TableB_Name From dbo.TableB Order By TableB_Name Asc')
SET @columnsQuery_ValueMember = 'TableB_ID'
SET @columnsQuery_DisplayMember = 'TableB_Name'
 
-- Let's declare how to fill the matrix content
DECLARE @contentQuery QueryBuilder
DECLARE @contentQuery_ColumnValueMember nvarchar(max)
DECLARE @contentQuery_RowValueMember nvarchar(max)
DECLARE @contentQuery_DisplayName nvarchar(max)
DECLARE @contentQuery_NullValue sql_variant
SET @contentQuery = QueryBuilder::New_StoredProcedure('spContent')
SET @contentQuery_ColumnValueMember = 'TableC_TableB_ID'
SET @contentQuery_RowValueMember = 'TableC_TableA_ID'
SET @contentQuery_DisplayName = 'TableC_Name'
SET @contentQuery_NullValue = '[NOT AVAILABLE]'
 
-- We want to see how the Matrix is going to execute all this
DECLARE @diagnose bit
SET @diagnose = 1
 
EXECUTE [TheMatrixDatabase].[dbo].[TheMatrix] 
   @rowsQuery
  ,@rowsQuery_ValueMember
  ,@rowsQuery_DisplayMember
  ,@firstColumnHeader
 
  ,@columnsQuery
  ,@columnsQuery_ValueMember
  ,@columnsQuery_DisplayMember
 
  ,@contentQuery
  ,@contentQuery_RowValueMember
  ,@contentQuery_ColumnValueMember
  ,@contentQuery_DisplayName
  ,@contentQuery_NullValue
  ,@diagnose
&lt;/pre&gt; &lt;br /&gt;When you execute this, you get the following resulset :&lt;br /&gt; &lt;br /&gt;&lt;table&gt;
&lt;tr&gt;
&lt;th&gt; HEADER &lt;/th&gt;&lt;th&gt; TableB_5 &lt;/th&gt;&lt;th&gt; TableB_6 &lt;/th&gt;&lt;th&gt; TableB_7 &lt;/th&gt;&lt;th&gt; TableB_8 &lt;/th&gt;&lt;th&gt; TableB_9 &lt;/th&gt;
&lt;/tr&gt;&lt;tr&gt;
&lt;td&gt; TableA_1 &lt;/td&gt;&lt;td&gt; TableC_1_5 &lt;/td&gt;&lt;td&gt; TableC_1_6 &lt;/td&gt;&lt;td&gt; TableC_1_7 &lt;/td&gt;&lt;td&gt; TableC_1_8 &lt;/td&gt;&lt;td&gt; TableC_1_9 &lt;/td&gt;
&lt;/tr&gt;&lt;tr&gt;
&lt;td&gt; TableA_2 &lt;/td&gt;&lt;td&gt; [NOT AVAILABLE] &lt;/td&gt;&lt;td&gt; TableC_2_6 &lt;/td&gt;&lt;td&gt; TableC_2_7 &lt;/td&gt;&lt;td&gt; TableC_2_8 &lt;/td&gt;&lt;td&gt; TableC_2_9 &lt;/td&gt;
&lt;/tr&gt;&lt;tr&gt;
&lt;td&gt; TableA_3 &lt;/td&gt;&lt;td&gt; TableC_3_5 &lt;/td&gt;&lt;td&gt; [NOT AVAILABLE] &lt;/td&gt;&lt;td&gt; TableC_3_7 &lt;/td&gt;&lt;td&gt; TableC_3_8 &lt;/td&gt;&lt;td&gt; TableC_3_9 &lt;/td&gt;
&lt;/tr&gt;&lt;tr&gt;
&lt;td&gt; TableA_4 &lt;/td&gt;&lt;td&gt; TableC_4_ &lt;/td&gt;&lt;td&gt; TableC_4_6 &lt;/td&gt;&lt;td&gt; TableC_4_7 &lt;/td&gt;&lt;td&gt; TableC_4_8 &lt;/td&gt;&lt;td&gt; TableC_4_9 &lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt; &lt;br /&gt; &lt;br /&gt;Notice that the Matrix allows you to call &lt;b&gt;literal SQL queries&lt;/b&gt; or &lt;b&gt;stored procedures&lt;/b&gt;. Those queries can also have input parameters if needed. &lt;br /&gt; &lt;br /&gt;In the previous example, the matrix content is filled with the resultset returned by the &lt;b&gt;spContent&lt;/b&gt; stored procedure:&lt;br /&gt; &lt;br /&gt;&lt;pre&gt;
Create Procedure [dbo].[spContent] As
 
Select TableC_TableA_ID, TableC_TableB_ID, TableC_Name From dbo.TableC
&lt;/pre&gt; &lt;br /&gt; &lt;br /&gt;Since we asked for diagnostic information, here is the output :&lt;br /&gt; &lt;br /&gt;&lt;pre&gt;
14/02/2008 11:22:08.46875- The SQL Server 2-D Matrix Builder
Starting TheMatrix call
 
14/02/2008 11:22:08.484375- Starting calling the Rows query
Query: Select TableA_ID, TableA_Name From dbo.TableA Order by TableA_Name Asc
	Is Stored Procedure: False
	Parameters number: 0
14/02/2008 11:22:08.484375- ValueMember index for [TableA_ID] is: 0
14/02/2008 11:22:08.484375- DisplayMember index for [TableA_Name] is: 1
14/02/2008 11:22:08.484375- Ending calling the Rows query
 
14/02/2008 11:22:08.484375- Starting calling the Columns query
Query: Select TableB_ID, TableB_Name From dbo.TableB Order By TableB_Name Asc
	Is Stored Procedure: False
	Parameters number: 0
14/02/2008 11:22:08.484375- ValueMember index for [TableB_ID] is: 0
14/02/2008 11:22:08.484375- DisplayMember index for [TableB_Name] is: 1
14/02/2008 11:22:08.484375- Ending calling the Columns query
 
14/02/2008 11:22:08.484375- Starting initializing the Matrix content
14/02/2008 11:22:08.484375- Ending initializing the Matrix content
 
14/02/2008 11:22:08.484375- Starting calling the Content query
Query: spContent
	Is Stored Procedure: True
	Parameters number: 0
14/02/2008 11:22:08.484375- ColumnValueMember index for [TableC_TableB_ID] is: 1
14/02/2008 11:22:08.484375- RowValueMember index for [TableC_TableA_ID] is: 0
14/02/2008 11:22:08.484375- DisplayMember index for [TableC_Name] is: 2
14/02/2008 11:22:08.484375- Ending calling the Content query
 
14/02/2008 11:22:08.484375- Starting SqlMetaData description
14/02/2008 11:22:08.484375- SqlMetaData, name='HEADER', sqlDbType='NVarChar', maxLength=8, precision=0, scale=0
14/02/2008 11:22:08.5- SqlMetaData, name='TableB_5', sqlDbType='NVarChar', maxLength=15, precision=0, scale=0
14/02/2008 11:22:08.5- SqlMetaData, name='TableB_6', sqlDbType='NVarChar', maxLength=15, precision=0, scale=0
14/02/2008 11:22:08.5- SqlMetaData, name='TableB_7', sqlDbType='NVarChar', maxLength=15, precision=0, scale=0
14/02/2008 11:22:08.5- SqlMetaData, name='TableB_8', sqlDbType='NVarChar', maxLength=15, precision=0, scale=0
14/02/2008 11:22:08.5- SqlMetaData, name='TableB_9', sqlDbType='NVarChar', maxLength=15, precision=0, scale=0
14/02/2008 11:22:08.5- Ending SqlMetaData description
 
14/02/2008 11:22:08.5- Starting sending back the resultset
 
(4 row(s) affected)
14/02/2008 11:22:08.5- Ending sending back the resultset
 
14/02/2008 11:22:08.5- Ending TheMatrix call...
&lt;/pre&gt; &lt;br /&gt; &lt;br /&gt;&lt;h1&gt;
Documentation
&lt;/h1&gt; &lt;br /&gt;&lt;img src="http://www.codeplex.com/Project/Download/FileDownload.aspx?ProjectName=SQL2DMatrixBuilder&amp;amp;DownloadId=27581" alt="SQLMatrix3.png" /&gt;&lt;br /&gt; &lt;br /&gt;The &lt;b&gt;QueryBuilder&lt;/b&gt; Used-Defined Type allows you to specify what query should be executed to fill:&lt;br /&gt; &lt;br /&gt;&lt;ul&gt;
&lt;li&gt;The first column rows (Query 1)&lt;/li&gt;&lt;li&gt;The columns headers (Query 2)&lt;/li&gt;&lt;li&gt;The Matrix content (Query 3)&lt;/li&gt;
&lt;/ul&gt; &lt;br /&gt;&lt;img src="http://www.codeplex.com/Project/Download/FileDownload.aspx?ProjectName=SQL2DMatrixBuilder&amp;amp;DownloadId=27574" alt="QueryBuilder.png" /&gt;&lt;br /&gt; &lt;br /&gt; &lt;br /&gt;Once you have declared a variable of this type, you can invoke any of its static methods using the &lt;b&gt;::&lt;/b&gt; operator. If you intend to call a literal SQL query, use the &lt;b&gt;New_QueryText&lt;/b&gt; method. If you plan to use a stored procedure instead, use the &lt;b&gt;New_StoredProcedure&lt;/b&gt; method.&lt;br /&gt; &lt;br /&gt;&lt;pre&gt;
-- If you are using a literal SQL query
Declare @MyLiteralSQLQueryBuilder QueryBuilder
Set @MyLiteralSQLQueryBuilder::New_QueryText(N'Select MyColumn1, MyColumn2, MyColumn3 From MyTable1 Inner Join... Where MyColumn4 = @MyParameter')
&lt;/pre&gt; &lt;br /&gt;&lt;pre&gt;
-- If you are using a stored procedure
Declare @MyStoredProcedureQueryBuilder QueryBuilder
Set @MyStoredProcedureQueryBuilder::New_StoredProcedure(N'MyStoredProcedureName')
&lt;/pre&gt; &lt;br /&gt;If your literal SQL query or your stored procedure need some input parameters, you can supply their values by calling the &lt;b&gt;SetParameter&lt;/b&gt; method:&lt;br /&gt; &lt;br /&gt;&lt;pre&gt;
Declare @Value [your type here]
Set @MyLiteralSQLQueryBuilder::SetParameter(N'@MyParameter', @Value)
&lt;/pre&gt; &lt;br /&gt;&lt;pre&gt;
Declare @Value [your type here]
Set @MyStoredProcedureQueryBuilder::SetParameter(N'@MyParameter', @Value)
&lt;/pre&gt; &lt;br /&gt;For the &lt;b&gt;Matrix content&lt;/b&gt; query only, we need to infere the &lt;b&gt;type&lt;/b&gt; of the columns that are returned in the &lt;b&gt;resultset&lt;/b&gt;. Although, this product tries to infere this type, it might not be suitable in all cases. Therefore, you can help infere this type by calling one of the following method:&lt;br /&gt; &lt;br /&gt;&lt;ul&gt;
&lt;ul&gt;
&lt;li&gt;SetContentType(typeName)&lt;/li&gt;&lt;li&gt;SetContentType2(typeName, maxLength)&lt;/li&gt;&lt;li&gt;SetContentType3(typeName, precision, scale)&lt;/li&gt;
&lt;/ul&gt;
&lt;/ul&gt; &lt;br /&gt;&lt;b&gt;typeName&lt;/b&gt; must be one of the &lt;b&gt;System.Data.SqlDbType&lt;/b&gt; enumeration value:&lt;br /&gt; &lt;br /&gt;&lt;img src="http://www.codeplex.com/Project/Download/FileDownload.aspx?ProjectName=SQL2DMatrixBuilder&amp;amp;DownloadId=27576" alt="SqlDbType.png" /&gt;&lt;br /&gt; &lt;br /&gt;Finally, once you have correctly declared the &lt;b&gt;3 QueryBuilder variables&lt;/b&gt; you need, you can call &lt;b&gt;TheMatrix&lt;/b&gt; stored procedure.&lt;br /&gt; &lt;br /&gt;The last thing we need to check for our three queries is the following:&lt;br /&gt; &lt;br /&gt;&lt;ul&gt;
&lt;li&gt;&lt;b&gt;Query 1&lt;/b&gt; and &lt;b&gt;Query 2&lt;/b&gt; need to return two columns (you can return more than two columns but only two columns will be used):&lt;/li&gt;&lt;ul&gt;
&lt;li&gt;one column must be the &amp;quot;&lt;b&gt;Primary Key&lt;/b&gt;&amp;quot;&lt;/li&gt;&lt;li&gt;one column must be the &amp;quot;&lt;b&gt;Display Value&lt;/b&gt;&amp;quot;&lt;/li&gt;
&lt;/ul&gt;
&lt;/ul&gt; &lt;br /&gt;&lt;ul&gt;
&lt;li&gt;&lt;b&gt;Query 3&lt;/b&gt; needs to return three columns (you can return more than three columns but only three columns will be used):&lt;/li&gt;&lt;ul&gt;
&lt;li&gt;one column must be the &amp;quot;&lt;b&gt;Row Primary Key&lt;/b&gt;&amp;quot;&lt;/li&gt;&lt;li&gt;one column must be the &amp;quot;&lt;b&gt;Column Primary Key&lt;/b&gt;&amp;quot;&lt;/li&gt;&lt;li&gt;one column must be the &amp;quot;&lt;b&gt;Display Value&lt;/b&gt;&amp;quot; of the Matrix&lt;/li&gt;
&lt;/ul&gt;
&lt;/ul&gt; &lt;br /&gt;We also need to supply two values:&lt;br /&gt;&lt;ul&gt;
&lt;li&gt;The &amp;quot;&lt;b&gt;Display Value&lt;/b&gt;&amp;quot; for the &lt;b&gt;first column header&lt;/b&gt;&lt;/li&gt;&lt;li&gt;The &amp;quot;&lt;b&gt;Display Value&lt;/b&gt;&amp;quot; to use if we have a &lt;b&gt;missing value&lt;/b&gt; in the Matrix content returned by &lt;b&gt;Query 3&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt; &lt;br /&gt;&lt;img src="http://www.codeplex.com/Project/Download/FileDownload.aspx?ProjectName=SQL2DMatrixBuilder&amp;amp;DownloadId=27582" alt="SQLMatrix4.png" /&gt;&lt;br /&gt; &lt;br /&gt;Those parameters will be supplied directly to &lt;b&gt;TheMatrix&lt;/b&gt; stored procedure call.&lt;br /&gt; &lt;br /&gt; &lt;br /&gt;&lt;h1&gt;
More resources on SQL Server 2-D Matrix Builder
&lt;/h1&gt; &lt;br /&gt;An &lt;b&gt;french&lt;/b&gt; article is now available here: &lt;a href="http://msdn2.microsoft.com/fr-fr/sqlserver/cc197167.aspx" class="externalLink"&gt;The SQL Server 2-D Matrix Builder (http://msdn2.microsoft.com/fr-fr/sqlserver/cc197167.aspx)&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;This article will also be translated in &lt;b&gt;English&lt;/b&gt; very soon. Stay tuned!&lt;br /&gt;
&lt;/div&gt;</description><author>olymars</author><pubDate>Wed, 05 Mar 2008 22:33:08 GMT</pubDate><guid isPermaLink="false">UPDATED WIKI: Home 20080305103308P</guid></item><item><title>UPDATED WIKI: Home</title><link>http://www.codeplex.com/SQL2DMatrixBuilder/Wiki/View.aspx?title=Home&amp;version=43</link><description>&lt;div class="wikidoc"&gt;
&lt;h1&gt;
Introduction
&lt;/h1&gt; &lt;br /&gt;This project is all about bringing a &lt;b&gt;2-D matrix builder&lt;/b&gt; to &lt;b&gt;Microsoft SQL Server 2005&lt;/b&gt; (or later). So why do we need this? Consider the following schema:&lt;br /&gt; &lt;br /&gt;&lt;img src="http://www.codeplex.com/Project/Download/FileDownload.aspx?ProjectName=SQL2DMatrixBuilder&amp;amp;DownloadId=27479" alt="SQLMatrix1.png" /&gt;&lt;br /&gt; &lt;br /&gt;Now, what we would like to get as a &lt;b&gt;query result&lt;/b&gt; is the following :&lt;br /&gt; &lt;br /&gt;&lt;img src="http://www.codeplex.com/Project/Download/FileDownload.aspx?ProjectName=SQL2DMatrixBuilder&amp;amp;DownloadId=27480" alt="SQLMatrix2.png" /&gt;&lt;br /&gt; &lt;br /&gt;Notice that the headers are not &lt;i&gt;columns names&lt;/i&gt; but the &lt;b&gt;records&lt;/b&gt; available in the &lt;b&gt;Table_B&lt;/b&gt; table. So how do you get this natively with Microsoft SQL Server? Well, you can't! Unless you use the &lt;b&gt;SQL Server 2-D Matrix Builder&lt;/b&gt;.&lt;br /&gt; &lt;br /&gt;This project is all about using the &lt;b&gt;hosted .NET Common Langage Runtime&lt;/b&gt; in Microsoft SQL Server. All you have to do is uploading the &lt;b&gt;TheMatrixSqlClr.dll&lt;/b&gt; assembly into your SQL Server instance and use it. The next two chapters describe how to install this assembly into your SQL Server instance and how to reuse &lt;b&gt;TheMatrix&lt;/b&gt; stored procedure.&lt;br /&gt; &lt;br /&gt;This project was built by &lt;b&gt;Pascal Belaud&lt;/b&gt;, Developer Evangelist at &lt;b&gt;Microsoft France&lt;/b&gt; &lt;a href="http://blogs.msdn.com/Pascal" class="externalLink"&gt;French Blog (http://blogs.msdn.com/Pascal)&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;). Pascal is also the author of a &lt;b&gt;.NET code generator&lt;/b&gt; based on SQL Server 2005 called &lt;b&gt;OlyMars&lt;/b&gt; (&lt;a href="http://www.olymars.net" class="externalLink"&gt;http://www.olymars.net&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;).&lt;br /&gt; &lt;br /&gt; &lt;br /&gt;&lt;h1&gt;
Deployment
&lt;/h1&gt; &lt;br /&gt;&lt;pre&gt;
-- First you need to enable the use of .NET in your SLQ Server instance
exec sp_configure 'CLR Enabled', 1
reconfigure
GO
 
-- Since this assembly needs external access, your database needs to be TrustWorthy
Alter Database YourDatabase
Set Trustworthy On
GO
 
Use YourDatabase
GO
 
-- You need to deploy the assembly in your SQL Server instance
CREATE ASSEMBLY [TheSQLServerMatrix]
FROM '&amp;lt;Your path to the assembly here&amp;gt;\TheMatrixSqlClr.dll'
WITH PERMISSION_SET=EXTERNAL_ACCESS
GO
 
-- You need to declare a new User Defined Type
CREATE TYPE [QueryBuilder]
EXTERNAL NAME [TheSQLServerMatrix].[TheMatrixSqlClr.QueryBuilder]
GO
 
-- You need to declare a new stored procedure
CREATE PROCEDURE [TheMatrix]
  @rowsQuery [QueryBuilder]
, @rowsQuery_ValueMember nvarchar(max)
, @rowsQuery_DisplayMember nvarchar(max)
, @firstColumnHeader nvarchar(max)
, @columnsQuery [QueryBuilder]
, @columnsQuery_ValueMember nvarchar(max)
, @columnsQuery_DisplayMember nvarchar(max)
, @contentQuery [QueryBuilder]
, @contentQuery_ColumnValueMember nvarchar(max)
, @contentQuery_RowValueMember nvarchar(max)
, @contentQuery_DisplayName nvarchar(max)
, @contentQuery_MissingValue sql_variant
, @diagnose bit = 0
 
AS
EXTERNAL NAME [TheSQLServerMatrix].[TheMatrixSqlClr.StoredProcedures].[TheMatrix]
&lt;/pre&gt; &lt;br /&gt; &lt;br /&gt;&lt;h1&gt;
Usage
&lt;/h1&gt; &lt;br /&gt;Now that the assembly is declared in our instance, we can use &lt;b&gt;TheMatrix&lt;/b&gt; stored procedure like this:&lt;br /&gt; &lt;br /&gt;&lt;pre&gt;
-- Let's declare the first column rows
DECLARE @rowsQuery QueryBuilder
DECLARE @rowsQuery_ValueMember nvarchar(max)
DECLARE @rowsQuery_DisplayMember nvarchar(max)
SET @rowsQuery = QueryBuilder::New_QueryText('Select TableA_ID, TableA_Name From dbo.TableA Order by TableA_Name Asc')
SET @rowsQuery_ValueMember = 'TableA_ID'
SET @rowsQuery_DisplayMember = 'TableA_Name'
 
-- Let's declare the name of the first column header
DECLARE @firstColumnHeader nvarchar(max)
SET @firstColumnHeader = 'HEADER'
 
-- Let's declare the others columns headers
DECLARE @columnsQuery QueryBuilder
DECLARE @columnsQuery_ValueMember nvarchar(max)
DECLARE @columnsQuery_DisplayMember nvarchar(max)
SET @columnsQuery = QueryBuilder::New_QueryText('Select TableB_ID, TableB_Name From dbo.TableB Order By TableB_Name Asc')
SET @columnsQuery_ValueMember = 'TableB_ID'
SET @columnsQuery_DisplayMember = 'TableB_Name'
 
-- Let's declare how to fill the matrix content
DECLARE @contentQuery QueryBuilder
DECLARE @contentQuery_ColumnValueMember nvarchar(max)
DECLARE @contentQuery_RowValueMember nvarchar(max)
DECLARE @contentQuery_DisplayName nvarchar(max)
DECLARE @contentQuery_NullValue sql_variant
SET @contentQuery = QueryBuilder::New_StoredProcedure('spContent')
SET @contentQuery_ColumnValueMember = 'TableC_TableB_ID'
SET @contentQuery_RowValueMember = 'TableC_TableA_ID'
SET @contentQuery_DisplayName = 'TableC_Name'
SET @contentQuery_NullValue = '[NOT AVAILABLE]'
 
-- We want to see how the Matrix is going to execute all this
DECLARE @diagnose bit
SET @diagnose = 1
 
EXECUTE [TheMatrixDatabase].[dbo].[TheMatrix] 
   @rowsQuery
  ,@rowsQuery_ValueMember
  ,@rowsQuery_DisplayMember
  ,@firstColumnHeader
 
  ,@columnsQuery
  ,@columnsQuery_ValueMember
  ,@columnsQuery_DisplayMember
 
  ,@contentQuery
  ,@contentQuery_RowValueMember
  ,@contentQuery_ColumnValueMember
  ,@contentQuery_DisplayName
  ,@contentQuery_NullValue
  ,@diagnose
&lt;/pre&gt; &lt;br /&gt;When you execute this, you get the following resulset :&lt;br /&gt; &lt;br /&gt;&lt;table&gt;
&lt;tr&gt;
&lt;th&gt; HEADER &lt;/th&gt;&lt;th&gt; TableB_5 &lt;/th&gt;&lt;th&gt; TableB_6 &lt;/th&gt;&lt;th&gt; TableB_7 &lt;/th&gt;&lt;th&gt; TableB_8 &lt;/th&gt;&lt;th&gt; TableB_9 &lt;/th&gt;
&lt;/tr&gt;&lt;tr&gt;
&lt;td&gt; TableA_1 &lt;/td&gt;&lt;td&gt; TableC_1_5 &lt;/td&gt;&lt;td&gt; TableC_1_6 &lt;/td&gt;&lt;td&gt; TableC_1_7 &lt;/td&gt;&lt;td&gt; TableC_1_8 &lt;/td&gt;&lt;td&gt; TableC_1_9 &lt;/td&gt;
&lt;/tr&gt;&lt;tr&gt;
&lt;td&gt; TableA_2 &lt;/td&gt;&lt;td&gt; [NOT AVAILABLE] &lt;/td&gt;&lt;td&gt; TableC_2_6 &lt;/td&gt;&lt;td&gt; TableC_2_7 &lt;/td&gt;&lt;td&gt; TableC_2_8 &lt;/td&gt;&lt;td&gt; TableC_2_9 &lt;/td&gt;
&lt;/tr&gt;&lt;tr&gt;
&lt;td&gt; TableA_3 &lt;/td&gt;&lt;td&gt; TableC_3_5 &lt;/td&gt;&lt;td&gt; [NOT AVAILABLE] &lt;/td&gt;&lt;td&gt; TableC_3_7 &lt;/td&gt;&lt;td&gt; TableC_3_8 &lt;/td&gt;&lt;td&gt; TableC_3_9 &lt;/td&gt;
&lt;/tr&gt;&lt;tr&gt;
&lt;td&gt; TableA_4 &lt;/td&gt;&lt;td&gt; TableC_4_ &lt;/td&gt;&lt;td&gt; TableC_4_6 &lt;/td&gt;&lt;td&gt; TableC_4_7 &lt;/td&gt;&lt;td&gt; TableC_4_8 &lt;/td&gt;&lt;td&gt; TableC_4_9 &lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt; &lt;br /&gt; &lt;br /&gt;Notice that the Matrix allows you to call &lt;b&gt;literal SQL queries&lt;/b&gt; or &lt;b&gt;stored procedures&lt;/b&gt;. Those queries can also have input parameters if needed. &lt;br /&gt; &lt;br /&gt;In the previous example, the matrix content is filled with the resultset returned by the &lt;b&gt;spContent&lt;/b&gt; stored procedure:&lt;br /&gt; &lt;br /&gt;&lt;pre&gt;
Create Procedure [dbo].[spContent] As
 
Select TableC_TableA_ID, TableC_TableB_ID, TableC_Name From dbo.TableC
&lt;/pre&gt; &lt;br /&gt; &lt;br /&gt;Since we asked for diagnostic information, here is the output :&lt;br /&gt; &lt;br /&gt;&lt;pre&gt;
14/02/2008 11:22:08.46875- The SQL Server 2-D Matrix Builder
Starting TheMatrix call
 
14/02/2008 11:22:08.484375- Starting calling the Rows query
Query: Select TableA_ID, TableA_Name From dbo.TableA Order by TableA_Name Asc
	Is Stored Procedure: False
	Parameters number: 0
14/02/2008 11:22:08.484375- ValueMember index for [TableA_ID] is: 0
14/02/2008 11:22:08.484375- DisplayMember index for [TableA_Name] is: 1
14/02/2008 11:22:08.484375- Ending calling the Rows query
 
14/02/2008 11:22:08.484375- Starting calling the Columns query
Query: Select TableB_ID, TableB_Name From dbo.TableB Order By TableB_Name Asc
	Is Stored Procedure: False
	Parameters number: 0
14/02/2008 11:22:08.484375- ValueMember index for [TableB_ID] is: 0
14/02/2008 11:22:08.484375- DisplayMember index for [TableB_Name] is: 1
14/02/2008 11:22:08.484375- Ending calling the Columns query
 
14/02/2008 11:22:08.484375- Starting initializing the Matrix content
14/02/2008 11:22:08.484375- Ending initializing the Matrix content
 
14/02/2008 11:22:08.484375- Starting calling the Content query
Query: spContent
	Is Stored Procedure: True
	Parameters number: 0
14/02/2008 11:22:08.484375- ColumnValueMember index for [TableC_TableB_ID] is: 1
14/02/2008 11:22:08.484375- RowValueMember index for [TableC_TableA_ID] is: 0
14/02/2008 11:22:08.484375- DisplayMember index for [TableC_Name] is: 2
14/02/2008 11:22:08.484375- Ending calling the Content query
 
14/02/2008 11:22:08.484375- Starting SqlMetaData description
14/02/2008 11:22:08.484375- SqlMetaData, name='HEADER', sqlDbType='NVarChar', maxLength=8, precision=0, scale=0
14/02/2008 11:22:08.5- SqlMetaData, name='TableB_5', sqlDbType='NVarChar', maxLength=15, precision=0, scale=0
14/02/2008 11:22:08.5- SqlMetaData, name='TableB_6', sqlDbType='NVarChar', maxLength=15, precision=0, scale=0
14/02/2008 11:22:08.5- SqlMetaData, name='TableB_7', sqlDbType='NVarChar', maxLength=15, precision=0, scale=0
14/02/2008 11:22:08.5- SqlMetaData, name='TableB_8', sqlDbType='NVarChar', maxLength=15, precision=0, scale=0
14/02/2008 11:22:08.5- SqlMetaData, name='TableB_9', sqlDbType='NVarChar', maxLength=15, precision=0, scale=0
14/02/2008 11:22:08.5- Ending SqlMetaData description
 
14/02/2008 11:22:08.5- Starting sending back the resultset
 
(4 row(s) affected)
14/02/2008 11:22:08.5- Ending sending back the resultset
 
14/02/2008 11:22:08.5- Ending TheMatrix call...
&lt;/pre&gt; &lt;br /&gt; &lt;br /&gt;&lt;h1&gt;
Documentation
&lt;/h1&gt; &lt;br /&gt;&lt;img src="http://www.codeplex.com/Project/Download/FileDownload.aspx?ProjectName=SQL2DMatrixBuilder&amp;amp;DownloadId=27581" alt="SQLMatrix3.png" /&gt;&lt;br /&gt; &lt;br /&gt;The &lt;b&gt;QueryBuilder&lt;/b&gt; Used-Defined Type allows you to specify what query should be executed to fill:&lt;br /&gt; &lt;br /&gt;&lt;ul&gt;
&lt;li&gt;The first column rows (Query 1)&lt;/li&gt;&lt;li&gt;The columns headers (Query 2)&lt;/li&gt;&lt;li&gt;The Matrix content (Query 3)&lt;/li&gt;
&lt;/ul&gt; &lt;br /&gt;&lt;img src="http://www.codeplex.com/Project/Download/FileDownload.aspx?ProjectName=SQL2DMatrixBuilder&amp;amp;DownloadId=27574" alt="QueryBuilder.png" /&gt;&lt;br /&gt; &lt;br /&gt; &lt;br /&gt;Once you have declared a variable of this type, you can invoke any of its static methods using the &lt;b&gt;::&lt;/b&gt; operator. If you intend to call a literal SQL query, use the &lt;b&gt;New_QueryText&lt;/b&gt; method. If you plan to use a stored procedure instead, use the &lt;b&gt;New_StoredProcedure&lt;/b&gt; method.&lt;br /&gt; &lt;br /&gt;&lt;pre&gt;
-- If you are using a literal SQL query
Declare @MyLiteralSQLQueryBuilder QueryBuilder
Set @MyLiteralSQLQueryBuilder::New_QueryText(N'Select MyColumn1, MyColumn2, MyColumn3 From MyTable1 Inner Join... Where MyColumn4 = @MyParameter')
&lt;/pre&gt; &lt;br /&gt;&lt;pre&gt;
-- If you are using a stored procedure
Declare @MyStoredProcedureQueryBuilder QueryBuilder
Set @MyStoredProcedureQueryBuilder::New_QueryText(N'MyStoredProcedureName')
&lt;/pre&gt; &lt;br /&gt;If your literal SQL query or your stored procedure need some input parameters, you can supply their values by calling the &lt;b&gt;SetParameter&lt;/b&gt; method:&lt;br /&gt; &lt;br /&gt;&lt;pre&gt;
Declare @Value [your type here]
Set @MyLiteralSQLQueryBuilder::SetParameter(N'@MyParameter', @Value)
&lt;/pre&gt; &lt;br /&gt;&lt;pre&gt;
Declare @Value [your type here]
Set @MyStoredProcedureQueryBuilder::SetParameter(N'@MyParameter', @Value)
&lt;/pre&gt; &lt;br /&gt;For the &lt;b&gt;Matrix content&lt;/b&gt; query only, we need to infere the &lt;b&gt;type&lt;/b&gt; of the columns that are returned in the &lt;b&gt;resultset&lt;/b&gt;. Although, this product tries to infere this type, it might not be suitable in all cases. Therefore, you can help infere this type by calling one of the following method:&lt;br /&gt; &lt;br /&gt;&lt;ul&gt;
&lt;ul&gt;
&lt;li&gt;SetContentType(typeName)&lt;/li&gt;&lt;li&gt;SetContentType2(typeName, maxLength)&lt;/li&gt;&lt;li&gt;SetContentType3(typeName, precision, scale)&lt;/li&gt;
&lt;/ul&gt;
&lt;/ul&gt; &lt;br /&gt;&lt;b&gt;typeName&lt;/b&gt; must be one of the &lt;b&gt;System.Data.SqlDbType&lt;/b&gt; enumeration value:&lt;br /&gt; &lt;br /&gt;&lt;img src="http://www.codeplex.com/Project/Download/FileDownload.aspx?ProjectName=SQL2DMatrixBuilder&amp;amp;DownloadId=27576" alt="SqlDbType.png" /&gt;&lt;br /&gt; &lt;br /&gt;Finally, once you have correctly declared the &lt;b&gt;3 QueryBuilder variables&lt;/b&gt; you need, you can call &lt;b&gt;TheMatrix&lt;/b&gt; stored procedure.&lt;br /&gt; &lt;br /&gt;The last thing we need to check for our three queries is the following:&lt;br /&gt; &lt;br /&gt;&lt;ul&gt;
&lt;li&gt;&lt;b&gt;Query 1&lt;/b&gt; and &lt;b&gt;Query 2&lt;/b&gt; need to return two columns (you can return more than two columns but only two columns will be used):&lt;/li&gt;&lt;ul&gt;
&lt;li&gt;one column must be the &amp;quot;&lt;b&gt;Primary Key&lt;/b&gt;&amp;quot;&lt;/li&gt;&lt;li&gt;one column must be the &amp;quot;&lt;b&gt;Display Value&lt;/b&gt;&amp;quot;&lt;/li&gt;
&lt;/ul&gt;
&lt;/ul&gt; &lt;br /&gt;&lt;ul&gt;
&lt;li&gt;&lt;b&gt;Query 3&lt;/b&gt; needs to return three columns (you can return more than three columns but only three columns will be used):&lt;/li&gt;&lt;ul&gt;
&lt;li&gt;one column must be the &amp;quot;&lt;b&gt;Row Primary Key&lt;/b&gt;&amp;quot;&lt;/li&gt;&lt;li&gt;one column must be the &amp;quot;&lt;b&gt;Column Primary Key&lt;/b&gt;&amp;quot;&lt;/li&gt;&lt;li&gt;one column must be the &amp;quot;&lt;b&gt;Display Value&lt;/b&gt;&amp;quot; of the Matrix&lt;/li&gt;
&lt;/ul&gt;
&lt;/ul&gt; &lt;br /&gt;We also need to supply two values:&lt;br /&gt;&lt;ul&gt;
&lt;li&gt;The &amp;quot;&lt;b&gt;Display Value&lt;/b&gt;&amp;quot; for the &lt;b&gt;first column header&lt;/b&gt;&lt;/li&gt;&lt;li&gt;The &amp;quot;&lt;b&gt;Display Value&lt;/b&gt;&amp;quot; to use if we have a &lt;b&gt;missing value&lt;/b&gt; in the Matrix content returned by &lt;b&gt;Query 3&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt; &lt;br /&gt;&lt;img src="http://www.codeplex.com/Project/Download/FileDownload.aspx?ProjectName=SQL2DMatrixBuilder&amp;amp;DownloadId=27582" alt="SQLMatrix4.png" /&gt;&lt;br /&gt; &lt;br /&gt;Those parameters will be supplied directly to &lt;b&gt;TheMatrix&lt;/b&gt; stored procedure call.&lt;br /&gt; &lt;br /&gt; &lt;br /&gt;&lt;h1&gt;
More resources on SQL Server 2-D Matrix Builder
&lt;/h1&gt; &lt;br /&gt;An &lt;b&gt;french&lt;/b&gt; article is now available here: &lt;a href="http://msdn2.microsoft.com/fr-fr/sqlserver/cc197167.aspx" class="externalLink"&gt;The SQL Server 2-D Matrix Builder (http://msdn2.microsoft.com/fr-fr/sqlserver/cc197167.aspx)&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;This article will also be translated in &lt;b&gt;English&lt;/b&gt; very soon. Stay tuned!&lt;br /&gt;
&lt;/div&gt;</description><author>olymars</author><pubDate>Fri, 15 Feb 2008 10:31:49 GMT</pubDate><guid isPermaLink="false">UPDATED WIKI: Home 20080215103149A</guid></item><item><title>UPDATED WIKI: Home</title><link>http://www.codeplex.com/SQL2DMatrixBuilder/Wiki/View.aspx?title=Home&amp;version=42</link><description>&lt;div class="wikidoc"&gt;
&lt;h1&gt;
Introduction
&lt;/h1&gt; &lt;br /&gt;This project is all about bringing a &lt;b&gt;2-D matrix builder&lt;/b&gt; to &lt;b&gt;Microsoft SQL Server 2005&lt;/b&gt; (or later). So why do we need this? Consider the following schema:&lt;br /&gt; &lt;br /&gt;&lt;img src="http://www.codeplex.com/Project/Download/FileDownload.aspx?ProjectName=SQL2DMatrixBuilder&amp;amp;DownloadId=27479" alt="SQLMatrix1.png" /&gt;&lt;br /&gt; &lt;br /&gt;Now, what we would like to get as a &lt;b&gt;query result&lt;/b&gt; is the following :&lt;br /&gt; &lt;br /&gt;&lt;img src="http://www.codeplex.com/Project/Download/FileDownload.aspx?ProjectName=SQL2DMatrixBuilder&amp;amp;DownloadId=27480" alt="SQLMatrix2.png" /&gt;&lt;br /&gt; &lt;br /&gt;Notice that the headers are not &lt;i&gt;columns names&lt;/i&gt; but the &lt;b&gt;records&lt;/b&gt; available in the &lt;b&gt;Table_B&lt;/b&gt; table. So how do you get this natively with Microsoft SQL Server? Well, you can't! Unless you use the &lt;b&gt;SQL Server 2-D Matrix Builder&lt;/b&gt;.&lt;br /&gt; &lt;br /&gt;This project is all about using the &lt;b&gt;hosted .NET Common Langage Runtime&lt;/b&gt; in Microsoft SQL Server. All you have to do is uploading the &lt;b&gt;TheMatrixSqlClr.dll&lt;/b&gt; assembly into your SQL Server instance and use it. The next two chapters describe how to install this assembly into your SQL Server instance and how to reuse &lt;b&gt;TheMatrix&lt;/b&gt; stored procedure.&lt;br /&gt; &lt;br /&gt;This project was built by &lt;b&gt;Pascal Belaud&lt;/b&gt;, Developer Evangelist at &lt;b&gt;Microsoft France&lt;/b&gt; &lt;a href="http://blogs.msdn.com/Pascal" class="externalLink"&gt;French Blog (http://blogs.msdn.com/Pascal)&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;). Pascal is also the author of a &lt;b&gt;.NET code generator&lt;/b&gt; based on SQL Server 2005 called &lt;b&gt;OlyMars&lt;/b&gt; (&lt;a href="http://www.olymars.net" class="externalLink"&gt;http://www.olymars.net&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;).&lt;br /&gt; &lt;br /&gt; &lt;br /&gt;&lt;h1&gt;
Deployment
&lt;/h1&gt; &lt;br /&gt;&lt;pre&gt;
-- First you need to enable the use of .NET in your SLQ Server instance
exec sp_configure 'CLR Enabled', 1
reconfigure
GO
 
-- Since this assembly needs external access, your database needs to be TrustWorthy
Alter Database YourDatabase
Set Trustworthy On
GO
 
Use YourDatabase
GO
 
-- You need to deploy the assembly in your SQL Server instance
CREATE ASSEMBLY [TheSQLServerMatrix]
FROM '&amp;lt;Your path to the assembly here&amp;gt;\TheMatrixSqlClr.dll'
WITH PERMISSION_SET=EXTERNAL_ACCESS
GO
 
-- You need to declare a new User Defined Type
CREATE TYPE [QueryBuilder]
EXTERNAL NAME [TheSQLServerMatrix].[TheMatrixSqlClr.QueryBuilder]
GO
 
-- You need to declare a new stored procedure
CREATE PROCEDURE [TheMatrix]
  @rowsQuery [QueryBuilder]
, @rowsQuery_ValueMember nvarchar(max)
, @rowsQuery_DisplayMember nvarchar(max)
, @firstColumnHeader nvarchar(max)
, @columnsQuery [QueryBuilder]
, @columnsQuery_ValueMember nvarchar(max)
, @columnsQuery_DisplayMember nvarchar(max)
, @contentQuery [QueryBuilder]
, @contentQuery_ColumnValueMember nvarchar(max)
, @contentQuery_RowValueMember nvarchar(max)
, @contentQuery_DisplayName nvarchar(max)
, @contentQuery_MissingValue sql_variant
, @diagnose bit = 0
 
AS
EXTERNAL NAME [TheSQLServerMatrix].[TheMatrixSqlClr.StoredProcedures].[TheMatrix]
&lt;/pre&gt; &lt;br /&gt; &lt;br /&gt;&lt;h1&gt;
Usage
&lt;/h1&gt; &lt;br /&gt;Now that the assembly is declared in our instance, we can use &lt;b&gt;TheMatrix&lt;/b&gt; stored procedure like this:&lt;br /&gt; &lt;br /&gt;&lt;pre&gt;
-- Let's declare the first column rows
DECLARE @rowsQuery QueryBuilder
DECLARE @rowsQuery_ValueMember nvarchar(max)
DECLARE @rowsQuery_DisplayMember nvarchar(max)
SET @rowsQuery = QueryBuilder::New_QueryText('Select TableA_ID, TableA_Name From dbo.TableA Order by TableA_Name Asc')
SET @rowsQuery_ValueMember = 'TableA_ID'
SET @rowsQuery_DisplayMember = 'TableA_Name'
 
-- Let's declare the name of the first column header
DECLARE @firstColumnHeader nvarchar(max)
SET @firstColumnHeader = 'HEADER'
 
-- Let's declare the others columns headers
DECLARE @columnsQuery QueryBuilder
DECLARE @columnsQuery_ValueMember nvarchar(max)
DECLARE @columnsQuery_DisplayMember nvarchar(max)
SET @columnsQuery = QueryBuilder::New_QueryText('Select TableB_ID, TableB_Name From dbo.TableB Order By TableB_Name Asc')
SET @columnsQuery_ValueMember = 'TableB_ID'
SET @columnsQuery_DisplayMember = 'TableB_Name'
 
-- Let's declare how to fill the matrix content
DECLARE @contentQuery QueryBuilder
DECLARE @contentQuery_ColumnValueMember nvarchar(max)
DECLARE @contentQuery_RowValueMember nvarchar(max)
DECLARE @contentQuery_DisplayName nvarchar(max)
DECLARE @contentQuery_NullValue sql_variant
SET @contentQuery = QueryBuilder::New_StoredProcedure('spContent')
SET @contentQuery_ColumnValueMember = 'TableC_TableB_ID'
SET @contentQuery_RowValueMember = 'TableC_TableA_ID'
SET @contentQuery_DisplayName = 'TableC_Name'
SET @contentQuery_NullValue = '[NOT AVAILABLE]'
 
-- We want to see how the Matrix is going to execute all this
DECLARE @diagnose bit
SET @diagnose = 1
 
EXECUTE [TheMatrixDatabase].[dbo].[TheMatrix] 
   @rowsQuery
  ,@rowsQuery_ValueMember
  ,@rowsQuery_DisplayMember
  ,@firstColumnHeader
 
  ,@columnsQuery
  ,@columnsQuery_ValueMember
  ,@columnsQuery_DisplayMember
 
  ,@contentQuery
  ,@contentQuery_RowValueMember
  ,@contentQuery_ColumnValueMember
  ,@contentQuery_DisplayName
  ,@contentQuery_NullValue
  ,@diagnose
&lt;/pre&gt; &lt;br /&gt;When you execute this, you get the following resulset :&lt;br /&gt; &lt;br /&gt;&lt;table&gt;
&lt;tr&gt;
&lt;th&gt; HEADER &lt;/th&gt;&lt;th&gt; TableB_5 &lt;/th&gt;&lt;th&gt; TableB_6 &lt;/th&gt;&lt;th&gt; TableB_7 &lt;/th&gt;&lt;th&gt; TableB_8 &lt;/th&gt;&lt;th&gt; TableB_9 &lt;/th&gt;
&lt;/tr&gt;&lt;tr&gt;
&lt;td&gt; TableA_1 &lt;/td&gt;&lt;td&gt; TableC_1_5 &lt;/td&gt;&lt;td&gt; TableC_1_6 &lt;/td&gt;&lt;td&gt; TableC_1_7 &lt;/td&gt;&lt;td&gt; TableC_1_8 &lt;/td&gt;&lt;td&gt; TableC_1_9 &lt;/td&gt;
&lt;/tr&gt;&lt;tr&gt;
&lt;td&gt; TableA_2 &lt;/td&gt;&lt;td&gt; [NOT AVAILABLE] &lt;/td&gt;&lt;td&gt; TableC_2_6 &lt;/td&gt;&lt;td&gt; TableC_2_7 &lt;/td&gt;&lt;td&gt; TableC_2_8 &lt;/td&gt;&lt;td&gt; TableC_2_9 &lt;/td&gt;
&lt;/tr&gt;&lt;tr&gt;
&lt;td&gt; TableA_3 &lt;/td&gt;&lt;td&gt; TableC_3_5 &lt;/td&gt;&lt;td&gt; [NOT AVAILABLE] &lt;/td&gt;&lt;td&gt; TableC_3_7 &lt;/td&gt;&lt;td&gt; TableC_3_8 &lt;/td&gt;&lt;td&gt; TableC_3_9 &lt;/td&gt;
&lt;/tr&gt;&lt;tr&gt;
&lt;td&gt; TableA_4 &lt;/td&gt;&lt;td&gt; TableC_4_ &lt;/td&gt;&lt;td&gt; TableC_4_6 &lt;/td&gt;&lt;td&gt; TableC_4_7 &lt;/td&gt;&lt;td&gt; TableC_4_8 &lt;/td&gt;&lt;td&gt; TableC_4_9 &lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt; &lt;br /&gt; &lt;br /&gt;Notice that the Matrix allows you to call &lt;b&gt;literal SQL queries&lt;/b&gt; or &lt;b&gt;stored procedures&lt;/b&gt;. Those queries can also have input parameters if needed. &lt;br /&gt; &lt;br /&gt;In the previous example, the matrix content is filled with the resultset returned by the &lt;b&gt;spContent&lt;/b&gt; stored procedure:&lt;br /&gt; &lt;br /&gt;&lt;pre&gt;
Create Procedure [dbo].[spContent] As
 
Select TableC_TableA_ID, TableC_TableB_ID, TableC_Name From dbo.TableC
&lt;/pre&gt; &lt;br /&gt; &lt;br /&gt;Since we asked for diagnostic information, here is the output :&lt;br /&gt; &lt;br /&gt;&lt;pre&gt;
14/02/2008 11:22:08.46875- The SQL Server 2-D Matrix Builder
Starting TheMatrix call
 
14/02/2008 11:22:08.484375- Starting calling the Rows query
Query: Select TableA_ID, TableA_Name From dbo.TableA Order by TableA_Name Asc
	Is Stored Procedure: False
	Parameters number: 0
14/02/2008 11:22:08.484375- ValueMember index for [TableA_ID] is: 0
14/02/2008 11:22:08.484375- DisplayMember index for [TableA_Name] is: 1
14/02/2008 11:22:08.484375- Ending calling the Rows query
 
14/02/2008 11:22:08.484375- Starting calling the Columns query
Query: Select TableB_ID, TableB_Name From dbo.TableB Order By TableB_Name Asc
	Is Stored Procedure: False
	Parameters number: 0
14/02/2008 11:22:08.484375- ValueMember index for [TableB_ID] is: 0
14/02/2008 11:22:08.484375- DisplayMember index for [TableB_Name] is: 1
14/02/2008 11:22:08.484375- Ending calling the Columns query
 
14/02/2008 11:22:08.484375- Starting initializing the Matrix content
14/02/2008 11:22:08.484375- Ending initializing the Matrix content
 
14/02/2008 11:22:08.484375- Starting calling the Content query
Query: spContent
	Is Stored Procedure: True
	Parameters number: 0
14/02/2008 11:22:08.484375- ColumnValueMember index for [TableC_TableB_ID] is: 1
14/02/2008 11:22:08.484375- RowValueMember index for [TableC_TableA_ID] is: 0
14/02/2008 11:22:08.484375- DisplayMember index for [TableC_Name] is: 2
14/02/2008 11:22:08.484375- Ending calling the Content query
 
14/02/2008 11:22:08.484375- Starting SqlMetaData description
14/02/2008 11:22:08.484375- SqlMetaData, name='HEADER', sqlDbType='NVarChar', maxLength=8, precision=0, scale=0
14/02/2008 11:22:08.5- SqlMetaData, name='TableB_5', sqlDbType='NVarChar', maxLength=15, precision=0, scale=0
14/02/2008 11:22:08.5- SqlMetaData, name='TableB_6', sqlDbType='NVarChar', maxLength=15, precision=0, scale=0
14/02/2008 11:22:08.5- SqlMetaData, name='TableB_7', sqlDbType='NVarChar', maxLength=15, precision=0, scale=0
14/02/2008 11:22:08.5- SqlMetaData, name='TableB_8', sqlDbType='NVarChar', maxLength=15, precision=0, scale=0
14/02/2008 11:22:08.5- SqlMetaData, name='TableB_9', sqlDbType='NVarChar', maxLength=15, precision=0, scale=0
14/02/2008 11:22:08.5- Ending SqlMetaData description
 
14/02/2008 11:22:08.5- Starting sending back the resultset
 
(4 row(s) affected)
14/02/2008 11:22:08.5- Ending sending back the resultset
 
14/02/2008 11:22:08.5- Ending TheMatrix call...
&lt;/pre&gt; &lt;br /&gt; &lt;br /&gt;&lt;h1&gt;
Documentation
&lt;/h1&gt; &lt;br /&gt;&lt;img src="http://www.codeplex.com/Project/Download/FileDownload.aspx?ProjectName=SQL2DMatrixBuilder&amp;amp;DownloadId=27581" alt="SQLMatrix3.png" /&gt;&lt;br /&gt; &lt;br /&gt;The &lt;b&gt;QueryBuilder&lt;/b&gt; Used-Defined Type allows you to specify what query should be executed to fill:&lt;br /&gt; &lt;br /&gt;&lt;ul&gt;
&lt;li&gt;The first column rows (Query 1)&lt;/li&gt;&lt;li&gt;The columns headers (Query 2)&lt;/li&gt;&lt;li&gt;The Matrix content (Query 3)&lt;/li&gt;
&lt;/ul&gt; &lt;br /&gt;&lt;img src="http://www.codeplex.com/Project/Download/FileDownload.aspx?ProjectName=SQL2DMatrixBuilder&amp;amp;DownloadId=27574" alt="QueryBuilder.png" /&gt;&lt;br /&gt; &lt;br /&gt; &lt;br /&gt;Once you have declared a variable of this type, you can invoke any of its static methods using the &lt;b&gt;::&lt;/b&gt; operator. If you intend to call a literal SQL query, use the &lt;b&gt;New_QueryText&lt;/b&gt; method. If you plan to use a stored procedure instead, use the &lt;b&gt;New_StoredProcedure&lt;/b&gt; method.&lt;br /&gt; &lt;br /&gt;&lt;pre&gt;
-- If you are using a literal SQL query
Declare @MyLiteralSQLQueryBuilder QueryBuilder
Set @MyLiteralSQLQueryBuilder::New_QueryText(N'Select MyColumn1, MyColumn2, MyColumn3 From MyTable1 Inner Join... Where MyColumn4 = @MyParameter')
&lt;/pre&gt; &lt;br /&gt;&lt;pre&gt;
-- If you are using a stored procedure
Declare @MyStoredProcedureQueryBuilder QueryBuilder
Set @MyStoredProcedureQueryBuilder::New_QueryText(N'MyStoredProcedureName')
&lt;/pre&gt; &lt;br /&gt;If your literal SQL query or your stored procedure need some input parameters, you can supply their values by calling the &lt;b&gt;SetParameter&lt;/b&gt; method:&lt;br /&gt; &lt;br /&gt;&lt;pre&gt;
Declare @Value [your type here]
Set @MyLiteralSQLQueryBuilder::SetParameter(N'@MyParameter', @Value)
&lt;/pre&gt; &lt;br /&gt;&lt;pre&gt;
Declare @Value [your type here]
Set @MyStoredProcedureQueryBuilder::SetParameter(N'@MyParameter', @Value)
&lt;/pre&gt; &lt;br /&gt;For the &lt;b&gt;Matrix content&lt;/b&gt; query only, we need to infere the &lt;b&gt;type&lt;/b&gt; of the columns that are returned in the &lt;b&gt;resultset&lt;/b&gt;. Although, this product tries to infere this type, it might not be suitable in all cases. Therefore, you can help infere this type by calling one of the following method:&lt;br /&gt; &lt;br /&gt;&lt;ul&gt;
&lt;ul&gt;
&lt;li&gt;SetContentType(typeName)&lt;/li&gt;&lt;li&gt;SetContentType2(typeName, maxLength)&lt;/li&gt;&lt;li&gt;SetContentType3(typeName, precision, scale)&lt;/li&gt;
&lt;/ul&gt;
&lt;/ul&gt; &lt;br /&gt;&lt;b&gt;typeName&lt;/b&gt; must be one of the &lt;b&gt;System.Data.SqlDbType&lt;/b&gt; enumeration value:&lt;br /&gt; &lt;br /&gt;&lt;img src="http://www.codeplex.com/Project/Download/FileDownload.aspx?ProjectName=SQL2DMatrixBuilder&amp;amp;DownloadId=27576" alt="SqlDbType.png" /&gt;&lt;br /&gt; &lt;br /&gt;The last thing we need to check for our three queries is the following:&lt;br /&gt; &lt;br /&gt;&lt;ul&gt;
&lt;li&gt;&lt;b&gt;Query 1&lt;/b&gt; and &lt;b&gt;Query 2&lt;/b&gt; need to return two columns (you can return more than two columns but only two columns will be used):&lt;/li&gt;&lt;ul&gt;
&lt;li&gt;one column must be the &amp;quot;&lt;b&gt;Primary Key&lt;/b&gt;&amp;quot;&lt;/li&gt;&lt;li&gt;one column must be the &amp;quot;&lt;b&gt;Display Value&lt;/b&gt;&amp;quot;&lt;/li&gt;
&lt;/ul&gt;
&lt;/ul&gt; &lt;br /&gt;&lt;ul&gt;
&lt;li&gt;&lt;b&gt;Query 3&lt;/b&gt; needs to return three columns (you can return more than three columns but only three columns will be used):&lt;/li&gt;&lt;ul&gt;
&lt;li&gt;one column must be the &amp;quot;&lt;b&gt;Row Primary Key&lt;/b&gt;&amp;quot;&lt;/li&gt;&lt;li&gt;one column must be the &amp;quot;&lt;b&gt;Column Primary Key&lt;/b&gt;&amp;quot;&lt;/li&gt;&lt;li&gt;one column must be the &amp;quot;&lt;b&gt;Display Value&lt;/b&gt;&amp;quot; of the Matrix&lt;/li&gt;
&lt;/ul&gt;
&lt;/ul&gt; &lt;br /&gt;We also need to supply two values:&lt;br /&gt;&lt;ul&gt;
&lt;li&gt;The &amp;quot;&lt;b&gt;Display Value&lt;/b&gt;&amp;quot; for the &lt;b&gt;first column header&lt;/b&gt;&lt;/li&gt;&lt;li&gt;The &amp;quot;&lt;b&gt;Display Value&lt;/b&gt;&amp;quot; to use if we have a &lt;b&gt;missing value&lt;/b&gt; in the Matrix content returned by &lt;b&gt;Query 3&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt; &lt;br /&gt;&lt;img src="http://www.codeplex.com/Project/Download/FileDownload.aspx?ProjectName=SQL2DMatrixBuilder&amp;amp;DownloadId=27582" alt="SQLMatrix4.png" /&gt;&lt;br /&gt; &lt;br /&gt;Finally, once you have correctly declared the &lt;b&gt;3 QueryBuilder variables&lt;/b&gt; you need, you can call &lt;b&gt;TheMatrix&lt;/b&gt; stored procedure.&lt;br /&gt; &lt;br /&gt; &lt;br /&gt;&lt;h1&gt;
More resources on SQL Server 2-D Matrix Builder
&lt;/h1&gt; &lt;br /&gt;An &lt;b&gt;french&lt;/b&gt; article is now available here: &lt;a href="http://msdn2.microsoft.com/fr-fr/sqlserver/cc197167.aspx" class="externalLink"&gt;The SQL Server 2-D Matrix Builder (http://msdn2.microsoft.com/fr-fr/sqlserver/cc197167.aspx)&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;This article will also be translated in &lt;b&gt;English&lt;/b&gt; very soon. Stay tuned!&lt;br /&gt;
&lt;/div&gt;</description><author>olymars</author><pubDate>Fri, 15 Feb 2008 09:15:40 GMT</pubDate><guid isPermaLink="false">UPDATED WIKI: Home 20080215091540A</guid></item><item><title>UPDATED WIKI: Home</title><link>http://www.codeplex.com/SQL2DMatrixBuilder/Wiki/View.aspx?title=Home&amp;version=41</link><description>&lt;div class="wikidoc"&gt;
&lt;h1&gt;
Introduction
&lt;/h1&gt; &lt;br /&gt;This project is all about bringing a &lt;b&gt;2-D matrix builder&lt;/b&gt; to &lt;b&gt;Microsoft SQL Server 2005&lt;/b&gt; (or later). So why do we need this? Consider the following schema:&lt;br /&gt; &lt;br /&gt;&lt;img src="http://www.codeplex.com/Project/Download/FileDownload.aspx?ProjectName=SQL2DMatrixBuilder&amp;amp;DownloadId=27479" alt="SQLMatrix1.png" /&gt;&lt;br /&gt; &lt;br /&gt;Now, what we would like to get as a &lt;b&gt;query result&lt;/b&gt; is the following :&lt;br /&gt; &lt;br /&gt;&lt;img src="http://www.codeplex.com/Project/Download/FileDownload.aspx?ProjectName=SQL2DMatrixBuilder&amp;amp;DownloadId=27480" alt="SQLMatrix2.png" /&gt;&lt;br /&gt; &lt;br /&gt;Notice that the headers are not &lt;i&gt;columns names&lt;/i&gt; but the &lt;b&gt;records&lt;/b&gt; available in the &lt;b&gt;Table_B&lt;/b&gt; table. So how do you get this natively with Microsoft SQL Server? Well, you can't! Unless you use the &lt;b&gt;SQL Server 2-D Matrix Builder&lt;/b&gt;.&lt;br /&gt; &lt;br /&gt;This project is all about using the &lt;b&gt;hosted .NET Common Langage Runtime&lt;/b&gt; in Microsoft SQL Server. All you have to do is uploading the &lt;b&gt;TheMatrixSqlClr.dll&lt;/b&gt; assembly into your SQL Server instance and use it. The next two chapters describe how to install this assembly into your SQL Server instance and how to reuse &lt;b&gt;TheMatrix&lt;/b&gt; stored procedure.&lt;br /&gt; &lt;br /&gt;This project was built by &lt;b&gt;Pascal Belaud&lt;/b&gt;, Developer Evangelist at &lt;b&gt;Microsoft France&lt;/b&gt; &lt;a href="http://blogs.msdn.com/Pascal" class="externalLink"&gt;French Blog (http://blogs.msdn.com/Pascal)&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;). Pascal is also the author of a &lt;b&gt;.NET code generator&lt;/b&gt; based on SQL Server 2005 called &lt;b&gt;OlyMars&lt;/b&gt; (&lt;a href="http://www.olymars.net" class="externalLink"&gt;http://www.olymars.net&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;).&lt;br /&gt; &lt;br /&gt; &lt;br /&gt;&lt;h1&gt;
Deployment
&lt;/h1&gt; &lt;br /&gt;&lt;pre&gt;
-- First you need to enable the use of .NET in your SLQ Server instance
exec sp_configure 'CLR Enabled', 1
reconfigure
GO
 
-- Since this assembly needs external access, your database needs to be TrustWorthy
Alter Database YourDatabase
Set Trustworthy On
GO
 
Use YourDatabase
GO
 
-- You need to deploy the assembly in your SQL Server instance
CREATE ASSEMBLY [TheSQLServerMatrix]
FROM '&amp;lt;Your path to the assembly here&amp;gt;\TheMatrixSqlClr.dll'
WITH PERMISSION_SET=EXTERNAL_ACCESS
GO
 
-- You need to declare a new User Defined Type
CREATE TYPE [QueryBuilder]
EXTERNAL NAME [TheSQLServerMatrix].[TheMatrixSqlClr.QueryBuilder]
GO
 
-- You need to declare a new stored procedure
CREATE PROCEDURE [TheMatrix]
  @rowsQuery [QueryBuilder]
, @rowsQuery_ValueMember nvarchar(max)
, @rowsQuery_DisplayMember nvarchar(max)
, @firstColumnHeader nvarchar(max)
, @columnsQuery [QueryBuilder]
, @columnsQuery_ValueMember nvarchar(max)
, @columnsQuery_DisplayMember nvarchar(max)
, @contentQuery [QueryBuilder]
, @contentQuery_ColumnValueMember nvarchar(max)
, @contentQuery_RowValueMember nvarchar(max)
, @contentQuery_DisplayName nvarchar(max)
, @contentQuery_MissingValue sql_variant
, @diagnose bit = 0
 
AS
EXTERNAL NAME [TheSQLServerMatrix].[TheMatrixSqlClr.StoredProcedures].[TheMatrix]
&lt;/pre&gt; &lt;br /&gt; &lt;br /&gt;&lt;h1&gt;
Usage
&lt;/h1&gt; &lt;br /&gt;Now that the assembly is declared in our instance, we can use &lt;b&gt;TheMatrix&lt;/b&gt; stored procedure like this:&lt;br /&gt; &lt;br /&gt;&lt;pre&gt;
-- Let's declare the first column rows
DECLARE @rowsQuery QueryBuilder
DECLARE @rowsQuery_ValueMember nvarchar(max)
DECLARE @rowsQuery_DisplayMember nvarchar(max)
SET @rowsQuery = QueryBuilder::New_QueryText('Select TableA_ID, TableA_Name From dbo.TableA Order by TableA_Name Asc')
SET @rowsQuery_ValueMember = 'TableA_ID'
SET @rowsQuery_DisplayMember = 'TableA_Name'
 
-- Let's declare the name of the first column header
DECLARE @firstColumnHeader nvarchar(max)
SET @firstColumnHeader = 'HEADER'
 
-- Let's declare the others columns headers
DECLARE @columnsQuery QueryBuilder
DECLARE @columnsQuery_ValueMember nvarchar(max)
DECLARE @columnsQuery_DisplayMember nvarchar(max)
SET @columnsQuery = QueryBuilder::New_QueryText('Select TableB_ID, TableB_Name From dbo.TableB Order By TableB_Name Asc')
SET @columnsQuery_ValueMember = 'TableB_ID'
SET @columnsQuery_DisplayMember = 'TableB_Name'
 
-- Let's declare how to fill the matrix content
DECLARE @contentQuery QueryBuilder
DECLARE @contentQuery_ColumnValueMember nvarchar(max)
DECLARE @contentQuery_RowValueMember nvarchar(max)
DECLARE @contentQuery_DisplayName nvarchar(max)
DECLARE @contentQuery_NullValue sql_variant
SET @contentQuery = QueryBuilder::New_StoredProcedure('spContent')
SET @contentQuery_ColumnValueMember = 'TableC_TableB_ID'
SET @contentQuery_RowValueMember = 'TableC_TableA_ID'
SET @contentQuery_DisplayName = 'TableC_Name'
SET @contentQuery_NullValue = '[NOT AVAILABLE]'
 
-- We want to see how the Matrix is going to execute all this
DECLARE @diagnose bit
SET @diagnose = 1
 
EXECUTE [TheMatrixDatabase].[dbo].[TheMatrix] 
   @rowsQuery
  ,@rowsQuery_ValueMember
  ,@rowsQuery_DisplayMember
  ,@firstColumnHeader
 
  ,@columnsQuery
  ,@columnsQuery_ValueMember
  ,@columnsQuery_DisplayMember
 
  ,@contentQuery
  ,@contentQuery_RowValueMember
  ,@contentQuery_ColumnValueMember
  ,@contentQuery_DisplayName
  ,@contentQuery_NullValue
  ,@diagnose
&lt;/pre&gt; &lt;br /&gt;When you execute this, you get the following resulset :&lt;br /&gt; &lt;br /&gt;&lt;table&gt;
&lt;tr&gt;
&lt;th&gt; HEADER &lt;/th&gt;&lt;th&gt; TableB_5 &lt;/th&gt;&lt;th&gt; TableB_6 &lt;/th&gt;&lt;th&gt; TableB_7 &lt;/th&gt;&lt;th&gt; TableB_8 &lt;/th&gt;&lt;th&gt; TableB_9 &lt;/th&gt;
&lt;/tr&gt;&lt;tr&gt;
&lt;td&gt; TableA_1 &lt;/td&gt;&lt;td&gt; TableC_1_5 &lt;/td&gt;&lt;td&gt; TableC_1_6 &lt;/td&gt;&lt;td&gt; TableC_1_7 &lt;/td&gt;&lt;td&gt; TableC_1_8 &lt;/td&gt;&lt;td&gt; TableC_1_9 &lt;/td&gt;
&lt;/tr&gt;&lt;tr&gt;
&lt;td&gt; TableA_2 &lt;/td&gt;&lt;td&gt; [NOT AVAILABLE] &lt;/td&gt;&lt;td&gt; TableC_2_6 &lt;/td&gt;&lt;td&gt; TableC_2_7 &lt;/td&gt;&lt;td&gt; TableC_2_8 &lt;/td&gt;&lt;td&gt; TableC_2_9 &lt;/td&gt;
&lt;/tr&gt;&lt;tr&gt;
&lt;td&gt; TableA_3 &lt;/td&gt;&lt;td&gt; TableC_3_5 &lt;/td&gt;&lt;td&gt; [NOT AVAILABLE] &lt;/td&gt;&lt;td&gt; TableC_3_7 &lt;/td&gt;&lt;td&gt; TableC_3_8 &lt;/td&gt;&lt;td&gt; TableC_3_9 &lt;/td&gt;
&lt;/tr&gt;&lt;tr&gt;
&lt;td&gt; TableA_4 &lt;/td&gt;&lt;td&gt; TableC_4_ &lt;/td&gt;&lt;td&gt; TableC_4_6 &lt;/td&gt;&lt;td&gt; TableC_4_7 &lt;/td&gt;&lt;td&gt; TableC_4_8 &lt;/td&gt;&lt;td&gt; TableC_4_9 &lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt; &lt;br /&gt; &lt;br /&gt;Notice that the Matrix allows you to call &lt;b&gt;literal SQL queries&lt;/b&gt; or &lt;b&gt;stored procedures&lt;/b&gt;. Those queries can also have input parameters if needed. &lt;br /&gt; &lt;br /&gt;In the previous example, the matrix content is filled with the resultset returned by the &lt;b&gt;spContent&lt;/b&gt; stored procedure:&lt;br /&gt; &lt;br /&gt;&lt;pre&gt;
Create Procedure [dbo].[spContent] As
 
Select TableC_TableA_ID, TableC_TableB_ID, TableC_Name From dbo.TableC
&lt;/pre&gt; &lt;br /&gt; &lt;br /&gt;Since we asked for diagnostic information, here is the output :&lt;br /&gt; &lt;br /&gt;&lt;pre&gt;
14/02/2008 11:22:08.46875- The SQL Server 2-D Matrix Builder
Starting TheMatrix call
 
14/02/2008 11:22:08.484375- Starting calling the Rows query
Query: Select TableA_ID, TableA_Name From dbo.TableA Order by TableA_Name Asc
	Is Stored Procedure: False
	Parameters number: 0
14/02/2008 11:22:08.484375- ValueMember index for [TableA_ID] is: 0
14/02/2008 11:22:08.484375- DisplayMember index for [TableA_Name] is: 1
14/02/2008 11:22:08.484375- Ending calling the Rows query
 
14/02/2008 11:22:08.484375- Starting calling the Columns query
Query: Select TableB_ID, TableB_Name From dbo.TableB Order By TableB_Name Asc
	Is Stored Procedure: False
	Parameters number: 0
14/02/2008 11:22:08.484375- ValueMember index for [TableB_ID] is: 0
14/02/2008 11:22:08.484375- DisplayMember index for [TableB_Name] is: 1
14/02/2008 11:22:08.484375- Ending calling the Columns query
 
14/02/2008 11:22:08.484375- Starting initializing the Matrix content
14/02/2008 11:22:08.484375- Ending initializing the Matrix content
 
14/02/2008 11:22:08.484375- Starting calling the Content query
Query: spContent
	Is Stored Procedure: True
	Parameters number: 0
14/02/2008 11:22:08.484375- ColumnValueMember index for [TableC_TableB_ID] is: 1
14/02/2008 11:22:08.484375- RowValueMember index for [TableC_TableA_ID] is: 0
14/02/2008 11:22:08.484375- DisplayMember index for [TableC_Name] is: 2
14/02/2008 11:22:08.484375- Ending calling the Content query
 
14/02/2008 11:22:08.484375- Starting SqlMetaData description
14/02/2008 11:22:08.484375- SqlMetaData, name='HEADER', sqlDbType='NVarChar', maxLength=8, precision=0, scale=0
14/02/2008 11:22:08.5- SqlMetaData, name='TableB_5', sqlDbType='NVarChar', maxLength=15, precision=0, scale=0
14/02/2008 11:22:08.5- SqlMetaData, name='TableB_6', sqlDbType='NVarChar', maxLength=15, precision=0, scale=0
14/02/2008 11:22:08.5- SqlMetaData, name='TableB_7', sqlDbType='NVarChar', maxLength=15, precision=0, scale=0
14/02/2008 11:22:08.5- SqlMetaData, name='TableB_8', sqlDbType='NVarChar', maxLength=15, precision=0, scale=0
14/02/2008 11:22:08.5- SqlMetaData, name='TableB_9', sqlDbType='NVarChar', maxLength=15, precision=0, scale=0
14/02/2008 11:22:08.5- Ending SqlMetaData description
 
14/02/2008 11:22:08.5- Starting sending back the resultset
 
(4 row(s) affected)
14/02/2008 11:22:08.5- Ending sending back the resultset
 
14/02/2008 11:22:08.5- Ending TheMatrix call...
&lt;/pre&gt; &lt;br /&gt; &lt;br /&gt;&lt;h1&gt;
Documentation
&lt;/h1&gt; &lt;br /&gt;&lt;img src="http://www.codeplex.com/Project/Download/FileDownload.aspx?ProjectName=SQL2DMatrixBuilder&amp;amp;DownloadId=27581" alt="SQLMatrix3.png" /&gt;&lt;br /&gt; &lt;br /&gt;The &lt;b&gt;QueryBuilder&lt;/b&gt; Used-Defined Type allows you to specify what query should be executed to fill:&lt;br /&gt; &lt;br /&gt;&lt;ul&gt;
&lt;li&gt;The first column rows (Query 1)&lt;/li&gt;&lt;li&gt;The columns headers (Query 2)&lt;/li&gt;&lt;li&gt;The Matrix content (Query 3)&lt;/li&gt;
&lt;/ul&gt; &lt;br /&gt;&lt;img src="http://www.codeplex.com/Project/Download/FileDownload.aspx?ProjectName=SQL2DMatrixBuilder&amp;amp;DownloadId=27574" alt="QueryBuilder.png" /&gt;&lt;br /&gt; &lt;br /&gt; &lt;br /&gt;Once you have declared a variable of this type, you can invoke any of its static methods using the &lt;b&gt;::&lt;/b&gt; operator. If you intend to call a literal SQL query, use the &lt;b&gt;New_QueryText&lt;/b&gt; method. If you plan to use a stored procedure instead, use the &lt;b&gt;New_StoredProcedure&lt;/b&gt; method.&lt;br /&gt; &lt;br /&gt;&lt;pre&gt;
-- If you are using a literal SQL query
Declare @MyLiteralSQLQueryBuilder QueryBuilder
Set @MyLiteralSQLQueryBuilder::New_QueryText(N'Select MyColumn1, MyColumn2, MyColumn3 From MyTable1 Inner Join... Where MyColumn4 = @MyParameter')
&lt;/pre&gt; &lt;br /&gt;&lt;pre&gt;
-- If you are using a stored procedure
Declare @MyStoredProcedureQueryBuilder QueryBuilder
Set @MyStoredProcedureQueryBuilder::New_QueryText(N'MyStoredProcedureName')
&lt;/pre&gt; &lt;br /&gt;If your literal SQL query or your stored procedure need some input parameters, you can supply their values by calling the &lt;b&gt;SetParameter&lt;/b&gt; method:&lt;br /&gt; &lt;br /&gt;&lt;pre&gt;
Declare @Value [your type here]
Set @MyLiteralSQLQueryBuilder::SetParameter(N'@MyParameter', @Value)
&lt;/pre&gt; &lt;br /&gt;&lt;pre&gt;
Declare @Value [your type here]
Set @MyStoredProcedureQueryBuilder::SetParameter(N'@MyParameter', @Value)
&lt;/pre&gt; &lt;br /&gt;For the &lt;b&gt;Matrix content&lt;/b&gt; query only, we need to infere the &lt;b&gt;type&lt;/b&gt; of the columns that are returned in the &lt;b&gt;resultset&lt;/b&gt;. Although, this product tries to infere this type, it might not be suitable in all cases. Therefore, you can help infere this type by calling one of the following method:&lt;br /&gt; &lt;br /&gt;&lt;ul&gt;
&lt;ul&gt;
&lt;li&gt;SetContentType(typeName)&lt;/li&gt;&lt;li&gt;SetContentType2(typeName, maxLength)&lt;/li&gt;&lt;li&gt;SetContentType3(typeName, precision, scale)&lt;/li&gt;
&lt;/ul&gt;
&lt;/ul&gt; &lt;br /&gt;&lt;b&gt;typeName&lt;/b&gt; must be one of the &lt;b&gt;System.Data.SqlDbType&lt;/b&gt; enumeration value:&lt;br /&gt; &lt;br /&gt;&lt;img src="http://www.codeplex.com/Project/Download/FileDownload.aspx?ProjectName=SQL2DMatrixBuilder&amp;amp;DownloadId=27576" alt="SqlDbType.png" /&gt;&lt;br /&gt; &lt;br /&gt;The last thing we need to check for our three queries is the following:&lt;br /&gt; &lt;br /&gt;&lt;ul&gt;
&lt;li&gt;&lt;b&gt;Query 1&lt;/b&gt; and &lt;b&gt;Query 2&lt;/b&gt; need to return two columns (you can return more than two columns but only two columns will be used):&lt;/li&gt;&lt;ul&gt;
&lt;li&gt;one column must be the &amp;quot;&lt;b&gt;Primary Key&lt;/b&gt;&amp;quot;&lt;/li&gt;&lt;li&gt;one column must be the &amp;quot;&lt;b&gt;Display Value&lt;/b&gt;&amp;quot;&lt;/li&gt;
&lt;/ul&gt;
&lt;/ul&gt; &lt;br /&gt;&lt;ul&gt;
&lt;li&gt;&lt;b&gt;Query 3&lt;/b&gt; needs to return three columns (you can return more than three columns but only three columns will be used):&lt;/li&gt;&lt;ul&gt;
&lt;li&gt;one column must be the &amp;quot;&lt;b&gt;Row Primary Key&lt;/b&gt;&amp;quot;&lt;/li&gt;&lt;li&gt;one column must be the &amp;quot;&lt;b&gt;Column Primary Key&lt;/b&gt;&amp;quot;&lt;/li&gt;&lt;li&gt;one column must be the &amp;quot;&lt;b&gt;Display Value&lt;/b&gt;&amp;quot; of the Matrix&lt;/li&gt;
&lt;/ul&gt;
&lt;/ul&gt; &lt;br /&gt;We also need to supply two values:&lt;br /&gt;&lt;ul&gt;
&lt;li&gt;The &amp;quot;&lt;b&gt;Display Value&lt;/b&gt;&amp;quot; for the &lt;b&gt;first column header&lt;/b&gt;&lt;/li&gt;&lt;li&gt;The &amp;quot;&lt;b&gt;Display Value&lt;/b&gt;&amp;quot; to use if we have a &lt;b&gt;missing value&lt;/b&gt; in the Matrix content returned by &lt;b&gt;Query 3&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt; &lt;br /&gt;Finally, once you have declared the &lt;b&gt;3 QueryBuilder variables&lt;/b&gt; you need, you can call &lt;b&gt;TheMatrix&lt;/b&gt; stored procedure.&lt;br /&gt; &lt;br /&gt; &lt;br /&gt;&lt;h1&gt;
More resources on SQL Server 2-D Matrix Builder
&lt;/h1&gt; &lt;br /&gt;An &lt;b&gt;french&lt;/b&gt; article is now available here: &lt;a href="http://msdn2.microsoft.com/fr-fr/sqlserver/cc197167.aspx" class="externalLink"&gt;The SQL Server 2-D Matrix Builder (http://msdn2.microsoft.com/fr-fr/sqlserver/cc197167.aspx)&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;This article will also be translated in &lt;b&gt;English&lt;/b&gt; very soon. Stay tuned!&lt;br /&gt;
&lt;/div&gt;</description><author>olymars</author><pubDate>Fri, 15 Feb 2008 09:12:52 GMT</pubDate><guid isPermaLink="false">UPDATED WIKI: Home 20080215091252A</guid></item><item><title>UPDATED WIKI: Home</title><link>http://www.codeplex.com/SQL2DMatrixBuilder/Wiki/View.aspx?title=Home&amp;version=40</link><description>&lt;div class="wikidoc"&gt;
&lt;h1&gt;
Introduction
&lt;/h1&gt; &lt;br /&gt;This project is all about bringing a &lt;b&gt;2-D matrix builder&lt;/b&gt; to &lt;b&gt;Microsoft SQL Server 2005&lt;/b&gt; (or later). So why do we need this? Consider the following schema:&lt;br /&gt; &lt;br /&gt;&lt;img src="http://www.codeplex.com/Project/Download/FileDownload.aspx?ProjectName=SQL2DMatrixBuilder&amp;amp;DownloadId=27479" alt="SQLMatrix1.png" /&gt;&lt;br /&gt; &lt;br /&gt;Now, what we would like to get as a &lt;b&gt;query result&lt;/b&gt; is the following :&lt;br /&gt; &lt;br /&gt;&lt;img src="http://www.codeplex.com/Project/Download/FileDownload.aspx?ProjectName=SQL2DMatrixBuilder&amp;amp;DownloadId=27480" alt="SQLMatrix2.png" /&gt;&lt;br /&gt; &lt;br /&gt;Notice that the headers are not &lt;i&gt;columns names&lt;/i&gt; but the &lt;b&gt;records&lt;/b&gt; available in the &lt;b&gt;Table_B&lt;/b&gt; table. So how do you get this natively with Microsoft SQL Server? Well, you can't! Unless you use the &lt;b&gt;SQL Server 2-D Matrix Builder&lt;/b&gt;.&lt;br /&gt; &lt;br /&gt;This project is all about using the &lt;b&gt;hosted .NET Common Langage Runtime&lt;/b&gt; in Microsoft SQL Server. All you have to do is uploading the &lt;b&gt;TheMatrixSqlClr.dll&lt;/b&gt; assembly into your SQL Server instance and use it. The next two chapters describe how to install this assembly into your SQL Server instance and how to reuse &lt;b&gt;TheMatrix&lt;/b&gt; stored procedure.&lt;br /&gt; &lt;br /&gt;This project was built by &lt;b&gt;Pascal Belaud&lt;/b&gt;, Developer Evangelist at &lt;b&gt;Microsoft France&lt;/b&gt; &lt;a href="http://blogs.msdn.com/Pascal" class="externalLink"&gt;French Blog (http://blogs.msdn.com/Pascal)&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;). Pascal is also the author of a &lt;b&gt;.NET code generator&lt;/b&gt; based on SQL Server 2005 called &lt;b&gt;OlyMars&lt;/b&gt; (&lt;a href="http://www.olymars.net" class="externalLink"&gt;http://www.olymars.net&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;).&lt;br /&gt; &lt;br /&gt; &lt;br /&gt;&lt;h1&gt;
Deployment
&lt;/h1&gt; &lt;br /&gt;&lt;pre&gt;
-- First you need to enable the use of .NET in your SLQ Server instance
exec sp_configure 'CLR Enabled', 1
reconfigure
GO
 
-- Since this assembly needs external access, your database needs to be TrustWorthy
Alter Database YourDatabase
Set Trustworthy On
GO
 
Use YourDatabase
GO
 
-- You need to deploy the assembly in your SQL Server instance
CREATE ASSEMBLY [TheSQLServerMatrix]
FROM '&amp;lt;Your path to the assembly here&amp;gt;\TheMatrixSqlClr.dll'
WITH PERMISSION_SET=EXTERNAL_ACCESS
GO
 
-- You need to declare a new User Defined Type
CREATE TYPE [QueryBuilder]
EXTERNAL NAME [TheSQLServerMatrix].[TheMatrixSqlClr.QueryBuilder]
GO
 
-- You need to declare a new stored procedure
CREATE PROCEDURE [TheMatrix]
  @rowsQuery [QueryBuilder]
, @rowsQuery_ValueMember nvarchar(max)
, @rowsQuery_DisplayMember nvarchar(max)
, @firstColumnHeader nvarchar(max)
, @columnsQuery [QueryBuilder]
, @columnsQuery_ValueMember nvarchar(max)
, @columnsQuery_DisplayMember nvarchar(max)
, @contentQuery [QueryBuilder]
, @contentQuery_ColumnValueMember nvarchar(max)
, @contentQuery_RowValueMember nvarchar(max)
, @contentQuery_DisplayName nvarchar(max)
, @contentQuery_MissingValue sql_variant
, @diagnose bit = 0
 
AS
EXTERNAL NAME [TheSQLServerMatrix].[TheMatrixSqlClr.StoredProcedures].[TheMatrix]
&lt;/pre&gt; &lt;br /&gt; &lt;br /&gt;&lt;h1&gt;
Usage
&lt;/h1&gt; &lt;br /&gt;Now that the assembly is declared in our instance, we can use &lt;b&gt;TheMatrix&lt;/b&gt; stored procedure like this:&lt;br /&gt; &lt;br /&gt;&lt;pre&gt;
-- Let's declare the first column rows
DECLARE @rowsQuery QueryBuilder
DECLARE @rowsQuery_ValueMember nvarchar(max)
DECLARE @rowsQuery_DisplayMember nvarchar(max)
SET @rowsQuery = QueryBuilder::New_QueryText('Select TableA_ID, TableA_Name From dbo.TableA Order by TableA_Name Asc')
SET @rowsQuery_ValueMember = 'TableA_ID'
SET @rowsQuery_DisplayMember = 'TableA_Name'
 
-- Let's declare the name of the first column header
DECLARE @firstColumnHeader nvarchar(max)
SET @firstColumnHeader = 'HEADER'
 
-- Let's declare the others columns headers
DECLARE @columnsQuery QueryBuilder
DECLARE @columnsQuery_ValueMember nvarchar(max)
DECLARE @columnsQuery_DisplayMember nvarchar(max)
SET @columnsQuery = QueryBuilder::New_QueryText('Select TableB_ID, TableB_Name From dbo.TableB Order By TableB_Name Asc')
SET @columnsQuery_ValueMember = 'TableB_ID'
SET @columnsQuery_DisplayMember = 'TableB_Name'
 
-- Let's declare how to fill the matrix content
DECLARE @contentQuery QueryBuilder
DECLARE @contentQuery_ColumnValueMember nvarchar(max)
DECLARE @contentQuery_RowValueMember nvarchar(max)
DECLARE @contentQuery_DisplayName nvarchar(max)
DECLARE @contentQuery_NullValue sql_variant
SET @contentQuery = QueryBuilder::New_StoredProcedure('spContent')
SET @contentQuery_ColumnValueMember = 'TableC_TableB_ID'
SET @contentQuery_RowValueMember = 'TableC_TableA_ID'
SET @contentQuery_DisplayName = 'TableC_Name'
SET @contentQuery_NullValue = '[NOT AVAILABLE]'
 
-- We want to see how the Matrix is going to execute all this
DECLARE @diagnose bit
SET @diagnose = 1
 
EXECUTE [TheMatrixDatabase].[dbo].[TheMatrix] 
   @rowsQuery
  ,@rowsQuery_ValueMember
  ,@rowsQuery_DisplayMember
  ,@firstColumnHeader
 
  ,@columnsQuery
  ,@columnsQuery_ValueMember
  ,@columnsQuery_DisplayMember
 
  ,@contentQuery
  ,@contentQuery_RowValueMember
  ,@contentQuery_ColumnValueMember
  ,@contentQuery_DisplayName
  ,@contentQuery_NullValue
  ,@diagnose
&lt;/pre&gt; &lt;br /&gt;When you execute this, you get the following resulset :&lt;br /&gt; &lt;br /&gt;&lt;table&gt;
&lt;tr&gt;
&lt;th&gt; HEADER &lt;/th&gt;&lt;th&gt; TableB_5 &lt;/th&gt;&lt;th&gt; TableB_6 &lt;/th&gt;&lt;th&gt; TableB_7 &lt;/th&gt;&lt;th&gt; TableB_8 &lt;/th&gt;&lt;th&gt; TableB_9 &lt;/th&gt;
&lt;/tr&gt;&lt;tr&gt;
&lt;td&gt; TableA_1 &lt;/td&gt;&lt;td&gt; TableC_1_5 &lt;/td&gt;&lt;td&gt; TableC_1_6 &lt;/td&gt;&lt;td&gt; TableC_1_7 &lt;/td&gt;&lt;td&gt; TableC_1_8 &lt;/td&gt;&lt;td&gt; TableC_1_9 &lt;/td&gt;
&lt;/tr&gt;&lt;tr&gt;
&lt;td&gt; TableA_2 &lt;/td&gt;&lt;td&gt; [NOT AVAILABLE] &lt;/td&gt;&lt;td&gt; TableC_2_6 &lt;/td&gt;&lt;td&gt; TableC_2_7 &lt;/td&gt;&lt;td&gt; TableC_2_8 &lt;/td&gt;&lt;td&gt; TableC_2_9 &lt;/td&gt;
&lt;/tr&gt;&lt;tr&gt;
&lt;td&gt; TableA_3 &lt;/td&gt;&lt;td&gt; TableC_3_5 &lt;/td&gt;&lt;td&gt; [NOT AVAILABLE] &lt;/td&gt;&lt;td&gt; TableC_3_7 &lt;/td&gt;&lt;td&gt; TableC_3_8 &lt;/td&gt;&lt;td&gt; TableC_3_9 &lt;/td&gt;
&lt;/tr&gt;&lt;tr&gt;
&lt;td&gt; TableA_4 &lt;/td&gt;&lt;td&gt; TableC_4_ &lt;/td&gt;&lt;td&gt; TableC_4_6 &lt;/td&gt;&lt;td&gt; TableC_4_7 &lt;/td&gt;&lt;td&gt; TableC_4_8 &lt;/td&gt;&lt;td&gt; TableC_4_9 &lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt; &lt;br /&gt; &lt;br /&gt;Notice that the Matrix allows you to call &lt;b&gt;literal SQL queries&lt;/b&gt; or &lt;b&gt;stored procedures&lt;/b&gt;. Those queries can also have input parameters if needed. &lt;br /&gt; &lt;br /&gt;In the previous example, the matrix content is filled with the resultset returned by the &lt;b&gt;spContent&lt;/b&gt; stored procedure:&lt;br /&gt; &lt;br /&gt;&lt;pre&gt;
Create Procedure [dbo].[spContent] As
 
Select TableC_TableA_ID, TableC_TableB_ID, TableC_Name From dbo.TableC
&lt;/pre&gt; &lt;br /&gt; &lt;br /&gt;Since we asked for diagnostic information, here is the output :&lt;br /&gt; &lt;br /&gt;&lt;pre&gt;
14/02/2008 11:22:08.46875- The SQL Server 2-D Matrix Builder
Starting TheMatrix call
 
14/02/2008 11:22:08.484375- Starting calling the Rows query
Query: Select TableA_ID, TableA_Name From dbo.TableA Order by TableA_Name Asc
	Is Stored Procedure: False
	Parameters number: 0
14/02/2008 11:22:08.484375- ValueMember index for [TableA_ID] is: 0
14/02/2008 11:22:08.484375- DisplayMember index for [TableA_Name] is: 1
14/02/2008 11:22:08.484375- Ending calling the Rows query
 
14/02/2008 11:22:08.484375- Starting calling the Columns query
Query: Select TableB_ID, TableB_Name From dbo.TableB Order By TableB_Name Asc
	Is Stored Procedure: False
	Parameters number: 0
14/02/2008 11:22:08.484375- ValueMember index for [TableB_ID] is: 0
14/02/2008 11:22:08.484375- DisplayMember index for [TableB_Name] is: 1
14/02/2008 11:22:08.484375- Ending calling the Columns query
 
14/02/2008 11:22:08.484375- Starting initializing the Matrix content
14/02/2008 11:22:08.484375- Ending initializing the Matrix content
 
14/02/2008 11:22:08.484375- Starting calling the Content query
Query: spContent
	Is Stored Procedure: True
	Parameters number: 0
14/02/2008 11:22:08.484375- ColumnValueMember index for [TableC_TableB_ID] is: 1
14/02/2008 11:22:08.484375- RowValueMember index for [TableC_TableA_ID] is: 0
14/02/2008 11:22:08.484375- DisplayMember index for [TableC_Name] is: 2
14/02/2008 11:22:08.484375- Ending calling the Content query
 
14/02/2008 11:22:08.484375- Starting SqlMetaData description
14/02/2008 11:22:08.484375- SqlMetaData, name='HEADER', sqlDbType='NVarChar', maxLength=8, precision=0, scale=0
14/02/2008 11:22:08.5- SqlMetaData, name='TableB_5', sqlDbType='NVarChar', maxLength=15, precision=0, scale=0
14/02/2008 11:22:08.5- SqlMetaData, name='TableB_6', sqlDbType='NVarChar', maxLength=15, precision=0, scale=0
14/02/2008 11:22:08.5- SqlMetaData, name='TableB_7', sqlDbType='NVarChar', maxLength=15, precision=0, scale=0
14/02/2008 11:22:08.5- SqlMetaData, name='TableB_8', sqlDbType='NVarChar', maxLength=15, precision=0, scale=0
14/02/2008 11:22:08.5- SqlMetaData, name='TableB_9', sqlDbType='NVarChar', maxLength=15, precision=0, scale=0
14/02/2008 11:22:08.5- Ending SqlMetaData description
 
14/02/2008 11:22:08.5- Starting sending back the resultset
 
(4 row(s) affected)
14/02/2008 11:22:08.5- Ending sending back the resultset
 
14/02/2008 11:22:08.5- Ending TheMatrix call...
&lt;/pre&gt; &lt;br /&gt; &lt;br /&gt;&lt;h1&gt;
Documentation
&lt;/h1&gt; &lt;br /&gt;&lt;img src="http://www.codeplex.com/Project/Download/FileDownload.aspx?ProjectName=SQL2DMatrixBuilder&amp;amp;DownloadId=27581" alt="SQLMatrix3.png" /&gt;&lt;br /&gt; &lt;br /&gt;The &lt;b&gt;QueryBuilder&lt;/b&gt; Used-Defined Type allows you to specify what query should be executed to fill:&lt;br /&gt; &lt;br /&gt;&lt;ul&gt;
&lt;li&gt;The first column rows (Query 1)&lt;/li&gt;&lt;li&gt;The columns headers (Query 2)&lt;/li&gt;&lt;li&gt;The Matrix content (Query 3)&lt;/li&gt;
&lt;/ul&gt; &lt;br /&gt;&lt;img src="http://www.codeplex.com/Project/Download/FileDownload.aspx?ProjectName=SQL2DMatrixBuilder&amp;amp;DownloadId=27574" alt="QueryBuilder.png" /&gt;&lt;br /&gt; &lt;br /&gt; &lt;br /&gt;Once you have declared a variable of this type, you can invoke any of its static methods using the &lt;b&gt;::&lt;/b&gt; operator. If you intend to call a literal SQL query, use the &lt;b&gt;New_QueryText&lt;/b&gt; method. If you plan to use a stored procedure instead, use the &lt;b&gt;New_StoredProcedure&lt;/b&gt; method.&lt;br /&gt; &lt;br /&gt;&lt;pre&gt;
-- If you are using a literal SQL query
Declare @MyLiteralSQLQueryBuilder QueryBuilder
Set @MyLiteralSQLQueryBuilder::New_QueryText(N'Select MyColumn1, MyColumn2, MyColumn3 From MyTable1 Inner Join... Where MyColumn4 = @MyParameter')
&lt;/pre&gt; &lt;br /&gt;&lt;pre&gt;
-- If you are using a stored procedure
Declare @MyStoredProcedureQueryBuilder QueryBuilder
Set @MyStoredProcedureQueryBuilder::New_QueryText(N'MyStoredProcedureName')
&lt;/pre&gt; &lt;br /&gt;If your literal SQL query or your stored procedure need some input parameters, you can supply their values by calling the &lt;b&gt;SetParameter&lt;/b&gt; method:&lt;br /&gt; &lt;br /&gt;&lt;pre&gt;
Declare @Value [your type here]
Set @MyLiteralSQLQueryBuilder::SetParameter(N'@MyParameter', @Value)
&lt;/pre&gt; &lt;br /&gt;&lt;pre&gt;
Declare @Value [your type here]
Set @MyStoredProcedureQueryBuilder::SetParameter(N'@MyParameter', @Value)
&lt;/pre&gt; &lt;br /&gt;For the &lt;b&gt;Matrix content&lt;/b&gt; query only, we need to infere the &lt;b&gt;type&lt;/b&gt; of the columns that are returned in the &lt;b&gt;resultset&lt;/b&gt;. Although, this product tries to infere this type, it might not be suitable in all cases. Therefore, you can help infere this type by calling one of the following method:&lt;br /&gt; &lt;br /&gt;&lt;ul&gt;
&lt;ul&gt;
&lt;li&gt;SetContentType(typeName)&lt;/li&gt;&lt;li&gt;SetContentType2(typeName, maxLength)&lt;/li&gt;&lt;li&gt;SetContentType3(typeName, precision, scale)&lt;/li&gt;
&lt;/ul&gt;
&lt;/ul&gt; &lt;br /&gt;&lt;b&gt;typeName&lt;/b&gt; must be one of the &lt;b&gt;System.Data.SqlDbType&lt;/b&gt; enumeration value:&lt;br /&gt; &lt;br /&gt;&lt;img src="http://www.codeplex.com/Project/Download/FileDownload.aspx?ProjectName=SQL2DMatrixBuilder&amp;amp;DownloadId=27576" alt="SqlDbType.png" /&gt;&lt;br /&gt; &lt;br /&gt;The last thing we need to check for our three queries is the following:&lt;br /&gt; &lt;br /&gt;&lt;ul&gt;
&lt;li&gt;&lt;b&gt;Query 1&lt;/b&gt; and &lt;b&gt;Query 2&lt;/b&gt; need to return two columns (you can return more than two columns but only two columns will be used):&lt;/li&gt;&lt;ul&gt;
&lt;li&gt;one column must be the &amp;quot;&lt;b&gt;Primary Key&lt;/b&gt;&amp;quot;&lt;/li&gt;&lt;li&gt;one column must be the &amp;quot;&lt;b&gt;Display Value&lt;/b&gt;&amp;quot;&lt;/li&gt;
&lt;/ul&gt;
&lt;/ul&gt; &lt;br /&gt;&lt;ul&gt;
&lt;li&gt;&lt;b&gt;Query 3&lt;/b&gt; needs to return three columns (you can return more than three columns but only three columns will be used):&lt;/li&gt;&lt;ul&gt;
&lt;li&gt;one column must be the &amp;quot;Row Primary Key&amp;quot;&lt;/li&gt;&lt;li&gt;one column must be the &amp;quot;Column Primary Key&amp;quot;&lt;/li&gt;&lt;li&gt;one column must be the &amp;quot;Display Value&amp;quot; of the Matrix&lt;/li&gt;
&lt;/ul&gt;
&lt;/ul&gt; &lt;br /&gt;Finally, once you have declared the &lt;b&gt;3 QueryBuilder variables&lt;/b&gt; you need, you can call &lt;b&gt;TheMatrix&lt;/b&gt; stored procedure.&lt;br /&gt; &lt;br /&gt; &lt;br /&gt;&lt;h1&gt;
More resources on SQL Server 2-D Matrix Builder
&lt;/h1&gt; &lt;br /&gt;An &lt;b&gt;french&lt;/b&gt; article is now available here: &lt;a href="http://msdn2.microsoft.com/fr-fr/sqlserver/cc197167.aspx" class="externalLink"&gt;The SQL Server 2-D Matrix Builder (http://msdn2.microsoft.com/fr-fr/sqlserver/cc197167.aspx)&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;This article will also be translated in &lt;b&gt;English&lt;/b&gt; very soon. Stay tuned!&lt;br /&gt;
&lt;/div&gt;</description><author>olymars</author><pubDate>Fri, 15 Feb 2008 09:10:28 GMT</pubDate><guid isPermaLink="false">UPDATED WIKI: Home 20080215091028A</guid></item><item><title>UPDATED WIKI: Home</title><link>http://www.codeplex.com/SQL2DMatrixBuilder/Wiki/View.aspx?title=Home&amp;version=39</link><description>&lt;div class="wikidoc"&gt;
&lt;h1&gt;
Introduction
&lt;/h1&gt; &lt;br /&gt;This project is all about bringing a &lt;b&gt;2-D matrix builder&lt;/b&gt; to &lt;b&gt;Microsoft SQL Server 2005&lt;/b&gt; (or later). So why do we need this? Consider the following schema:&lt;br /&gt; &lt;br /&gt;&lt;img src="http://www.codeplex.com/Project/Download/FileDownload.aspx?ProjectName=SQL2DMatrixBuilder&amp;amp;DownloadId=27479" alt="SQLMatrix1.png" /&gt;&lt;br /&gt; &lt;br /&gt;Now, what we would like to get as a &lt;b&gt;query result&lt;/b&gt; is the following :&lt;br /&gt; &lt;br /&gt;&lt;img src="http://www.codeplex.com/Project/Download/FileDownload.aspx?ProjectName=SQL2DMatrixBuilder&amp;amp;DownloadId=27480" alt="SQLMatrix2.png" /&gt;&lt;br /&gt; &lt;br /&gt;Notice that the headers are not &lt;i&gt;columns names&lt;/i&gt; but the &lt;b&gt;records&lt;/b&gt; available in the &lt;b&gt;Table_B&lt;/b&gt; table. So how do you get this natively with Microsoft SQL Server? Well, you can't! Unless you use the &lt;b&gt;SQL Server 2-D Matrix Builder&lt;/b&gt;.&lt;br /&gt; &lt;br /&gt;This project is all about using the &lt;b&gt;hosted .NET Common Langage Runtime&lt;/b&gt; in Microsoft SQL Server. All you have to do is uploading the &lt;b&gt;TheMatrixSqlClr.dll&lt;/b&gt; assembly into your SQL Server instance and use it. The next two chapters describe how to install this assembly into your SQL Server instance and how to reuse &lt;b&gt;TheMatrix&lt;/b&gt; stored procedure.&lt;br /&gt; &lt;br /&gt;This project was built by &lt;b&gt;Pascal Belaud&lt;/b&gt;, Developer Evangelist at &lt;b&gt;Microsoft France&lt;/b&gt; &lt;a href="http://blogs.msdn.com/Pascal" class="externalLink"&gt;French Blog (http://blogs.msdn.com/Pascal)&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;). Pascal is also the author of a &lt;b&gt;.NET code generator&lt;/b&gt; based on SQL Server 2005 called &lt;b&gt;OlyMars&lt;/b&gt; (&lt;a href="http://www.olymars.net" class="externalLink"&gt;http://www.olymars.net&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;).&lt;br /&gt; &lt;br /&gt; &lt;br /&gt;&lt;h1&gt;
Deployment
&lt;/h1&gt; &lt;br /&gt;&lt;pre&gt;
-- First you need to enable the use of .NET in your SLQ Server instance
exec sp_configure 'CLR Enabled', 1
reconfigure
GO
 
-- Since this assembly needs external access, your database needs to be TrustWorthy
Alter Database YourDatabase
Set Trustworthy On
GO
 
Use YourDatabase
GO
 
-- You need to deploy the assembly in your SQL Server instance
CREATE ASSEMBLY [TheSQLServerMatrix]
FROM '&amp;lt;Your path to the assembly here&amp;gt;\TheMatrixSqlClr.dll'
WITH PERMISSION_SET=EXTERNAL_ACCESS
GO
 
-- You need to declare a new User Defined Type
CREATE TYPE [QueryBuilder]
EXTERNAL NAME [TheSQLServerMatrix].[TheMatrixSqlClr.QueryBuilder]
GO
 
-- You need to declare a new stored procedure
CREATE PROCEDURE [TheMatrix]
  @rowsQuery [QueryBuilder]
, @rowsQuery_ValueMember nvarchar(max)
, @rowsQuery_DisplayMember nvarchar(max)
, @firstColumnHeader nvarchar(max)
, @columnsQuery [QueryBuilder]
, @columnsQuery_ValueMember nvarchar(max)
, @columnsQuery_DisplayMember nvarchar(max)
, @contentQuery [QueryBuilder]
, @contentQuery_ColumnValueMember nvarchar(max)
, @contentQuery_RowValueMember nvarchar(max)
, @contentQuery_DisplayName nvarchar(max)
, @contentQuery_MissingValue sql_variant
, @diagnose bit = 0
 
AS
EXTERNAL NAME [TheSQLServerMatrix].[TheMatrixSqlClr.StoredProcedures].[TheMatrix]
&lt;/pre&gt; &lt;br /&gt; &lt;br /&gt;&lt;h1&gt;
Usage
&lt;/h1&gt; &lt;br /&gt;Now that the assembly is declared in our instance, we can use &lt;b&gt;TheMatrix&lt;/b&gt; stored procedure like this:&lt;br /&gt; &lt;br /&gt;&lt;pre&gt;
-- Let's declare the first column rows
DECLARE @rowsQuery QueryBuilder
DECLARE @rowsQuery_ValueMember nvarchar(max)
DECLARE @rowsQuery_DisplayMember nvarchar(max)
SET @rowsQuery = QueryBuilder::New_QueryText('Select TableA_ID, TableA_Name From dbo.TableA Order by TableA_Name Asc')
SET @rowsQuery_ValueMember = 'TableA_ID'
SET @rowsQuery_DisplayMember = 'TableA_Name'
 
-- Let's declare the name of the first column header
DECLARE @firstColumnHeader nvarchar(max)
SET @firstColumnHeader = 'HEADER'
 
-- Let's declare the others columns headers
DECLARE @columnsQuery QueryBuilder
DECLARE @columnsQuery_ValueMember nvarchar(max)
DECLARE @columnsQuery_DisplayMember nvarchar(max)
SET @columnsQuery = QueryBuilder::New_QueryText('Select TableB_ID, TableB_Name From dbo.TableB Order By TableB_Name Asc')
SET @columnsQuery_ValueMember = 'TableB_ID'
SET @columnsQuery_DisplayMember = 'TableB_Name'
 
-- Let's declare how to fill the matrix content
DECLARE @contentQuery QueryBuilder
DECLARE @contentQuery_ColumnValueMember nvarchar(max)
DECLARE @contentQuery_RowValueMember nvarchar(max)
DECLARE @contentQuery_DisplayName nvarchar(max)
DECLARE @contentQuery_NullValue sql_variant
SET @contentQuery = QueryBuilder::New_StoredProcedure('spContent')
SET @contentQuery_ColumnValueMember = 'TableC_TableB_ID'
SET @contentQuery_RowValueMember = 'TableC_TableA_ID'
SET @contentQuery_DisplayName = 'TableC_Name'
SET @contentQuery_NullValue = '[NOT AVAILABLE]'
 
-- We want to see how the Matrix is going to execute all this
DECLARE @diagnose bit
SET @diagnose = 1
 
EXECUTE [TheMatrixDatabase].[dbo].[TheMatrix] 
   @rowsQuery
  ,@rowsQuery_ValueMember
  ,@rowsQuery_DisplayMember
  ,@firstColumnHeader
 
  ,@columnsQuery
  ,@columnsQuery_ValueMember
  ,@columnsQuery_DisplayMember
 
  ,@contentQuery
  ,@contentQuery_RowValueMember
  ,@contentQuery_ColumnValueMember
  ,@contentQuery_DisplayName
  ,@contentQuery_NullValue
  ,@diagnose
&lt;/pre&gt; &lt;br /&gt;When you execute this, you get the following resulset :&lt;br /&gt; &lt;br /&gt;&lt;table&gt;
&lt;tr&gt;
&lt;th&gt; HEADER &lt;/th&gt;&lt;th&gt; TableB_5 &lt;/th&gt;&lt;th&gt; TableB_6 &lt;/th&gt;&lt;th&gt; TableB_7 &lt;/th&gt;&lt;th&gt; TableB_8 &lt;/th&gt;&lt;th&gt; TableB_9 &lt;/th&gt;
&lt;/tr&gt;&lt;tr&gt;
&lt;td&gt; TableA_1 &lt;/td&gt;&lt;td&gt; TableC_1_5 &lt;/td&gt;&lt;td&gt; TableC_1_6 &lt;/td&gt;&lt;td&gt; TableC_1_7 &lt;/td&gt;&lt;td&gt; TableC_1_8 &lt;/td&gt;&lt;td&gt; TableC_1_9 &lt;/td&gt;
&lt;/tr&gt;&lt;tr&gt;
&lt;td&gt; TableA_2 &lt;/td&gt;&lt;td&gt; [NOT AVAILABLE] &lt;/td&gt;&lt;td&gt; TableC_2_6 &lt;/td&gt;&lt;td&gt; TableC_2_7 &lt;/td&gt;&lt;td&gt; TableC_2_8 &lt;/td&gt;&lt;td&gt; TableC_2_9 &lt;/td&gt;
&lt;/tr&gt;&lt;tr&gt;
&lt;td&gt; TableA_3 &lt;/td&gt;&lt;td&gt; TableC_3_5 &lt;/td&gt;&lt;td&gt; [NOT AVAILABLE] &lt;/td&gt;&lt;td&gt; TableC_3_7 &lt;/td&gt;&lt;td&gt; TableC_3_8 &lt;/td&gt;&lt;td&gt; TableC_3_9 &lt;/td&gt;
&lt;/tr&gt;&lt;tr&gt;
&lt;td&gt; TableA_4 &lt;/td&gt;&lt;td&gt; TableC_4_ &lt;/td&gt;&lt;td&gt; TableC_4_6 &lt;/td&gt;&lt;td&gt; TableC_4_7 &lt;/td&gt;&lt;td&gt; TableC_4_8 &lt;/td&gt;&lt;td&gt; TableC_4_9 &lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt; &lt;br /&gt; &lt;br /&gt;Notice that the Matrix allows you to call &lt;b&gt;literal SQL queries&lt;/b&gt; or &lt;b&gt;stored procedures&lt;/b&gt;. Those queries can also have input parameters if needed. &lt;br /&gt; &lt;br /&gt;In the previous example, the matrix content is filled with the resultset returned by the &lt;b&gt;spContent&lt;/b&gt; stored procedure:&lt;br /&gt; &lt;br /&gt;&lt;pre&gt;
Create Procedure [dbo].[spContent] As
 
Select TableC_TableA_ID, TableC_TableB_ID, TableC_Name From dbo.TableC
&lt;/pre&gt; &lt;br /&gt; &lt;br /&gt;Since we asked for diagnostic information, here is the output :&lt;br /&gt; &lt;br /&gt;&lt;pre&gt;
14/02/2008 11:22:08.46875- The SQL Server 2-D Matrix Builder
Starting TheMatrix call
 
14/02/2008 11:22:08.484375- Starting calling the Rows query
Query: Select TableA_ID, TableA_Name From dbo.TableA Order by TableA_Name Asc
	Is Stored Procedure: False
	Parameters number: 0
14/02/2008 11:22:08.484375- ValueMember index for [TableA_ID] is: 0
14/02/2008 11:22:08.484375- DisplayMember index for [TableA_Name] is: 1
14/02/2008 11:22:08.484375- Ending calling the Rows query
 
14/02/2008 11:22:08.484375- Starting calling the Columns query
Query: Select TableB_ID, TableB_Name From dbo.TableB Order By TableB_Name Asc
	Is Stored Procedure: False
	Parameters number: 0
14/02/2008 11:22:08.484375- ValueMember index for [TableB_ID] is: 0
14/02/2008 11:22:08.484375- DisplayMember index for [TableB_Name] is: 1
14/02/2008 11:22:08.484375- Ending calling the Columns query
 
14/02/2008 11:22:08.484375- Starting initializing the Matrix content
14/02/2008 11:22:08.484375- Ending initializing the Matrix content
 
14/02/2008 11:22:08.484375- Starting calling the Content query
Query: spContent
	Is Stored Procedure: True
	Parameters number: 0
14/02/2008 11:22:08.484375- ColumnValueMember index for [TableC_TableB_ID] is: 1
14/02/2008 11:22:08.484375- RowValueMember index for [TableC_TableA_ID] is: 0
14/02/2008 11:22:08.484375- DisplayMember index for [TableC_Name] is: 2
14/02/2008 11:22:08.484375- Ending calling the Content query
 
14/02/2008 11:22:08.484375- Starting SqlMetaData description
14/02/2008 11:22:08.484375- SqlMetaData, name='HEADER', sqlDbType='NVarChar', maxLength=8, precision=0, scale=0
14/02/2008 11:22:08.5- SqlMetaData, name='TableB_5', sqlDbType='NVarChar', maxLength=15, precision=0, scale=0
14/02/2008 11:22:08.5- SqlMetaData, name='TableB_6', sqlDbType='NVarChar', maxLength=15, precision=0, scale=0
14/02/2008 11:22:08.5- SqlMetaData, name='TableB_7', sqlDbType='NVarChar', maxLength=15, precision=0, scale=0
14/02/2008 11:22:08.5- SqlMetaData, name='TableB_8', sqlDbType='NVarChar', maxLength=15, precision=0, scale=0
14/02/2008 11:22:08.5- SqlMetaData, name='TableB_9', sqlDbType='NVarChar', maxLength=15, precision=0, scale=0
14/02/2008 11:22:08.5- Ending SqlMetaData description
 
14/02/2008 11:22:08.5- Starting sending back the resultset
 
(4 row(s) affected)
14/02/2008 11:22:08.5- Ending sending back the resultset
 
14/02/2008 11:22:08.5- Ending TheMatrix call...
&lt;/pre&gt; &lt;br /&gt; &lt;br /&gt;&lt;h1&gt;
Documentation
&lt;/h1&gt; &lt;br /&gt;&lt;img src="http://www.codeplex.com/Project/Download/FileDownload.aspx?ProjectName=SQL2DMatrixBuilder&amp;amp;DownloadId=27581" alt="SQLMatrix3.png" /&gt;&lt;br /&gt; &lt;br /&gt;The &lt;b&gt;QueryBuilder&lt;/b&gt; Used-Defined Type allows you to specify what query should be executed to fill:&lt;br /&gt; &lt;br /&gt;&lt;ul&gt;
&lt;li&gt;The first column rows (Query 1)&lt;/li&gt;&lt;li&gt;The columns headers (Query 2)&lt;/li&gt;&lt;li&gt;The Matrix content (Query 3)&lt;/li&gt;
&lt;/ul&gt; &lt;br /&gt;&lt;img src="http://www.codeplex.com/Project/Download/FileDownload.aspx?ProjectName=SQL2DMatrixBuilder&amp;amp;DownloadId=27574" alt="QueryBuilder.png" /&gt;&lt;br /&gt; &lt;br /&gt; &lt;br /&gt;Once you have declared a variable of this type, you can invoke any of its static methods using the &lt;b&gt;::&lt;/b&gt; operator. If you intend to call a literal SQL query, use the &lt;b&gt;New_QueryText&lt;/b&gt; method. If you plan to use a stored procedure instead, use the &lt;b&gt;New_StoredProcedure&lt;/b&gt; method.&lt;br /&gt; &lt;br /&gt;&lt;pre&gt;
-- If you are using a literal SQL query
Declare @MyLiteralSQLQueryBuilder QueryBuilder
Set @MyLiteralSQLQueryBuilder::New_QueryText(N'Select MyColumn1, MyColumn2, MyColumn3 From MyTable1 Inner Join... Where MyColumn4 = @MyParameter')
&lt;/pre&gt; &lt;br /&gt;&lt;pre&gt;
-- If you are using a stored procedure
Declare @MyStoredProcedureQueryBuilder QueryBuilder
Set @MyStoredProcedureQueryBuilder::New_QueryText(N'MyStoredProcedureName')
&lt;/pre&gt; &lt;br /&gt;If your literal SQL query or your stored procedure need some input parameters, you can supply their values by calling the &lt;b&gt;SetParameter&lt;/b&gt; method:&lt;br /&gt; &lt;br /&gt;&lt;pre&gt;
Declare @Value [your type here]
Set @MyLiteralSQLQueryBuilder::SetParameter(N'@MyParameter', @Value)
&lt;/pre&gt; &lt;br /&gt;&lt;pre&gt;
Declare @Value [your type here]
Set @MyStoredProcedureQueryBuilder::SetParameter(N'@MyParameter', @Value)
&lt;/pre&gt; &lt;br /&gt;For the &lt;b&gt;Matrix content&lt;/b&gt; query only, we need to infere the &lt;b&gt;type&lt;/b&gt; of the columns that are returned in the &lt;b&gt;resultset&lt;/b&gt;. Although, this product tries to infere this type, it might not be suitable in all cases. Therefore, you can help infere this type by calling one of the following method:&lt;br /&gt; &lt;br /&gt;&lt;ul&gt;
&lt;ul&gt;
&lt;li&gt;SetContentType(typeName)&lt;/li&gt;&lt;li&gt;SetContentType2(typeName, maxLength)&lt;/li&gt;&lt;li&gt;SetContentType3(typeName, precision, scale)&lt;/li&gt;
&lt;/ul&gt;
&lt;/ul&gt; &lt;br /&gt;&lt;b&gt;typeName&lt;/b&gt; must be one of the &lt;b&gt;System.Data.SqlDbType&lt;/b&gt; enumeration value:&lt;br /&gt; &lt;br /&gt;&lt;img src="http://www.codeplex.com/Project/Download/FileDownload.aspx?ProjectName=SQL2DMatrixBuilder&amp;amp;DownloadId=27576" alt="SqlDbType.png" /&gt;&lt;br /&gt; &lt;br /&gt;Finally, once you have declared the &lt;b&gt;3 QueryBuilder variables&lt;/b&gt; you need, you can call &lt;b&gt;TheMatrix&lt;/b&gt; stored procedure:&lt;br /&gt; &lt;br /&gt; &lt;br /&gt;&lt;h1&gt;
More resources on SQL Server 2-D Matrix Builder
&lt;/h1&gt; &lt;br /&gt;An &lt;b&gt;french&lt;/b&gt; article is now available here: &lt;a href="http://msdn2.microsoft.com/fr-fr/sqlserver/cc197167.aspx" class="externalLink"&gt;The SQL Server 2-D Matrix Builder (http://msdn2.microsoft.com/fr-fr/sqlserver/cc197167.aspx)&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;This article will also be translated in &lt;b&gt;English&lt;/b&gt; very soon. Stay tuned!&lt;br /&gt;
&lt;/div&gt;</description><author>olymars</author><pubDate>Fri, 15 Feb 2008 09:02:34 GMT</pubDate><guid isPermaLink="false">UPDATED WIKI: Home 20080215090234A</guid></item><item><title>UPDATED WIKI: Home</title><link>http://www.codeplex.com/SQL2DMatrixBuilder/Wiki/View.aspx?title=Home&amp;version=38</link><description>&lt;div class="wikidoc"&gt;
&lt;h1&gt;
Introduction
&lt;/h1&gt; &lt;br /&gt;This project is all about bringing a &lt;b&gt;2-D matrix builder&lt;/b&gt; to &lt;b&gt;Microsoft SQL Server 2005&lt;/b&gt; (or later). So why do we need this? Consider the following schema:&lt;br /&gt; &lt;br /&gt;&lt;img src="http://www.codeplex.com/Project/Download/FileDownload.aspx?ProjectName=SQL2DMatrixBuilder&amp;amp;DownloadId=27479" alt="SQLMatrix1.png" /&gt;&lt;br /&gt; &lt;br /&gt;Now, what we would like to get as a &lt;b&gt;query result&lt;/b&gt; is the following :&lt;br /&gt; &lt;br /&gt;&lt;img src="http://www.codeplex.com/Project/Download/FileDownload.aspx?ProjectName=SQL2DMatrixBuilder&amp;amp;DownloadId=27480" alt="SQLMatrix2.png" /&gt;&lt;br /&gt; &lt;br /&gt;Notice that the headers are not &lt;i&gt;columns names&lt;/i&gt; but the &lt;b&gt;records&lt;/b&gt; available in the &lt;b&gt;Table_B&lt;/b&gt; table. So how do you get this natively with Microsoft SQL Server? Well, you can't! Unless you use the &lt;b&gt;SQL Server 2-D Matrix Builder&lt;/b&gt;.&lt;br /&gt; &lt;br /&gt;This project is all about using the &lt;b&gt;hosted .NET Common Langage Runtime&lt;/b&gt; in Microsoft SQL Server. All you have to do is uploading the &lt;b&gt;TheMatrixSqlClr.dll&lt;/b&gt; assembly into your SQL Server instance and use it. The next two chapters describe how to install this assembly into your SQL Server instance and how to reuse &lt;b&gt;TheMatrix&lt;/b&gt; stored procedure.&lt;br /&gt; &lt;br /&gt;This project was built by &lt;b&gt;Pascal Belaud&lt;/b&gt;, Developer Evangelist at &lt;b&gt;Microsoft France&lt;/b&gt; &lt;a href="http://blogs.msdn.com/Pascal" class="externalLink"&gt;French Blog (http://blogs.msdn.com/Pascal)&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;). Pascal is also the author of a &lt;b&gt;.NET code generator&lt;/b&gt; based on SQL Server 2005 called &lt;b&gt;OlyMars&lt;/b&gt; (&lt;a href="http://www.olymars.net" class="externalLink"&gt;http://www.olymars.net&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;).&lt;br /&gt; &lt;br /&gt; &lt;br /&gt;&lt;h1&gt;
Deployment
&lt;/h1&gt; &lt;br /&gt;&lt;pre&gt;
-- First you need to enable the use of .NET in your SLQ Server instance
exec sp_configure 'CLR Enabled', 1
reconfigure
GO
 
-- Since this assembly needs external access, your database needs to be TrustWorthy
Alter Database YourDatabase
Set Trustworthy On
GO
 
Use YourDatabase
GO
 
-- You need to deploy the assembly in your SQL Server instance
CREATE ASSEMBLY [TheSQLServerMatrix]
FROM '&amp;lt;Your path to the assembly here&amp;gt;\TheMatrixSqlClr.dll'
WITH PERMISSION_SET=EXTERNAL_ACCESS
GO
 
-- You need to declare a new User Defined Type
CREATE TYPE [QueryBuilder]
EXTERNAL NAME [TheSQLServerMatrix].[TheMatrixSqlClr.QueryBuilder]
GO
 
-- You need to declare a new stored procedure
CREATE PROCEDURE [TheMatrix]
  @rowsQuery [QueryBuilder]
, @rowsQuery_ValueMember nvarchar(max)
, @rowsQuery_DisplayMember nvarchar(max)
, @firstColumnHeader nvarchar(max)
, @columnsQuery [QueryBuilder]
, @columnsQuery_ValueMember nvarchar(max)
, @columnsQuery_DisplayMember nvarchar(max)
, @contentQuery [QueryBuilder]
, @contentQuery_ColumnValueMember nvarchar(max)
, @contentQuery_RowValueMember nvarchar(max)
, @contentQuery_DisplayName nvarchar(max)
, @contentQuery_MissingValue sql_variant
, @diagnose bit = 0
 
AS
EXTERNAL NAME [TheSQLServerMatrix].[TheMatrixSqlClr.StoredProcedures].[TheMatrix]
&lt;/pre&gt; &lt;br /&gt; &lt;br /&gt;&lt;h1&gt;
Usage
&lt;/h1&gt; &lt;br /&gt;Now that the assembly is declared in our instance, we can use &lt;b&gt;TheMatrix&lt;/b&gt; stored procedure like this:&lt;br /&gt; &lt;br /&gt;&lt;pre&gt;
-- Let's declare the first column rows
DECLARE @rowsQuery QueryBuilder
DECLARE @rowsQuery_ValueMember nvarchar(max)
DECLARE @rowsQuery_DisplayMember nvarchar(max)
SET @rowsQuery = QueryBuilder::New_QueryText('Select TableA_ID, TableA_Name From dbo.TableA Order by TableA_Name Asc')
SET @rowsQuery_ValueMember = 'TableA_ID'
SET @rowsQuery_DisplayMember = 'TableA_Name'
 
-- Let's declare the name of the first column header
DECLARE @firstColumnHeader nvarchar(max)
SET @firstColumnHeader = 'HEADER'
 
-- Let's declare the others columns headers
DECLARE @columnsQuery QueryBuilder
DECLARE @columnsQuery_ValueMember nvarchar(max)
DECLARE @columnsQuery_DisplayMember nvarchar(max)
SET @columnsQuery = QueryBuilder::New_QueryText('Select TableB_ID, TableB_Name From dbo.TableB Order By TableB_Name Asc')
SET @columnsQuery_ValueMember = 'TableB_ID'
SET @columnsQuery_DisplayMember = 'TableB_Name'
 
-- Let's declare how to fill the matrix content
DECLARE @contentQuery QueryBuilder
DECLARE @contentQuery_ColumnValueMember nvarchar(max)
DECLARE @contentQuery_RowValueMember nvarchar(max)
DECLARE @contentQuery_DisplayName nvarchar(max)
DECLARE @contentQuery_NullValue sql_variant
SET @contentQuery = QueryBuilder::New_StoredProcedure('spContent')
SET @contentQuery_ColumnValueMember = 'TableC_TableB_ID'
SET @contentQuery_RowValueMember = 'TableC_TableA_ID'
SET @contentQuery_DisplayName = 'TableC_Name'
SET @contentQuery_NullValue = '[NOT AVAILABLE]'
 
-- We want to see how the Matrix is going to execute all this
DECLARE @diagnose bit
SET @diagnose = 1
 
EXECUTE [TheMatrixDatabase].[dbo].[TheMatrix] 
   @rowsQuery
  ,@rowsQuery_ValueMember
  ,@rowsQuery_DisplayMember
  ,@firstColumnHeader
 
  ,@columnsQuery
  ,@columnsQuery_ValueMember
  ,@columnsQuery_DisplayMember
 
  ,@contentQuery
  ,@contentQuery_RowValueMember
  ,@contentQuery_ColumnValueMember
  ,@contentQuery_DisplayName
  ,@contentQuery_NullValue
  ,@diagnose
&lt;/pre&gt; &lt;br /&gt;When you execute this, you get the following resulset :&lt;br /&gt; &lt;br /&gt;&lt;table&gt;
&lt;tr&gt;
&lt;th&gt; HEADER &lt;/th&gt;&lt;th&gt; TableB_5 &lt;/th&gt;&lt;th&gt; TableB_6 &lt;/th&gt;&lt;th&gt; TableB_7 &lt;/th&gt;&lt;th&gt; TableB_8 &lt;/th&gt;&lt;th&gt; TableB_9 &lt;/th&gt;
&lt;/tr&gt;&lt;tr&gt;
&lt;td&gt; TableA_1 &lt;/td&gt;&lt;td&gt; TableC_1_5 &lt;/td&gt;&lt;td&gt; TableC_1_6 &lt;/td&gt;&lt;td&gt; TableC_1_7 &lt;/td&gt;&lt;td&gt; TableC_1_8 &lt;/td&gt;&lt;td&gt; TableC_1_9 &lt;/td&gt;
&lt;/tr&gt;&lt;tr&gt;
&lt;td&gt; TableA_2 &lt;/td&gt;&lt;td&gt; [NOT AVAILABLE] &lt;/td&gt;&lt;td&gt; TableC_2_6 &lt;/td&gt;&lt;td&gt; TableC_2_7 &lt;/td&gt;&lt;td&gt; TableC_2_8 &lt;/td&gt;&lt;td&gt; TableC_2_9 &lt;/td&gt;
&lt;/tr&gt;&lt;tr&gt;
&lt;td&gt; TableA_3 &lt;/td&gt;&lt;td&gt; TableC_3_5 &lt;/td&gt;&lt;td&gt; [NOT AVAILABLE] &lt;/td&gt;&lt;td&gt; TableC_3_7 &lt;/td&gt;&lt;td&gt; TableC_3_8 &lt;/td&gt;&lt;td&gt; TableC_3_9 &lt;/td&gt;
&lt;/tr&gt;&lt;tr&gt;
&lt;td&gt; TableA_4 &lt;/td&gt;&lt;td&gt; TableC_4_ &lt;/td&gt;&lt;td&gt; TableC_4_6 &lt;/td&gt;&lt;td&gt; TableC_4_7 &lt;/td&gt;&lt;td&gt; TableC_4_8 &lt;/td&gt;&lt;td&gt; TableC_4_9 &lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt; &lt;br /&gt; &lt;br /&gt;Notice that the Matrix allows you to call &lt;b&gt;literal SQL queries&lt;/b&gt; or &lt;b&gt;stored procedures&lt;/b&gt;. Those queries can also have input parameters if needed. &lt;br /&gt; &lt;br /&gt;In the previous example, the matrix content is filled with the resultset returned by the &lt;b&gt;spContent&lt;/b&gt; stored procedure:&lt;br /&gt; &lt;br /&gt;&lt;pre&gt;
Create Procedure [dbo].[spContent] As
 
Select TableC_TableA_ID, TableC_TableB_ID, TableC_Name From dbo.TableC
&lt;/pre&gt; &lt;br /&gt; &lt;br /&gt;Since we asked for diagnostic information, here is the output :&lt;br /&gt; &lt;br /&gt;&lt;pre&gt;
14/02/2008 11:22:08.46875- The SQL Server 2-D Matrix Builder
Starting TheMatrix call
 
14/02/2008 11:22:08.484375- Starting calling the Rows query
Query: Select TableA_ID, TableA_Name From dbo.TableA Order by TableA_Name Asc
	Is Stored Procedure: False
	Parameters number: 0
14/02/2008 11:22:08.484375- ValueMember index for [TableA_ID] is: 0
14/02/2008 11:22:08.484375- DisplayMember index for [TableA_Name] is: 1
14/02/2008 11:22:08.484375- Ending calling the Rows query
 
14/02/2008 11:22:08.484375- Starting calling the Columns query
Query: Select TableB_ID, TableB_Name From dbo.TableB Order By TableB_Name Asc
	Is Stored Procedure: False
	Parameters number: 0
14/02/2008 11:22:08.484375- ValueMember index for [TableB_ID] is: 0
14/02/2008 11:22:08.484375- DisplayMember index for [TableB_Name] is: 1
14/02/2008 11:22:08.484375- Ending calling the Columns query
 
14/02/2008 11:22:08.484375- Starting initializing the Matrix content
14/02/2008 11:22:08.484375- Ending initializing the Matrix content
 
14/02/2008 11:22:08.484375- Starting calling the Content query
Query: spContent
	Is Stored Procedure: True
	Parameters number: 0
14/02/2008 11:22:08.484375- ColumnValueMember index for [TableC_TableB_ID] is: 1
14/02/2008 11:22:08.484375- RowValueMember index for [TableC_TableA_ID] is: 0
14/02/2008 11:22:08.484375- DisplayMember index for [TableC_Name] is: 2
14/02/2008 11:22:08.484375- Ending calling the Content query
 
14/02/2008 11:22:08.484375- Starting SqlMetaData description
14/02/2008 11:22:08.484375- SqlMetaData, name='HEADER', sqlDbType='NVarChar', maxLength=8, precision=0, scale=0
14/02/2008 11:22:08.5- SqlMetaData, name='TableB_5', sqlDbType='NVarChar', maxLength=15, precision=0, scale=0
14/02/2008 11:22:08.5- SqlMetaData, name='TableB_6', sqlDbType='NVarChar', maxLength=15, precision=0, scale=0
14/02/2008 11:22:08.5- SqlMetaData, name='TableB_7', sqlDbType='NVarChar', maxLength=15, precision=0, scale=0
14/02/2008 11:22:08.5- SqlMetaData, name='TableB_8', sqlDbType='NVarChar', maxLength=15, precision=0, scale=0
14/02/2008 11:22:08.5- SqlMetaData, name='TableB_9', sqlDbType='NVarChar', maxLength=15, precision=0, scale=0
14/02/2008 11:22:08.5- Ending SqlMetaData description
 
14/02/2008 11:22:08.5- Starting sending back the resultset
 
(4 row(s) affected)
14/02/2008 11:22:08.5- Ending sending back the resultset
 
14/02/2008 11:22:08.5- Ending TheMatrix call...
&lt;/pre&gt; &lt;br /&gt; &lt;br /&gt;&lt;h1&gt;
Documentation
&lt;/h1&gt; &lt;br /&gt;The &lt;b&gt;QueryBuilder&lt;/b&gt; Used-Defined Type allows you to specify what query should be executed to fill:&lt;br /&gt; &lt;br /&gt;&lt;ul&gt;
&lt;li&gt;The firt column rows&lt;/li&gt;&lt;li&gt;The columns headers&lt;/li&gt;&lt;li&gt;The Matrix content&lt;/li&gt;
&lt;/ul&gt; &lt;br /&gt;&lt;img src="http://www.codeplex.com/Project/Download/FileDownload.aspx?ProjectName=SQL2DMatrixBuilder&amp;amp;DownloadId=27574" alt="QueryBuilder.png" /&gt;&lt;br /&gt; &lt;br /&gt; &lt;br /&gt;Once you have declared a variable of this type, you can invoke any of its static methods using the &lt;b&gt;::&lt;/b&gt; operator. If you intend to call a literal SQL query, use the &lt;b&gt;New_QueryText&lt;/b&gt; method. If you plan to use a stored procedure instead, use the &lt;b&gt;New_StoredProcedure&lt;/b&gt; method.&lt;br /&gt; &lt;br /&gt;&lt;pre&gt;
-- If you are using a literal SQL query
Declare @MyLiteralSQLQueryBuilder QueryBuilder
Set @MyLiteralSQLQueryBuilder::New_QueryText(N'Select MyColumn1, MyColumn2, MyColumn3 From MyTable1 Inner Join... Where MyColumn4 = @MyParameter')
&lt;/pre&gt; &lt;br /&gt;&lt;pre&gt;
-- If you are using a stored procedure
Declare @MyStoredProcedureQueryBuilder QueryBuilder
Set @MyStoredProcedureQueryBuilder::New_QueryText(N'MyStoredProcedureName')
&lt;/pre&gt; &lt;br /&gt;If your literal SQL query or your stored procedure need some input parameters, you can supply their values by calling the &lt;b&gt;SetParameter&lt;/b&gt; method:&lt;br /&gt; &lt;br /&gt;&lt;pre&gt;
Declare @Value [your type here]
Set @MyLiteralSQLQueryBuilder::SetParameter(N'@MyParameter', @Value)
&lt;/pre&gt; &lt;br /&gt;&lt;pre&gt;
Declare @Value [your type here]
Set @MyStoredProcedureQueryBuilder::SetParameter(N'@MyParameter', @Value)
&lt;/pre&gt; &lt;br /&gt;For the &lt;b&gt;Matrix content&lt;/b&gt; query only, we need to infere the &lt;b&gt;type&lt;/b&gt; of the columns that are returned in the &lt;b&gt;resultset&lt;/b&gt;. Although, this product tries to infere this type, it might not be suitable in all cases. Therefore, you can help infere this type by calling one of the following method:&lt;br /&gt; &lt;br /&gt;&lt;ul&gt;
&lt;ul&gt;
&lt;li&gt;SetContentType(typeName)&lt;/li&gt;&lt;li&gt;SetContentType2(typeName, maxLength)&lt;/li&gt;&lt;li&gt;SetContentType3(typeName, precision, scale)&lt;/li&gt;
&lt;/ul&gt;
&lt;/ul&gt; &lt;br /&gt;&lt;b&gt;typeName&lt;/b&gt; must be one of the &lt;b&gt;System.Data.SqlDbType&lt;/b&gt; enumeration value:&lt;br /&gt; &lt;br /&gt;&lt;img src="http://www.codeplex.com/Project/Download/FileDownload.aspx?ProjectName=SQL2DMatrixBuilder&amp;amp;DownloadId=27576" alt="SqlDbType.png" /&gt;&lt;br /&gt; &lt;br /&gt;Finally, once you have declared the &lt;b&gt;3 QueryBuilder variables&lt;/b&gt; you need, you can call &lt;b&gt;TheMatrix&lt;/b&gt; stored procedure:&lt;br /&gt; &lt;br /&gt; &lt;br /&gt;&lt;h1&gt;
More resources on SQL Server 2-D Matrix Builder
&lt;/h1&gt; &lt;br /&gt;An &lt;b&gt;french&lt;/b&gt; article is now available here: &lt;a href="http://msdn2.microsoft.com/fr-fr/sqlserver/cc197167.aspx" class="externalLink"&gt;The SQL Server 2-D Matrix Builder (http://msdn2.microsoft.com/fr-fr/sqlserver/cc197167.aspx)&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;This article will also be translated in &lt;b&gt;English&lt;/b&gt; very soon. Stay tuned!&lt;br /&gt;
&lt;/div&gt;</description><author>olymars</author><pubDate>Fri, 15 Feb 2008 08:53:29 GMT</pubDate><guid isPermaLink="false">UPDATED WIKI: Home 20080215085329A</guid></item><item><title>UPDATED WIKI: Home</title><link>http://www.codeplex.com/SQL2DMatrixBuilder/Wiki/View.aspx?title=Home&amp;version=37</link><description>&lt;div class="wikidoc"&gt;
&lt;h1&gt;
Introduction
&lt;/h1&gt; &lt;br /&gt;This project is all about bringing a &lt;b&gt;2-D matrix builder&lt;/b&gt; to &lt;b&gt;Microsoft SQL Server 2005&lt;/b&gt; (or later). So why do we need this? Consider the following schema:&lt;br /&gt; &lt;br /&gt;&lt;img src="http://www.codeplex.com/Project/Download/FileDownload.aspx?ProjectName=SQL2DMatrixBuilder&amp;amp;DownloadId=27479" alt="SQLMatrix1.png" /&gt;&lt;br /&gt; &lt;br /&gt;Now, what we would like to get as a &lt;b&gt;query result&lt;/b&gt; is the following :&lt;br /&gt; &lt;br /&gt;&lt;img src="http://www.codeplex.com/Project/Download/FileDownload.aspx?ProjectName=SQL2DMatrixBuilder&amp;amp;DownloadId=27480" alt="SQLMatrix2.png" /&gt;&lt;br /&gt; &lt;br /&gt;Notice that the headers are not &lt;i&gt;columns names&lt;/i&gt; but the &lt;b&gt;records&lt;/b&gt; available in the &lt;b&gt;Table_B&lt;/b&gt; table. So how do you get this natively with Microsoft SQL Server? Well, you can't! Unless you use the &lt;b&gt;SQL Server 2-D Matrix Builder&lt;/b&gt;.&lt;br /&gt; &lt;br /&gt;This project is all about using the &lt;b&gt;hosted .NET Common Langage Runtime&lt;/b&gt; in Microsoft SQL Server. All you have to do is uploading the &lt;b&gt;TheMatrixSqlClr.dll&lt;/b&gt; assembly into your SQL Server instance and use it. The next two chapters describe how to install this assembly into your SQL Server instance and how to reuse &lt;b&gt;TheMatrix&lt;/b&gt; stored procedure.&lt;br /&gt; &lt;br /&gt;This project was built by &lt;b&gt;Pascal Belaud&lt;/b&gt;, Developer Evangelist at &lt;b&gt;Microsoft France&lt;/b&gt; &lt;a href="http://blogs.msdn.com/Pascal" class="externalLink"&gt;French Blog (http://blogs.msdn.com/Pascal)&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;). Pascal is also the author of a &lt;b&gt;.NET code generator&lt;/b&gt; based on SQL Server 2005 called &lt;b&gt;OlyMars&lt;/b&gt; (&lt;a href="http://www.olymars.net" class="externalLink"&gt;http://www.olymars.net&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;).&lt;br /&gt; &lt;br /&gt; &lt;br /&gt;&lt;h1&gt;
Deployment
&lt;/h1&gt; &lt;br /&gt;&lt;pre&gt;
-- First you need to enable the use of .NET in your SLQ Server instance
exec sp_configure 'CLR Enabled', 1
reconfigure
GO
 
-- Since this assembly needs external access, your database needs to be TrustWorthy
Alter Database YourDatabase
Set Trustworthy On
GO
 
Use YourDatabase
GO
 
-- You need to deploy the assembly in your SQL Server instance
CREATE ASSEMBLY [TheSQLServerMatrix]
FROM '&amp;lt;Your path to the assembly here&amp;gt;\TheMatrixSqlClr.dll'
WITH PERMISSION_SET=EXTERNAL_ACCESS
GO
 
-- You need to declare a new User Defined Type
CREATE TYPE [QueryBuilder]
EXTERNAL NAME [TheSQLServerMatrix].[TheMatrixSqlClr.QueryBuilder]
GO
 
-- You need to declare a new stored procedure
CREATE PROCEDURE [TheMatrix]
  @rowsQuery [QueryBuilder]
, @rowsQuery_ValueMember nvarchar(max)
, @rowsQuery_DisplayMember nvarchar(max)
, @firstColumnHeader nvarchar(max)
, @columnsQuery [QueryBuilder]
, @columnsQuery_ValueMember nvarchar(max)
, @columnsQuery_DisplayMember nvarchar(max)
, @contentQuery [QueryBuilder]
, @contentQuery_ColumnValueMember nvarchar(max)
, @contentQuery_RowValueMember nvarchar(max)
, @contentQuery_DisplayName nvarchar(max)
, @contentQuery_MissingValue sql_variant
, @diagnose bit = 0
 
AS
EXTERNAL NAME [TheSQLServerMatrix].[TheMatrixSqlClr.StoredProcedures].[TheMatrix]
&lt;/pre&gt; &lt;br /&gt; &lt;br /&gt;&lt;h1&gt;
Usage
&lt;/h1&gt; &lt;br /&gt;Now that the assembly is declared in our instance, we can use &lt;b&gt;TheMatrix&lt;/b&gt; stored procedure like this:&lt;br /&gt; &lt;br /&gt;&lt;pre&gt;
-- Let's declare the first column rows
DECLARE @rowsQuery QueryBuilder
DECLARE @rowsQuery_ValueMember nvarchar(max)
DECLARE @rowsQuery_DisplayMember nvarchar(max)
SET @rowsQuery = QueryBuilder::New_QueryText('Select TableA_ID, TableA_Name From dbo.TableA Order by TableA_Name Asc')
SET @rowsQuery_ValueMember = 'TableA_ID'
SET @rowsQuery_DisplayMember = 'TableA_Name'
 
-- Let's declare the name of the first column header
DECLARE @firstColumnHeader nvarchar(max)
SET @firstColumnHeader = 'HEADER'
 
-- Let's declare the others columns headers
DECLARE @columnsQuery QueryBuilder
DECLARE @columnsQuery_ValueMember nvarchar(max)
DECLARE @columnsQuery_DisplayMember nvarchar(max)
SET @columnsQuery = QueryBuilder::New_QueryText('Select TableB_ID, TableB_Name From dbo.TableB Order By TableB_Name Asc')
SET @columnsQuery_ValueMember = 'TableB_ID'
SET @columnsQuery_DisplayMember = 'TableB_Name'
 
-- Let's declare how to fill the matrix content
DECLARE @contentQuery QueryBuilder
DECLARE @contentQuery_ColumnValueMember nvarchar(max)
DECLARE @contentQuery_RowValueMember nvarchar(max)
DECLARE @contentQuery_DisplayName nvarchar(max)
DECLARE @contentQuery_NullValue sql_variant
SET @contentQuery = QueryBuilder::New_StoredProcedure('spContent')
SET @contentQuery_ColumnValueMember = 'TableC_TableB_ID'
SET @contentQuery_RowValueMember = 'TableC_TableA_ID'
SET @contentQuery_DisplayName = 'TableC_Name'
SET @contentQuery_NullValue = '[NOT AVAILABLE]'
 
-- We want to see how the Matrix is going to execute all this
DECLARE @diagnose bit
SET @diagnose = 1
 
EXECUTE [TheMatrixDatabase].[dbo].[TheMatrix] 
   @rowsQuery
  ,@rowsQuery_ValueMember
  ,@rowsQuery_DisplayMember
  ,@firstColumnHeader
 
  ,@columnsQuery
  ,@columnsQuery_ValueMember
  ,@columnsQuery_DisplayMember
 
  ,@contentQuery
  ,@contentQuery_RowValueMember
  ,@contentQuery_ColumnValueMember
  ,@contentQuery_DisplayName
  ,@contentQuery_NullValue
  ,@diagnose
&lt;/pre&gt; &lt;br /&gt;When you execute this, you get the following resulset :&lt;br /&gt; &lt;br /&gt;&lt;table&gt;
&lt;tr&gt;
&lt;th&gt; HEADER &lt;/th&gt;&lt;th&gt; TableB_5 &lt;/th&gt;&lt;th&gt; TableB_6 &lt;/th&gt;&lt;th&gt; TableB_7 &lt;/th&gt;&lt;th&gt; TableB_8 &lt;/th&gt;&lt;th&gt; TableB_9 &lt;/th&gt;
&lt;/tr&gt;&lt;tr&gt;
&lt;td&gt; TableA_1 &lt;/td&gt;&lt;td&gt; TableC_1_5 &lt;/td&gt;&lt;td&gt; TableC_1_6 &lt;/td&gt;&lt;td&gt; TableC_1_7 &lt;/td&gt;&lt;td&gt; TableC_1_8 &lt;/td&gt;&lt;td&gt; TableC_1_9 &lt;/td&gt;
&lt;/tr&gt;&lt;tr&gt;
&lt;td&gt; TableA_2 &lt;/td&gt;&lt;td&gt; [NOT AVAILABLE] &lt;/td&gt;&lt;td&gt; TableC_2_6 &lt;/td&gt;&lt;td&gt; TableC_2_7 &lt;/td&gt;&lt;td&gt; TableC_2_8 &lt;/td&gt;&lt;td&gt; TableC_2_9 &lt;/td&gt;
&lt;/tr&gt;&lt;tr&gt;
&lt;td&gt; TableA_3 &lt;/td&gt;&lt;td&gt; TableC_3_5 &lt;/td&gt;&lt;td&gt; [NOT AVAILABLE] &lt;/td&gt;&lt;td&gt; TableC_3_7 &lt;/td&gt;&lt;td&gt; TableC_3_8 &lt;/td&gt;&lt;td&gt; TableC_3_9 &lt;/td&gt;
&lt;/tr&gt;&lt;tr&gt;
&lt;td&gt; TableA_4 &lt;/td&gt;&lt;td&gt; TableC_4_ &lt;/td&gt;&lt;td&gt; TableC_4_6 &lt;/td&gt;&lt;td&gt; TableC_4_7 &lt;/td&gt;&lt;td&gt; TableC_4_8 &lt;/td&gt;&lt;td&gt; TableC_4_9 &lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt; &lt;br /&gt; &lt;br /&gt;Notice that the Matrix allows you to call &lt;b&gt;literal SQL queries&lt;/b&gt; or &lt;b&gt;stored procedures&lt;/b&gt;. Those queries can also have input parameters if needed. &lt;br /&gt; &lt;br /&gt;In the previous example, the matrix content is filled with the resultset returned by the &lt;b&gt;spContent&lt;/b&gt; stored procedure:&lt;br /&gt; &lt;br /&gt;&lt;pre&gt;
Create Procedure [dbo].[spContent] As
 
Select TableC_TableA_ID, TableC_TableB_ID, TableC_Name From dbo.TableC
&lt;/pre&gt; &lt;br /&gt; &lt;br /&gt;Since we asked for diagnostic information, here is the output :&lt;br /&gt; &lt;br /&gt;&lt;pre&gt;
14/02/2008 11:22:08.46875- The SQL Server 2-D Matrix Builder
Starting TheMatrix call
 
14/02/2008 11:22:08.484375- Starting calling the Rows query
Query: Select TableA_ID, TableA_Name From dbo.TableA Order by TableA_Name Asc
	Is Stored Procedure: False
	Parameters number: 0
14/02/2008 11:22:08.484375- ValueMember index for [TableA_ID] is: 0
14/02/2008 11:22:08.484375- DisplayMember index for [TableA_Name] is: 1
14/02/2008 11:22:08.484375- Ending calling the Rows query
 
14/02/2008 11:22:08.484375- Starting calling the Columns query
Query: Select TableB_ID, TableB_Name From dbo.TableB Order By TableB_Name Asc
	Is Stored Procedure: False
	Parameters number: 0
14/02/2008 11:22:08.484375- ValueMember index for [TableB_ID] is: 0
14/02/2008 11:22:08.484375- DisplayMember index for [TableB_Name] is: 1
14/02/2008 11:22:08.484375- Ending calling the Columns query
 
14/02/2008 11:22:08.484375- Starting initializing the Matrix content
14/02/2008 11:22:08.484375- Ending initializing the Matrix content
 
14/02/2008 11:22:08.484375- Starting calling the Content query
Query: spContent
	Is Stored Procedure: True
	Parameters number: 0
14/02/2008 11:22:08.484375- ColumnValueMember index for [TableC_TableB_ID] is: 1
14/02/2008 11:22:08.484375- RowValueMember index for [TableC_TableA_ID] is: 0
14/02/2008 11:22:08.484375- DisplayMember index for [TableC_Name] is: 2
14/02/2008 11:22:08.484375- Ending calling the Content query
 
14/02/2008 11:22:08.484375- Starting SqlMetaData description
14/02/2008 11:22:08.484375- SqlMetaData, name='HEADER', sqlDbType='NVarChar', maxLength=8, precision=0, scale=0
14/02/2008 11:22:08.5- SqlMetaData, name='TableB_5', sqlDbType='NVarChar', maxLength=15, precision=0, scale=0
14/02/2008 11:22:08.5- SqlMetaData, name='TableB_6', sqlDbType='NVarChar', maxLength=15, precision=0, scale=0
14/02/2008 11:22:08.5- SqlMetaData, name='TableB_7', sqlDbType='NVarChar', maxLength=15, precision=0, scale=0
14/02/2008 11:22:08.5- SqlMetaData, name='TableB_8', sqlDbType='NVarChar', maxLength=15, precision=0, scale=0
14/02/2008 11:22:08.5- SqlMetaData, name='TableB_9', sqlDbType='NVarChar', maxLength=15, precision=0, scale=0
14/02/2008 11:22:08.5- Ending SqlMetaData description
 
14/02/2008 11:22:08.5- Starting sending back the resultset
 
(4 row(s) affected)
14/02/2008 11:22:08.5- Ending sending back the resultset
 
14/02/2008 11:22:08.5- Ending TheMatrix call...
&lt;/pre&gt; &lt;br /&gt; &lt;br /&gt;&lt;h1&gt;
Documentation
&lt;/h1&gt; &lt;br /&gt;The &lt;b&gt;QueryBuilder&lt;/b&gt; Used-Defined Type allows you to specify what query should be executed to fill:&lt;br /&gt; &lt;br /&gt;&lt;ul&gt;
&lt;li&gt;The firt column rows&lt;/li&gt;&lt;li&gt;The columns headers&lt;/li&gt;&lt;li&gt;The Matrix content&lt;/li&gt;
&lt;/ul&gt; &lt;br /&gt;&lt;img src="http://www.codeplex.com/Project/Download/FileDownload.aspx?ProjectName=SQL2DMatrixBuilder&amp;amp;DownloadId=27574" alt="QueryBuilder.png" /&gt;&lt;br /&gt; &lt;br /&gt; &lt;br /&gt;Once you have declared a variable of this type, you can invoke any of its static methods using the &lt;b&gt;::&lt;/b&gt; operator. If you intend to call a literal SQL query, use the &lt;b&gt;New_QueryText&lt;/b&gt; method. If you plan to use a stored procedure instead, use the &lt;b&gt;New_StoredProcedure&lt;/b&gt; method.&lt;br /&gt; &lt;br /&gt;&lt;pre&gt;
-- If you are using a literal SQL query
Declare @MyLiteralSQLQueryBuilder QueryBuilder
Set @MyLiteralSQLQueryBuilder::New_QueryText(N'Select MyColumn1, MyColumn2, MyColumn3 From MyTable1 Inner Join... Where MyColumn4 = @MyParameter')
&lt;/pre&gt; &lt;br /&gt;&lt;pre&gt;
-- If you are using a stored procedure
Declare @MyStoredProcedureQueryBuilder QueryBuilder
Set @MyStoredProcedureQueryBuilder::New_QueryText(N'MyStoredProcedureName')
&lt;/pre&gt; &lt;br /&gt;If your literal SQL query or your stored procedure need some input parameters, you can supply their values by calling the &lt;b&gt;SetParameter&lt;/b&gt; method:&lt;br /&gt; &lt;br /&gt;&lt;pre&gt;
Declare @Value [your type here]
Set @MyLiteralSQLQueryBuilder::SetParameter(N'@MyParameter', @Value)
&lt;/pre&gt; &lt;br /&gt;&lt;pre&gt;
Declare @Value [your type here]
Set @MyStoredProcedureQueryBuilder::SetParameter(N'@MyParameter', @Value)
&lt;/pre&gt; &lt;br /&gt;For the &lt;b&gt;Matrix content&lt;/b&gt; query only, we need to infere the &lt;b&gt;type&lt;/b&gt; of the columns that are returned in the &lt;b&gt;resultset&lt;/b&gt;. Although, this product tries to infere this type, it might not be suitable in all cases. Therefore, you can help infere this type by calling one of the following method:&lt;br /&gt; &lt;br /&gt;&lt;ul&gt;
&lt;ul&gt;
&lt;li&gt;SetContentType(typeName)&lt;/li&gt;&lt;li&gt;SetContentType2(typeName, maxLength)&lt;/li&gt;&lt;li&gt;SetContentType3(typeName, precision, scale)&lt;/li&gt;
&lt;/ul&gt;
&lt;/ul&gt; &lt;br /&gt;&lt;b&gt;typeName&lt;/b&gt; must be one of the &lt;b&gt;System.Data.SqlDbType&lt;/b&gt; enumeration value:&lt;br /&gt; &lt;br /&gt;&lt;img src="http://www.codeplex.com/Project/Download/FileDownload.aspx?ProjectName=SQL2DMatrixBuilder&amp;amp;DownloadId=27576" alt="SqlDbType.png" /&gt;&lt;br /&gt; &lt;br /&gt; &lt;br /&gt;&lt;h1&gt;
More resources on SQL Server 2-D Matrix Builder
&lt;/h1&gt; &lt;br /&gt;An &lt;b&gt;french&lt;/b&gt; article is now available here: &lt;a href="http://msdn2.microsoft.com/fr-fr/sqlserver/cc197167.aspx" class="externalLink"&gt;The SQL Server 2-D Matrix Builder (http://msdn2.microsoft.com/fr-fr/sqlserver/cc197167.aspx)&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;This article will also be translated in &lt;b&gt;English&lt;/b&gt; very soon. Stay tuned!&lt;br /&gt;
&lt;/div&gt;</description><author>olymars</author><pubDate>Fri, 15 Feb 2008 08:50:22 GMT</pubDate><guid isPermaLink="false">UPDATED WIKI: Home 20080215085022A</guid></item><item><title>UPDATED WIKI: Home</title><link>http://www.codeplex.com/SQL2DMatrixBuilder/Wiki/View.aspx?title=Home&amp;version=36</link><description>&lt;div class="wikidoc"&gt;
&lt;h1&gt;
Introduction
&lt;/h1&gt; &lt;br /&gt;This project is all about bringing a &lt;b&gt;2-D matrix builder&lt;/b&gt; to &lt;b&gt;Microsoft SQL Server 2005&lt;/b&gt; (or later). So why do we need this? Consider the following schema:&lt;br /&gt; &lt;br /&gt;&lt;img src="http://www.codeplex.com/Project/Download/FileDownload.aspx?ProjectName=SQL2DMatrixBuilder&amp;amp;DownloadId=27479" alt="SQLMatrix1.png" /&gt;&lt;br /&gt; &lt;br /&gt;Now, what we would like to get as a &lt;b&gt;query result&lt;/b&gt; is the following :&lt;br /&gt; &lt;br /&gt;&lt;img src="http://www.codeplex.com/Project/Download/FileDownload.aspx?ProjectName=SQL2DMatrixBuilder&amp;amp;DownloadId=27480" alt="SQLMatrix2.png" /&gt;&lt;br /&gt; &lt;br /&gt;Notice that the headers are not &lt;i&gt;columns names&lt;/i&gt; but the &lt;b&gt;records&lt;/b&gt; available in the &lt;b&gt;Table_B&lt;/b&gt; table. So how do you get this natively with Microsoft SQL Server? Well, you can't! Unless you use the &lt;b&gt;SQL Server 2-D Matrix Builder&lt;/b&gt;.&lt;br /&gt; &lt;br /&gt;This project is all about using the &lt;b&gt;hosted .NET Common Langage Runtime&lt;/b&gt; in Microsoft SQL Server. All you have to do is uploading the &lt;b&gt;TheMatrixSqlClr.dll&lt;/b&gt; assembly into your SQL Server instance and use it. The next two chapters describe how to install this assembly into your SQL Server instance and how to reuse &lt;b&gt;TheMatrix&lt;/b&gt; stored procedure.&lt;br /&gt; &lt;br /&gt;This project was built by &lt;b&gt;Pascal Belaud&lt;/b&gt;, Developer Evangelist at &lt;b&gt;Microsoft France&lt;/b&gt; &lt;a href="http://blogs.msdn.com/Pascal" class="externalLink"&gt;French Blog (http://blogs.msdn.com/Pascal)&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;). Pascal is also the author of a &lt;b&gt;.NET code generator&lt;/b&gt; based on SQL Server 2005 called &lt;b&gt;OlyMars&lt;/b&gt; (&lt;a href="http://www.olymars.net" class="externalLink"&gt;http://www.olymars.net&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;).&lt;br /&gt; &lt;br /&gt; &lt;br /&gt;&lt;h1&gt;
Deployment
&lt;/h1&gt; &lt;br /&gt;&lt;pre&gt;
-- First you need to enable the use of .NET in your SLQ Server instance
exec sp_configure 'CLR Enabled', 1
reconfigure
GO
 
-- Since this assembly needs external access, your database needs to be TrustWorthy
Alter Database YourDatabase
Set Trustworthy On
GO
 
Use YourDatabase
GO
 
-- You need to deploy the assembly in your SQL Server instance
CREATE ASSEMBLY [TheSQLServerMatrix]
FROM '&amp;lt;Your path to the assembly here&amp;gt;\TheMatrixSqlClr.dll'
WITH PERMISSION_SET=EXTERNAL_ACCESS
GO
 
-- You need to declare a new User Defined Type
CREATE TYPE [QueryBuilder]
EXTERNAL NAME [TheSQLServerMatrix].[TheMatrixSqlClr.QueryBuilder]
GO
 
-- You need to declare a new stored procedure
CREATE PROCEDURE [TheMatrix]
  @rowsQuery [QueryBuilder]
, @rowsQuery_ValueMember nvarchar(max)
, @rowsQuery_DisplayMember nvarchar(max)
, @firstColumnHeader nvarchar(max)
, @columnsQuery [QueryBuilder]
, @columnsQuery_ValueMember nvarchar(max)
, @columnsQuery_DisplayMember nvarchar(max)
, @contentQuery [QueryBuilder]
, @contentQuery_ColumnValueMember nvarchar(max)
, @contentQuery_RowValueMember nvarchar(max)
, @contentQuery_DisplayName nvarchar(max)
, @contentQuery_MissingValue sql_variant
, @diagnose bit = 0
 
AS
EXTERNAL NAME [TheSQLServerMatrix].[TheMatrixSqlClr.StoredProcedures].[TheMatrix]
&lt;/pre&gt; &lt;br /&gt; &lt;br /&gt;&lt;h1&gt;
Usage
&lt;/h1&gt; &lt;br /&gt;Now that the assembly is declared in our instance, we can use &lt;b&gt;TheMatrix&lt;/b&gt; stored procedure like this:&lt;br /&gt; &lt;br /&gt;&lt;pre&gt;
-- Let's declare the first column rows
DECLARE @rowsQuery QueryBuilder
DECLARE @rowsQuery_ValueMember nvarchar(max)
DECLARE @rowsQuery_DisplayMember nvarchar(max)
SET @rowsQuery = QueryBuilder::New_QueryText('Select TableA_ID, TableA_Name From dbo.TableA Order by TableA_Name Asc')
SET @rowsQuery_ValueMember = 'TableA_ID'
SET @rowsQuery_DisplayMember = 'TableA_Name'
 
-- Let's declare the name of the first column header
DECLARE @firstColumnHeader nvarchar(max)
SET @firstColumnHeader = 'HEADER'
 
-- Let's declare the others columns headers
DECLARE @columnsQuery QueryBuilder
DECLARE @columnsQuery_ValueMember nvarchar(max)
DECLARE @columnsQuery_DisplayMember nvarchar(max)
SET @columnsQuery = QueryBuilder::New_QueryText('Select TableB_ID, TableB_Name From dbo.TableB Order By TableB_Name Asc')
SET @columnsQuery_ValueMember = 'TableB_ID'
SET @columnsQuery_DisplayMember = 'TableB_Name'
 
-- Let's declare how to fill the matrix content
DECLARE @contentQuery QueryBuilder
DECLARE @contentQuery_ColumnValueMember nvarchar(max)
DECLARE @contentQuery_RowValueMember nvarchar(max)
DECLARE @contentQuery_DisplayName nvarchar(max)
DECLARE @contentQuery_NullValue sql_variant
SET @contentQuery = QueryBuilder::New_StoredProcedure('spContent')
SET @contentQuery_ColumnValueMember = 'TableC_TableB_ID'
SET @contentQuery_RowValueMember = 'TableC_TableA_ID'
SET @contentQuery_DisplayName = 'TableC_Name'
SET @contentQuery_NullValue = '[NOT AVAILABLE]'
 
-- We want to see how the Matrix is going to execute all this
DECLARE @diagnose bit
SET @diagnose = 1
 
EXECUTE [TheMatrixDatabase].[dbo].[TheMatrix] 
   @rowsQuery
  ,@rowsQuery_ValueMember
  ,@rowsQuery_DisplayMember
  ,@firstColumnHeader
 
  ,@columnsQuery
  ,@columnsQuery_ValueMember
  ,@columnsQuery_DisplayMember
 
  ,@contentQuery
  ,@contentQuery_RowValueMember
  ,@contentQuery_ColumnValueMember
  ,@contentQuery_DisplayName
  ,@contentQuery_NullValue
  ,@diagnose
&lt;/pre&gt; &lt;br /&gt;When you execute this, you get the following resulset :&lt;br /&gt; &lt;br /&gt;&lt;table&gt;
&lt;tr&gt;
&lt;th&gt; HEADER &lt;/th&gt;&lt;th&gt; TableB_5 &lt;/th&gt;&lt;th&gt; TableB_6 &lt;/th&gt;&lt;th&gt; TableB_7 &lt;/th&gt;&lt;th&gt; TableB_8 &lt;/th&gt;&lt;th&gt; TableB_9 &lt;/th&gt;
&lt;/tr&gt;&lt;tr&gt;
&lt;td&gt; TableA_1 &lt;/td&gt;&lt;td&gt; TableC_1_5 &lt;/td&gt;&lt;td&gt; TableC_1_6 &lt;/td&gt;&lt;td&gt; TableC_1_7 &lt;/td&gt;&lt;td&gt; TableC_1_8 &lt;/td&gt;&lt;td&gt; TableC_1_9 &lt;/td&gt;
&lt;/tr&gt;&lt;tr&gt;
&lt;td&gt; TableA_2 &lt;/td&gt;&lt;td&gt; [NOT AVAILABLE] &lt;/td&gt;&lt;td&gt; TableC_2_6 &lt;/td&gt;&lt;td&gt; TableC_2_7 &lt;/td&gt;&lt;td&gt; TableC_2_8 &lt;/td&gt;&lt;td&gt; TableC_2_9 &lt;/td&gt;
&lt;/tr&gt;&lt;tr&gt;
&lt;td&gt; TableA_3 &lt;/td&gt;&lt;td&gt; TableC_3_5 &lt;/td&gt;&lt;td&gt; [NOT AVAILABLE] &lt;/td&gt;&lt;td&gt; TableC_3_7 &lt;/td&gt;&lt;td&gt; TableC_3_8 &lt;/td&gt;&lt;td&gt; TableC_3_9 &lt;/td&gt;
&lt;/tr&gt;&lt;tr&gt;
&lt;td&gt; TableA_4 &lt;/td&gt;&lt;td&gt; TableC_4_ &lt;/td&gt;&lt;td&gt; TableC_4_6 &lt;/td&gt;&lt;td&gt; TableC_4_7 &lt;/td&gt;&lt;td&gt; TableC_4_8 &lt;/td&gt;&lt;td&gt; TableC_4_9 &lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt; &lt;br /&gt; &lt;br /&gt;Notice that the Matrix allows you to call &lt;b&gt;literal SQL queries&lt;/b&gt; or &lt;b&gt;stored procedures&lt;/b&gt;. Those queries can also have input parameters if needed. &lt;br /&gt; &lt;br /&gt;In the previous example, the matrix content is filled with the resultset returned by the &lt;b&gt;spContent&lt;/b&gt; stored procedure:&lt;br /&gt; &lt;br /&gt;&lt;pre&gt;
Create Procedure [dbo].[spContent] As
 
Select TableC_TableA_ID, TableC_TableB_ID, TableC_Name From dbo.TableC
&lt;/pre&gt; &lt;br /&gt; &lt;br /&gt;Since we asked for diagnostic information, here is the output :&lt;br /&gt; &lt;br /&gt;&lt;pre&gt;
14/02/2008 11:22:08.46875- The SQL Server 2-D Matrix Builder
Starting TheMatrix call
 
14/02/2008 11:22:08.484375- Starting calling the Rows query
Query: Select TableA_ID, TableA_Name From dbo.TableA Order by TableA_Name Asc
	Is Stored Procedure: False
	Parameters number: 0
14/02/2008 11:22:08.484375- ValueMember index for [TableA_ID] is: 0
14/02/2008 11:22:08.484375- DisplayMember index for [TableA_Name] is: 1
14/02/2008 11:22:08.484375- Ending calling the Rows query
 
14/02/2008 11:22:08.484375- Starting calling the Columns query
Query: Select TableB_ID, TableB_Name From dbo.TableB Order By TableB_Name Asc
	Is Stored Procedure: False
	Parameters number: 0
14/02/2008 11:22:08.484375- ValueMember index for [TableB_ID] is: 0
14/02/2008 11:22:08.484375- DisplayMember index for [TableB_Name] is: 1
14/02/2008 11:22:08.484375- Ending calling the Columns query
 
14/02/2008 11:22:08.484375- Starting initializing the Matrix content
14/02/2008 11:22:08.484375- Ending initializing the Matrix content
 
14/02/2008 11:22:08.484375- Starting calling the Content query
Query: spContent
	Is Stored Procedure: True
	Parameters number: 0
14/02/2008 11:22:08.484375- ColumnValueMember index for [TableC_TableB_ID] is: 1
14/02/2008 11:22:08.484375- RowValueMember index for [TableC_TableA_ID] is: 0
14/02/2008 11:22:08.484375- DisplayMember index for [TableC_Name] is: 2
14/02/2008 11:22:08.484375- Ending calling the Content query
 
14/02/2008 11:22:08.484375- Starting SqlMetaData description
14/02/2008 11:22:08.484375- SqlMetaData, name='HEADER', sqlDbType='NVarChar', maxLength=8, precision=0, scale=0
14/02/2008 11:22:08.5- SqlMetaData, name='TableB_5', sqlDbType='NVarChar', maxLength=15, precision=0, scale=0
14/02/2008 11:22:08.5- SqlMetaData, name='TableB_6', sqlDbType='NVarChar', maxLength=15, precision=0, scale=0
14/02/2008 11:22:08.5- SqlMetaData, name='TableB_7', sqlDbType='NVarChar', maxLength=15, precision=0, scale=0
14/02/2008 11:22:08.5- SqlMetaData, name='TableB_8', sqlDbType='NVarChar', maxLength=15, precision=0, scale=0
14/02/2008 11:22:08.5- SqlMetaData, name='TableB_9', sqlDbType='NVarChar', maxLength=15, precision=0, scale=0
14/02/2008 11:22:08.5- Ending SqlMetaData description
 
14/02/2008 11:22:08.5- Starting sending back the resultset
 
(4 row(s) affected)
14/02/2008 11:22:08.5- Ending sending back the resultset
 
14/02/2008 11:22:08.5- Ending TheMatrix call...
&lt;/pre&gt; &lt;br /&gt; &lt;br /&gt;&lt;h1&gt;
Documentation
&lt;/h1&gt; &lt;br /&gt;The &lt;b&gt;QueryBuilder&lt;/b&gt; Used-Defined Type allows you to specify what query should be executed to fill:&lt;br /&gt; &lt;br /&gt;&lt;ul&gt;
&lt;li&gt;The firt column rows&lt;/li&gt;&lt;li&gt;The columns headers&lt;/li&gt;&lt;li&gt;The Matrix content&lt;/li&gt;
&lt;/ul&gt; &lt;br /&gt;&lt;img src="http://www.codeplex.com/Project/Download/FileDownload.aspx?ProjectName=SQL2DMatrixBuilder&amp;amp;Down