<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DZone Snippets: sql-server code</title>
    <link>http://snippets.dzone.com/posts</link>
    <pubDate>Fri, 08 Aug 2008 04:49:21 GMT</pubDate>
    <description>DZone Snippets: sql-server code</description>
    <item>
      <title>Return current system date and time in Microsoft SQL Server</title>
      <link>http://snippets.dzone.com/posts/show/5767</link>
      <description>Solution from &lt;a href="http://mattfaus.com/blog/2008/02/16/ms-sql-server-transact-sql-now-function/"&gt;The Matt Faus Blog&lt;/a&gt;:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;SELECT GETDATE();&lt;br /&gt;&lt;/code&gt;</description>
      <pubDate>Tue, 15 Jul 2008 05:28:42 GMT</pubDate>
      <guid>http://snippets.dzone.com/posts/show/5767</guid>
      <author>jeffreybarke (Jeffrey Barke)</author>
    </item>
    <item>
      <title>Search for specific text in all stored procedures</title>
      <link>http://snippets.dzone.com/posts/show/3905</link>
      <description>&lt;code&gt;&lt;br /&gt;declare @search varchar(50)&lt;br /&gt;SET @search = 'searchterm'&lt;br /&gt;&lt;br /&gt;SELECT    &lt;br /&gt;     ROUTINE_NAME,&lt;br /&gt;     ROUTINE_DEFINITION&lt;br /&gt;FROM    &lt;br /&gt;    INFORMATION_SCHEMA.ROUTINES&lt;br /&gt;WHERE    &lt;br /&gt;    ROUTINE_DEFINITION LIKE @search&lt;br /&gt;ORDER BY&lt;br /&gt;    ROUTINE_NAME&lt;br /&gt;&lt;/code&gt;</description>
      <pubDate>Thu, 26 Apr 2007 03:08:05 GMT</pubDate>
      <guid>http://snippets.dzone.com/posts/show/3905</guid>
      <author>mrtrombone (Mark Easton)</author>
    </item>
    <item>
      <title>A generic cross tab / pivot table query for Transact SQL (with sortable columns)</title>
      <link>http://snippets.dzone.com/posts/show/2000</link>
      <description>This procedure generates a 'cross-tab' (or 'pivot table') result set from (almost) any query, even a stored procedure and optionally allows you to specify a column sort order. &lt;br /&gt;&lt;br /&gt;The procedure makes extensive use dynamic SQL and hence 'sp_executesql'. Because the scope of temporary tables does not extend outside of an sp_executesql transaction, I've had to use global temporary tables, which means that this procedure could become a bottleneck if used too frequently by multiple sessions.&lt;br /&gt; &lt;br /&gt;This stored procedure is provided 'as is' and without any warranty - I've only tested it on a relatively small number of queries. For more information (and my contact details) see http://nwsoft.blogspot.com/2006/05/generic-cross-tab-pivot-table-query.html&lt;br /&gt;&lt;br /&gt;This work is licensed under a Creative Commons Attribution 2.5 License.&lt;br /&gt;&lt;code&gt;&lt;br /&gt;CREATE PROCEDURE [dbo].[genericCrosstab]&lt;br /&gt;&lt;br /&gt; -- @tableSpec&lt;br /&gt; --   A comma delimited list of columns with datatypes (and null constraints, if required)&lt;br /&gt; --   e.g. 'col1 INT, col2 VARCHAR(255) NULL'&lt;br /&gt; --   N.B. You only need provide this list if the source of the data is a stored procedure&lt;br /&gt; @tableSpec    NVARCHAR(4000) = '',&lt;br /&gt;&lt;br /&gt; -- @sqlSelect&lt;br /&gt; --   The SELECT clause (or 'EXEC &lt;stored_procedure&gt;' statement) for the input data&lt;br /&gt; --   e.g. 'SELECT a.au_id, a.au_fname, a.au_lname, a.phone, LEFT(t.title, 10) AS [title], LEFT(s.stor_name, 10) AS [store], sales.qty'&lt;br /&gt; --   e.g. 'EXEC dbo.myStoredProcedure &lt;param1&gt;, &lt;param2&gt;'&lt;br /&gt; @sqlSelect    NVARCHAR(512),&lt;br /&gt;&lt;br /&gt; -- @sqlFromWhere&lt;br /&gt; --   The FROM and WHERE clauses for the input data (if a SELECT statement)&lt;br /&gt; --   e.g. 'FROM authors a, titleauthor ta, titles t, stores s, sales WHERE a.au_id = ta.au_id AND ta.title_id = t.title_id AND t.title_id = sales.title_id AND s.stor_id = sales.stor_id'&lt;br /&gt; --   N.B. Leave this blank if the source of the data is a stored procedure&lt;br /&gt; @sqlFromWhere NVARCHAR(512)  = '',&lt;br /&gt;&lt;br /&gt; -- @pivotExpr&lt;br /&gt; --   The column name or expression to use as the pivot (specifies which values are the column headings for the crosstabbed data)&lt;br /&gt; --   e.g. 'store' or '''Store: '' + [store]'&lt;br /&gt; @pivotExpr    NVARCHAR(255),&lt;br /&gt;&lt;br /&gt; -- @valueExpr&lt;br /&gt; --   A column name or expression to use as the values in the crosstabbed data&lt;br /&gt; --   e.g. 'qty'&lt;br /&gt; @valueExpr    NVARCHAR(512),&lt;br /&gt;&lt;br /&gt; -- @function&lt;br /&gt; --   The aggregation function to use to combine values in the crosstabbed data&lt;br /&gt; --   e.g. 'MIN'&lt;br /&gt; --   N.B. If this parameter is left blank, the procedure will count up occurences and create additional column headings as necessary, e.g. '[X], [Y], [Y (2)], [Z]' if there are two occurences for label 'Y'&lt;br /&gt; @function     NVARCHAR(20)   = '',&lt;br /&gt;&lt;br /&gt; -- @groupBy&lt;br /&gt; --   The column list to group by (these columns will appear to the left of the crosstabbed data)&lt;br /&gt; --   e.g. 'au_id, au_fname, au_lname, phone'&lt;br /&gt; @groupBy      NVARCHAR(512),&lt;br /&gt;&lt;br /&gt; -- @sortLookup&lt;br /&gt; --   A table or view which can be queried to provide a sort order for the columns in the crosstabbed data&lt;br /&gt; --   e.g. 'days_of_the_week'&lt;br /&gt; --   N.B. The specified table or view must have 'label' and 'sort_order' columns&lt;br /&gt; --   N.B. If column order is irrelevant, leave this parameter blank&lt;br /&gt; --   N.B. Feature: if @sortLookup is given as '*', the columns are placed in ascending alphabetical order&lt;br /&gt; @sortLookup   NVARCHAR(40)   = '',&lt;br /&gt;&lt;br /&gt; -- @collation&lt;br /&gt; --   The collation sequence&lt;br /&gt; --   e.g. 'Latin1_general_CI_AS'&lt;br /&gt; @collation   NVARCHAR(40)   = 'Latin1_general_CI_AS',&lt;br /&gt;&lt;br /&gt; -- @verbose&lt;br /&gt; --   Set to 1 if you want debug messages&lt;br /&gt; @verbose     BIT            = 0&lt;br /&gt;&lt;br /&gt;AS&lt;br /&gt;BEGIN&lt;br /&gt;&lt;br /&gt; -- Check that the mandatory parameters are not empty strings&lt;br /&gt; IF LEN(RTRIM(ISNULL(@sqlSelect, ''))) = 0&lt;br /&gt; BEGIN&lt;br /&gt;   RAISERROR ('The @sqlSelect parameter cannot be an empty string.', 16, 1)&lt;br /&gt;   ROLLBACK TRANSACTION&lt;br /&gt; END&lt;br /&gt;&lt;br /&gt; IF LEN(RTRIM(ISNULL(@pivotExpr, ''))) = 0&lt;br /&gt; BEGIN&lt;br /&gt;   RAISERROR ('The @pivotExpr parameter cannot be an empty string.', 16, 1)&lt;br /&gt;   ROLLBACK TRANSACTION&lt;br /&gt; END&lt;br /&gt;&lt;br /&gt; IF LEN(RTRIM(ISNULL(@valueExpr, ''))) = 0&lt;br /&gt; BEGIN&lt;br /&gt;   RAISERROR ('The @valueExpr parameter cannot be an empty string.', 16, 1)&lt;br /&gt;   ROLLBACK TRANSACTION&lt;br /&gt; END&lt;br /&gt;&lt;br /&gt; IF LEN(RTRIM(ISNULL(@groupBy, ''))) = 0&lt;br /&gt; BEGIN&lt;br /&gt;   RAISERROR ('The @groupBy parameter cannot be an empty string.', 16, 1)&lt;br /&gt;   ROLLBACK TRANSACTION&lt;br /&gt; END&lt;br /&gt;&lt;br /&gt; -- Local variables&lt;br /&gt; DECLARE @i      INTEGER&lt;br /&gt; DECLARE @sql    NVARCHAR(4000)&lt;br /&gt; DECLARE @sqlX   NVARCHAR(4000)&lt;br /&gt; DECLARE @col    NVARCHAR(4000)&lt;br /&gt; DECLARE @pivot  NVARCHAR(4000)&lt;br /&gt; DECLARE @indx   NVARCHAR(10)&lt;br /&gt; DECLARE @cols   NVARCHAR(4000)&lt;br /&gt; DECLARE @where  NVARCHAR(4000)&lt;br /&gt; DECLARE @update NVARCHAR(4000)&lt;br /&gt; DECLARE @value  NVARCHAR(532)&lt;br /&gt; DECLARE @select NVARCHAR(4000)&lt;br /&gt;&lt;br /&gt; -- Drop the global temporary tables we will use (if they already exist)&lt;br /&gt; -- N.B. we have to use global temp tables, as local temp tables are dropped at the end of a batch (so are not accessible outside of the sp_executesql context)&lt;br /&gt; -- This syntax is a bit long winded because I couldn't make the substitution syntax for sp_executesql work (for this example only! - a bug in T-SQL?)&lt;br /&gt; SELECT @sql = N'IF EXISTS (SELECT 1 FROM tempdb.dbo.sysobjects WHERE name = ''@table'' AND xtype = ''U'') DROP TABLE @table'&lt;br /&gt; SELECT @sqlX = REPLACE(@sql, N'@table', N'##input')&lt;br /&gt; EXEC sp_executesql @sqlX&lt;br /&gt; SELECT @sqlX = REPLACE(@sql, N'@table', N'##grpCount')&lt;br /&gt; EXEC sp_executesql @sqlX&lt;br /&gt; SELECT @sqlX = REPLACE(@sql, N'@table', N'##colList')&lt;br /&gt; EXEC sp_executesql @sqlX&lt;br /&gt; SELECT @sqlX = REPLACE(@sql, N'@table', N'##lookup')&lt;br /&gt; EXEC sp_executesql @sqlX&lt;br /&gt; SELECT @sqlX = REPLACE(@sql, N'@table', N'##results')&lt;br /&gt; EXEC sp_executesql @sqlX&lt;br /&gt; SELECT @sqlX = REPLACE(@sql, N'@table', N'##temp')&lt;br /&gt; EXEC sp_executesql @sqlX&lt;br /&gt;&lt;br /&gt; IF @verbose = 1 SELECT 'Global temporary tables dropped (if present).' AS [Message]&lt;br /&gt;&lt;br /&gt; -- * The real work starts here&lt;br /&gt;&lt;br /&gt; -- Store the input dataset&lt;br /&gt; IF LEN(RTRIM(@tableSpec)) = 0&lt;br /&gt; BEGIN&lt;br /&gt;   -- Create and populate the temporary table in one step&lt;br /&gt;   SELECT @sql = @sqlSelect + ' INTO ##input ' + @sqlFromWhere&lt;br /&gt;   IF @verbose = 1 SELECT @sql AS [Create and populate the temporary table in one step]&lt;br /&gt;   EXEC sp_executesql @sql&lt;br /&gt; END&lt;br /&gt; ELSE&lt;br /&gt; BEGIN&lt;br /&gt;   -- Create the temporary table first (the only method that can be used if the data is coming from a stored proc)&lt;br /&gt;   SELECT @sql = 'CREATE TABLE ##input (' + @tableSpec + ')'&lt;br /&gt;   IF @verbose = 1 SELECT @sql AS [Create the temporary table]&lt;br /&gt;   EXEC sp_executesql @sql&lt;br /&gt;   -- Populate it&lt;br /&gt;   SELECT @sql = 'INSERT INTO ##input ' + @sqlSelect + ' ' + @sqlFromWhere&lt;br /&gt;   IF @verbose = 1 SELECT @sql AS [Populate the temporary table]&lt;br /&gt;   EXEC sp_executesql @sql&lt;br /&gt; END&lt;br /&gt; IF @verbose = 1 SELECT * FROM ##input&lt;br /&gt;&lt;br /&gt; -- Does the query we want to cross-tab already have a column called 'crossTabRowID'? This is a reserved column name!&lt;br /&gt; IF EXISTS(SELECT 1 FROM tempdb.dbo.sysobjects o, tempdb.dbo.syscolumns c WHERE o.id = c.id AND o.name = '##input' AND c.name = 'crossTabRowID')&lt;br /&gt; BEGIN&lt;br /&gt;   RAISERROR ('The query passed to the [genericCrosstab] procedure uses a reserved column name (''crossTabRowID'').', 16, 1)&lt;br /&gt;   ROLLBACK TRANSACTION&lt;br /&gt; END&lt;br /&gt;&lt;br /&gt; -- Add an identity column (we need a 'row ID')&lt;br /&gt; ALTER TABLE ##input ADD crossTabRowID NUMERIC(9, 0) IDENTITY NOT NULL&lt;br /&gt;&lt;br /&gt; -- Generate the column list&lt;br /&gt; SELECT @sql = 'SELECT ' + @groupBy + ' INTO ##colList FROM ##input WHERE 1 = 0'&lt;br /&gt; IF @verbose = 1 SELECT @sql AS [Generate the column list]&lt;br /&gt; EXEC sp_executesql @sql&lt;br /&gt; IF @verbose = 1 SELECT * FROM ##colList&lt;br /&gt;&lt;br /&gt; -- If no aggregation function is specified, we have to check first that there are no duplicates, and - if there are - we need to handle them&lt;br /&gt; IF RTRIM(ISNULL(@function, '')) = ''&lt;br /&gt; BEGIN&lt;br /&gt;   SELECT @sql = 'SELECT ' + @groupBy + ', ' + @pivotExpr + ' COLLATE ' + @collation + ' AS [pivot], COUNT(1) AS [count] INTO ##grpCount FROM ##input GROUP BY ' + @groupBy + ', ' + @pivotExpr + ' COLLATE ' + @collation&lt;br /&gt; END&lt;br /&gt; ELSE&lt;br /&gt; BEGIN&lt;br /&gt;   SELECT @sql = 'SELECT ' + @groupBy + ', ' + @pivotExpr + ' COLLATE ' + @collation + ' AS [pivot], 1 AS [count] INTO ##grpCount FROM ##input GROUP BY ' + @groupBy + ', ' + @pivotExpr + ' COLLATE ' + @collation&lt;br /&gt; END&lt;br /&gt; IF @verbose = 1 SELECT @sql AS [Create the ##grpCount table]&lt;br /&gt; EXEC sp_executesql @sql&lt;br /&gt; IF @verbose = 1 SELECT * FROM ##grpCount&lt;br /&gt;&lt;br /&gt; -- Create a temporary table that will act as a lookup (containing all of the non-pivot / non-group columns names)&lt;br /&gt; SELECT [pivot], [count] AS [index], [pivot] AS [column_name] INTO ##lookup FROM ##grpCount WHERE 1 = 0&lt;br /&gt;&lt;br /&gt; -- Build the results table; one row per group&lt;br /&gt; SELECT @sql = 'SELECT ' + @groupBy + ' INTO ##results FROM ##grpCount GROUP BY ' + @groupBy&lt;br /&gt; IF @verbose = 1 SELECT @sql AS [Create the ##results table]&lt;br /&gt; EXEC sp_executesql @sql&lt;br /&gt; IF @verbose = 1 SELECT * FROM ##results&lt;br /&gt;&lt;br /&gt; -- Build the column list, taking into account duplicate occurences of pivotal values&lt;br /&gt; DECLARE xcursor CURSOR FOR SELECT [pivot], MAX([count]) FROM ##grpCount GROUP BY [pivot]&lt;br /&gt; OPEN xcursor&lt;br /&gt;&lt;br /&gt; FETCH NEXT FROM xcursor INTO @pivot, @indx&lt;br /&gt;&lt;br /&gt; WHILE @@FETCH_STATUS = 0&lt;br /&gt; BEGIN&lt;br /&gt;&lt;br /&gt;  SELECT @i = 1&lt;br /&gt;&lt;br /&gt;  -- Loop over indx&lt;br /&gt;  WHILE @i &lt;= @indx&lt;br /&gt;  BEGIN&lt;br /&gt;&lt;br /&gt;    -- Build the column list&lt;br /&gt;    SELECT @col = CASE @i WHEN 1 THEN @pivot ELSE @pivot + ' (' + CAST(@i AS VARCHAR(10)) + ')' END&lt;br /&gt;    INSERT INTO ##lookup VALUES (@pivot, @i, @col)&lt;br /&gt;    SELECT @col = '[' + @col + '] NVARCHAR(255) NULL'&lt;br /&gt;    SELECT @cols =  ISNULL(@cols + ', ', '') + @col&lt;br /&gt;&lt;br /&gt;    -- Add the column to the results table&lt;br /&gt;    SELECT @sql = 'ALTER TABLE ##results ADD ' + @col&lt;br /&gt;    IF @verbose = 1 SELECT @sql AS [Add column to the ##results table]&lt;br /&gt;    EXEC sp_executesql @sql&lt;br /&gt;&lt;br /&gt;    -- Continue&lt;br /&gt;    SELECT @i = @i + 1&lt;br /&gt;&lt;br /&gt;  END&lt;br /&gt;  &lt;br /&gt;  FETCH NEXT FROM xcursor INTO @pivot, @indx&lt;br /&gt;&lt;br /&gt; END&lt;br /&gt;&lt;br /&gt; CLOSE xcursor&lt;br /&gt; DEALLOCATE xcursor &lt;br /&gt;&lt;br /&gt; IF @verbose = 1 SELECT * FROM ##lookup&lt;br /&gt; IF @verbose = 1 SELECT * FROM ##results&lt;br /&gt;&lt;br /&gt; -- Loop over the column list (using the syscolumns table in the temp database) to build the WHERE clause&lt;br /&gt; DECLARE xcursor CURSOR FOR SELECT DISTINCT c.[colid], c.[name] FROM tempdb.dbo.sysobjects o, tempdb.dbo.syscolumns c WHERE o.[id] = c.[id] AND o.[name] = '##colList' ORDER BY c.[colid]&lt;br /&gt; OPEN xcursor&lt;br /&gt;&lt;br /&gt; FETCH NEXT FROM xcursor INTO @indx, @col&lt;br /&gt;&lt;br /&gt; WHILE @@FETCH_STATUS = 0&lt;br /&gt; BEGIN&lt;br /&gt;  &lt;br /&gt;   -- Build the WHERE clause&lt;br /&gt;   SELECT @where = ISNULL(@where + ' AND ', '') + 'ISNULL(t1.[' + @col + '], '''') = ISNULL(t3.[' + @col + '], '''')'&lt;br /&gt;  &lt;br /&gt;   FETCH NEXT FROM xcursor INTO @indx, @col&lt;br /&gt;&lt;br /&gt; END&lt;br /&gt;&lt;br /&gt; CLOSE xcursor&lt;br /&gt; DEALLOCATE xcursor &lt;br /&gt;&lt;br /&gt; IF @verbose = 1 SELECT @where AS [WHERE clause]&lt;br /&gt;&lt;br /&gt; -- Create a temp table that will help us build the UPDATE statements to set the values in the pivot table, and the SELECT statement (with columns in preferred order) afterwards&lt;br /&gt; IF RTRIM(ISNULL(@sortLookup, '')) = ''&lt;br /&gt; BEGIN&lt;br /&gt;&lt;br /&gt;   -- If no sorting table was specified, just select all columns&lt;br /&gt;   SELECT @select = '*'&lt;br /&gt;&lt;br /&gt;   -- Sort alphabetically&lt;br /&gt;   SELECT @sql = 'SELECT DISTINCT t5.[index], c.[name], t5.[pivot] INTO ##temp FROM tempdb.dbo.sysobjects o, tempdb.dbo.syscolumns c, ##lookup t5 WHERE o.[id] = c.[id] AND o.[name] = ''##results'' AND c.[name] COLLATE ' + @collation + ' = t5.[column_name] COLLATE ' + @collation + ' ORDER BY c.[name], t5.[index]'&lt;br /&gt;&lt;br /&gt; END&lt;br /&gt; ELSE&lt;br /&gt; BEGIN&lt;br /&gt;&lt;br /&gt;   -- The 'group by' column(s) always come(s) first&lt;br /&gt;   SELECT @select = @groupBy&lt;br /&gt;&lt;br /&gt;   -- Sort in proscribed order&lt;br /&gt;   SELECT @sql = 'SELECT DISTINCT t5.[index], c.[name], t5.[pivot], l.[sort_order] INTO ##temp FROM tempdb.dbo.sysobjects o, tempdb.dbo.syscolumns c, ##lookup t5, ' + @sortLookup + ' l WHERE o.[id] = c.[id] AND o.[name] = ''##results'' AND t5.[pivot] COLLATE ' + @collation + ' *= l.[label] COLLATE ' + @collation + ' AND c.[name] COLLATE ' + @collation + ' = t5.[column_name] COLLATE ' + @collation + ' ORDER BY l.[sort_order], c.[name], t5.[index]'&lt;br /&gt;&lt;br /&gt; END&lt;br /&gt;&lt;br /&gt; IF @verbose = 1 SELECT @sql AS [Build the ##temp table]&lt;br /&gt; EXEC sp_executesql @sql &lt;br /&gt; IF @verbose = 1 SELECT * FROM ##temp&lt;br /&gt;&lt;br /&gt; -- The value expression&lt;br /&gt; SELECT @value = @valueExpr&lt;br /&gt;&lt;br /&gt; -- If a function has been specified&lt;br /&gt; IF RTRIM(ISNULL(@function, '')) != ''&lt;br /&gt; BEGIN&lt;br /&gt;   SELECT @value = @function + '(' + @value + ')'&lt;br /&gt; END&lt;br /&gt;&lt;br /&gt; DECLARE xcursor CURSOR FOR SELECT [index], [name], [pivot] FROM ##temp&lt;br /&gt; OPEN xcursor&lt;br /&gt;&lt;br /&gt; FETCH NEXT FROM xcursor INTO @indx, @col, @pivot&lt;br /&gt;&lt;br /&gt; WHILE @@FETCH_STATUS = 0&lt;br /&gt; BEGIN&lt;br /&gt;&lt;br /&gt;  -- Build the SELECT expression&lt;br /&gt;  IF @select != '*' SELECT @select = @select + ', ' + @col&lt;br /&gt;&lt;br /&gt;  -- Create the SET clause of the UPDATE sql&lt;br /&gt;  IF RTRIM(ISNULL(@function, '')) = ''&lt;br /&gt;  BEGIN&lt;br /&gt;    -- No function specified&lt;br /&gt;    SELECT @update = '[' + @col + '] = (SELECT ' + @value + ' FROM ##input t1 WHERE ' + @where + ' AND ' + @pivotExpr + ' COLLATE ' + @collation + ' = ''' + @pivot + ''' COLLATE ' + @collation + ' AND t1.crossTabRowID = (SELECT MIN(t0.crossTabRowID) FROM ##input t0 WHERE ' + REPLACE(@where, 't3.', 't0.') + ' AND ' + @pivotExpr + ' COLLATE ' + @collation + ' = ''' + @pivot + '''' + ' COLLATE ' + @collation + ') + (' + CAST(@indx AS VARCHAR(3)) + ' - 1))'&lt;br /&gt;  END&lt;br /&gt;  ELSE&lt;br /&gt;  BEGIN&lt;br /&gt;    -- Function specified&lt;br /&gt;    SELECT @update = '[' + @col + '] = (SELECT ' + @value + ' FROM ##input t1 WHERE ' + @where + ' AND ' + @pivotExpr + ' COLLATE ' + @collation + ' = ''' + @pivot + ''' COLLATE ' + @collation + ' AND t1.crossTabRowID IN (SELECT t0.crossTabRowID FROM ##input t0 WHERE ' + REPLACE(@where, 't3.', 't0.') + ' AND ' + @pivotExpr + ' COLLATE ' + @collation + ' = ''' + @pivot + '''' + ' COLLATE ' + @collation + '))'&lt;br /&gt;  END&lt;br /&gt;  SELECT @sql = 'UPDATE ##results SET ' + @update + ' FROM ##results t3'&lt;br /&gt;  IF @verbose = 1 SELECT @sql AS [Create the SET clause of the UPDATE sql]&lt;br /&gt;  EXEC sp_executesql @sql&lt;br /&gt;  &lt;br /&gt;  FETCH NEXT FROM xcursor INTO @indx, @col, @pivot&lt;br /&gt;&lt;br /&gt; END&lt;br /&gt;&lt;br /&gt; CLOSE xcursor&lt;br /&gt; DEALLOCATE xcursor &lt;br /&gt;&lt;br /&gt; -- Return the results&lt;br /&gt; SELECT @sql = 'SELECT ' + @select + ' FROM ##results'&lt;br /&gt; IF @verbose = 1 SELECT @sql AS [Create the SELECT statement that will return the results]&lt;br /&gt; EXEC sp_executesql @sql&lt;br /&gt;&lt;br /&gt; -- Tidy up: drop the global temporary tables&lt;br /&gt; SELECT @sql = N'IF EXISTS (SELECT 1 FROM tempdb.dbo.sysobjects WHERE name = ''@table'' AND xtype = ''U'') DROP TABLE @table'&lt;br /&gt; SELECT @sqlX = REPLACE(@sql, N'@table', N'##input')&lt;br /&gt; EXEC sp_executesql @sqlX&lt;br /&gt; SELECT @sqlX = REPLACE(@sql, N'@table', N'##grpCount')&lt;br /&gt; EXEC sp_executesql @sqlX&lt;br /&gt; SELECT @sqlX = REPLACE(@sql, N'@table', N'##colList')&lt;br /&gt; EXEC sp_executesql @sqlX&lt;br /&gt; SELECT @sqlX = REPLACE(@sql, N'@table', N'##lookup')&lt;br /&gt; EXEC sp_executesql @sqlX&lt;br /&gt; SELECT @sqlX = REPLACE(@sql, N'@table', N'##results')&lt;br /&gt; EXEC sp_executesql @sqlX&lt;br /&gt; SELECT @sqlX = REPLACE(@sql, N'@table', N'##temp')&lt;br /&gt; EXEC sp_executesql @sqlX&lt;br /&gt;&lt;br /&gt;END&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;The following script creates two tables (one of test data, the other to specify a sort order) and runs the genericCrosstab procedure to generate a report.&lt;br /&gt;&lt;code&gt;&lt;br /&gt;IF EXISTS (SELECT *&lt;br /&gt;             FROM dbo.sysobjects&lt;br /&gt;            WHERE [id] = object_id(N'[dbo].[testTable]')&lt;br /&gt;              AND OBJECTPROPERTY(id, N'IsTable') = 1)&lt;br /&gt;BEGIN&lt;br /&gt;  DROP TABLE [dbo].[testTable]&lt;br /&gt;END&lt;br /&gt;GO&lt;br /&gt;&lt;br /&gt;CREATE TABLE testTable&lt;br /&gt; ([who]  VARCHAR(10)  NOT NULL,&lt;br /&gt;  [when] DATETIME     NOT NULL,&lt;br /&gt;  [what] VARCHAR(255) NOT NULL,&lt;br /&gt;  [qty]  INT          NOT NULL)&lt;br /&gt;GO&lt;br /&gt;&lt;br /&gt;DELETE FROM testTable&lt;br /&gt;GO&lt;br /&gt;&lt;br /&gt;INSERT INTO testTable VALUES ('Fred', '2005-APR-01', 'Coding',  5)&lt;br /&gt;INSERT INTO testTable VALUES ('Jo',   '2005-APR-01', 'Coding',  1)&lt;br /&gt;INSERT INTO testTable VALUES ('Jo',   '2005-APR-01', 'Testing', 7)&lt;br /&gt;INSERT INTO testTable VALUES ('Fred', '2005-APR-01', 'Coding',  3)&lt;br /&gt;INSERT INTO testTable VALUES ('Tim',  '2005-APR-01', 'Coding',  4)&lt;br /&gt;INSERT INTO testTable VALUES ('Fred', '2005-APR-02', 'Coding',  8)&lt;br /&gt;INSERT INTO testTable VALUES ('Jo',   '2005-APR-02', 'Coding',  2)&lt;br /&gt;INSERT INTO testTable VALUES ('Jo',   '2005-APR-02', 'Testing', 6)&lt;br /&gt;INSERT INTO testTable VALUES ('Tim',  '2005-APR-02', 'Coding',  4)&lt;br /&gt;GO&lt;br /&gt;&lt;br /&gt;SELECT * FROM testTable&lt;br /&gt;GO&lt;br /&gt;&lt;br /&gt;EXEC [dbo].[genericCrosstab]&lt;br /&gt; @sqlSelect    = 'SELECT *',&lt;br /&gt; @sqlFromWhere = 'FROM testTable',&lt;br /&gt; @pivotExpr    = 'what',&lt;br /&gt; @valueExpr    = 'qty',&lt;br /&gt; @function     = 'SUM',&lt;br /&gt; @groupBy      = 'who'&lt;br /&gt;GO&lt;br /&gt;&lt;br /&gt;-- Extending the example to proscribe column order...&lt;br /&gt;&lt;br /&gt;IF EXISTS (SELECT *&lt;br /&gt;             FROM dbo.sysobjects&lt;br /&gt;            WHERE [id] = object_id(N'[dbo].[testSorter]')&lt;br /&gt;              AND OBJECTPROPERTY(id, N'IsTable') = 1)&lt;br /&gt;BEGIN&lt;br /&gt;  DROP TABLE [dbo].[testSorter]&lt;br /&gt;END&lt;br /&gt;GO&lt;br /&gt;&lt;br /&gt;CREATE TABLE testSorter&lt;br /&gt; ([label]      VARCHAR(255) NOT NULL,&lt;br /&gt;  [sort_order] INT          NOT NULL)&lt;br /&gt;GO&lt;br /&gt;&lt;br /&gt;DELETE FROM testSorter&lt;br /&gt;GO&lt;br /&gt;&lt;br /&gt;INSERT INTO testSorter VALUES ('Testing',  1)&lt;br /&gt;INSERT INTO testSorter VALUES ('Coding',   2)&lt;br /&gt;GO&lt;br /&gt;&lt;br /&gt;SELECT * FROM testSorter&lt;br /&gt;GO&lt;br /&gt;&lt;br /&gt;EXEC [dbo].[genericCrosstab]&lt;br /&gt; @sqlSelect    = 'SELECT *',&lt;br /&gt; @sqlFromWhere = 'FROM testTable',&lt;br /&gt; @pivotExpr    = 'what',&lt;br /&gt; @valueExpr    = 'qty',&lt;br /&gt; @function     = 'SUM',&lt;br /&gt; @groupBy      = 'who',&lt;br /&gt; @sortLookup   = 'testSorter',&lt;br /&gt; @verbose      = 0&lt;br /&gt;GO&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;You can change @verbose to 1 to see what is going on.</description>
      <pubDate>Tue, 09 May 2006 13:11:23 GMT</pubDate>
      <guid>http://snippets.dzone.com/posts/show/2000</guid>
      <author>rgedwards (Rich Edwards (rich at semantise dot com))</author>
    </item>
    <item>
      <title>Convert a string representation of a UK date to a datetime</title>
      <link>http://snippets.dzone.com/posts/show/887</link>
      <description>This function is not particularly smart - it expects a UK-style date string in 'dd/mm/yyyy' format, but can cope with 'dd/mm/yy' (and if mm &gt; 12 it assumes the date is 'mm/dd/yyyy'). This work is licensed under a Creative Commons Attribution 2.5 License.&lt;br /&gt;&lt;code&gt;&lt;br /&gt;CREATE FUNCTION dbo.f_convert_str_to_date(@str VARCHAR(10))&lt;br /&gt;  RETURNS DATETIME&lt;br /&gt;AS&lt;br /&gt;BEGIN&lt;br /&gt;&lt;br /&gt;  -- Declare local variables&lt;br /&gt;  DECLARE @boundary  TINYINT&lt;br /&gt;  DECLARE @separator CHAR(1)&lt;br /&gt;  DECLARE @return    VARCHAR(11)&lt;br /&gt;  DECLARE @index1    INT&lt;br /&gt;  DECLARE @index2    INT&lt;br /&gt;  DECLARE @day       VARCHAR(2)&lt;br /&gt;  DECLARE @month     VARCHAR(2)&lt;br /&gt;  DECLARE @year      VARCHAR(4)&lt;br /&gt;  DECLARE @iDay      TINYINT&lt;br /&gt;  DECLARE @iMonth    TINYINT&lt;br /&gt;  DECLARE @iYear     SMALLINT&lt;br /&gt;  DECLARE @iSwap     TINYINT&lt;br /&gt;&lt;br /&gt;  -- 'Constants'&lt;br /&gt;  SELECT @boundary = 20&lt;br /&gt;  SELECT @separator = '/'&lt;br /&gt;&lt;br /&gt;  -- Indexes of forward slash separators (2 are expected)&lt;br /&gt;  SELECT @index1 = CHARINDEX(@separator, @str)&lt;br /&gt;  SELECT @index2 = CHARINDEX(@separator, @str, @index1 + 1)&lt;br /&gt;&lt;br /&gt;  -- Get the day, month and year&lt;br /&gt;  SELECT @day    = LTRIM(RTRIM(LEFT(@str, @index1 - 1)))&lt;br /&gt;  SELECT @month  = LTRIM(RTRIM(SUBSTRING(@str, (@index1 + 1), (@index2 - @index1) - 1)))&lt;br /&gt;  SELECT @year   = LTRIM(RTRIM(RIGHT(@str, (LEN(@str) - @index2))))&lt;br /&gt;&lt;br /&gt;  -- Convert the values to integer representations (will throw an error if they can't be converted)&lt;br /&gt;  SELECT @iDay   = CAST(@day AS TINYINT)&lt;br /&gt;  SELECT @iMonth = CAST(@month AS TINYINT)&lt;br /&gt;  SELECT @iYear  = CAST(@year AS SMALLINT)&lt;br /&gt;&lt;br /&gt;  -- Swap the day and month if they're obviously in the wrong format&lt;br /&gt;  IF @iMonth &gt; 12&lt;br /&gt;  BEGIN&lt;br /&gt;    SELECT @iSwap  = @iMonth&lt;br /&gt;    SELECT @iMonth = @iDay&lt;br /&gt;    SELECT @iDay   = @iSwap&lt;br /&gt;  END&lt;br /&gt;&lt;br /&gt;  -- Convert back to string representations&lt;br /&gt;  SELECT @day    = CAST(@iDay AS VARCHAR(2))&lt;br /&gt;  SELECT @month  = CAST(@iMonth AS VARCHAR(2))&lt;br /&gt;  SELECT @year   = CAST(@iYear AS VARCHAR(4))&lt;br /&gt;&lt;br /&gt;  -- If the day and/or month and/or year are a single digit, prefix with a zero&lt;br /&gt;  SELECT @day    = CASE WHEN LEN(@day)   = 1 THEN '0' + @day   ELSE @day   END&lt;br /&gt;  SELECT @month  = CASE WHEN LEN(@month) = 1 THEN '0' + @month ELSE @month END&lt;br /&gt;  SELECT @year   = CASE WHEN LEN(@year)  = 1 THEN '0' + @year  ELSE @year  END&lt;br /&gt;&lt;br /&gt;  -- If the year is only 2 digits long, prefix with '19' or '20' (depending on the boundary)&lt;br /&gt;  IF LEN(@year) = 2 SELECT @year = CASE WHEN @iYear &lt; @boundary THEN '20' + @year ELSE '19' + @year END&lt;br /&gt;&lt;br /&gt;  -- Build the cleaned up date string, with the month number converted to a string expression&lt;br /&gt;  SELECT @return = @day + '-'&lt;br /&gt;                 + CASE @month&lt;br /&gt;                     WHEN '01' THEN 'JAN'&lt;br /&gt;                     WHEN '02' THEN 'FEB'&lt;br /&gt;                     WHEN '03' THEN 'MAR'&lt;br /&gt;                     WHEN '04' THEN 'APR'&lt;br /&gt;                     WHEN '05' THEN 'MAY'&lt;br /&gt;                     WHEN '06' THEN 'JUN'&lt;br /&gt;                     WHEN '07' THEN 'JUL'&lt;br /&gt;                     WHEN '08' THEN 'AUG'&lt;br /&gt;                     WHEN '09' THEN 'SEP'&lt;br /&gt;                     WHEN '10' THEN 'OCT'&lt;br /&gt;                     WHEN '11' THEN 'NOV'&lt;br /&gt;                     WHEN '12' THEN 'DEC'&lt;br /&gt;                   END&lt;br /&gt;                 + '-' + @year&lt;br /&gt;&lt;br /&gt;  -- Done&lt;br /&gt;  RETURN CAST(@return AS DATETIME)&lt;br /&gt;&lt;br /&gt;END&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Example of usage:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;SELECT dbo.f_convert_str_to_date('21/8/01')&lt;br /&gt;&lt;/code&gt;</description>
      <pubDate>Mon, 14 Nov 2005 00:34:44 GMT</pubDate>
      <guid>http://snippets.dzone.com/posts/show/887</guid>
      <author>rgedwards (Rich Edwards (rich at semantise dot com))</author>
    </item>
    <item>
      <title>SqlServer table structure with Information_Schema</title>
      <link>http://snippets.dzone.com/posts/show/815</link>
      <description>&lt;code&gt;&lt;br /&gt;SELECT COLUMN_NAME,&lt;br /&gt;       DATA_TYPE,&lt;br /&gt;       CHARACTER_MAXIMUM_LENGTH,&lt;br /&gt;       NUMERIC_PRECISION,&lt;br /&gt;       NUMERIC_SCALE,&lt;br /&gt;       IS_NULLABLE,&lt;br /&gt;       COLUMNPROPERTY(OBJECT_ID(TABLE_NAME), COLUMN_NAME, 'IsIdentity') AS IS_AUTOINCREMENT,&lt;br /&gt;       COLUMN_DEFAULT&lt;br /&gt;FROM   INFORMATION_SCHEMA.COLUMNS&lt;br /&gt;WHERE  TABLE_NAME = 'xxxxxxxx'&lt;br /&gt;ORDER BY ORDINAL_POSITION&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;Edit: The "system_function_schema.fn_datadictionary" snippet will create a system function in SQL Server that returns a data dictionary for any database on the server (http://www.bigbold.com/snippets/posts/show/1175).</description>
      <pubDate>Tue, 18 Oct 2005 17:45:28 GMT</pubDate>
      <guid>http://snippets.dzone.com/posts/show/815</guid>
      <author>ms_michel (Michel)</author>
    </item>
    <item>
      <title>Replace multiple spaces with single spaces</title>
      <link>http://snippets.dzone.com/posts/show/771</link>
      <description>This work is licensed under a Creative Commons Attribution 2.5 License.&lt;br /&gt;&lt;code&gt;&lt;br /&gt;WHILE CHARINDEX('  ', @string) &gt; 0 SELECT @string = REPLACE(@string, '  ', ' ')&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;where @string is the parameter or variable.</description>
      <pubDate>Thu, 29 Sep 2005 23:22:32 GMT</pubDate>
      <guid>http://snippets.dzone.com/posts/show/771</guid>
      <author>rgedwards (Rich Edwards (rich at semantise dot com))</author>
    </item>
    <item>
      <title>Date Literals in SQL</title>
      <link>http://snippets.dzone.com/posts/show/756</link>
      <description>Due to international issues, there are many ways of representing a date in SQL code.  I prefer to use odbc canonical.&lt;br /&gt;&lt;br /&gt;dates&lt;br /&gt;&lt;code&gt;&lt;br /&gt;{d 'yyyy-mm-dd'}&lt;br /&gt;{d '2001-12-31'}&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;timestamps&lt;br /&gt;&lt;code&gt;&lt;br /&gt;{ts 'yyyy-mm-dd hh:mm:ss'}&lt;br /&gt;{ts '2001-12-31 00:00:00'}&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;times&lt;br /&gt;&lt;code&gt;&lt;br /&gt;{t 'hh:mm:ss'}&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Don't let the ODBC in the name fool you, these work in Microsoft SQL Server, and through ODBC connections.&lt;br /&gt;I've tested it in Query Analyzer, Stored Procedures, ADO code (both OLEDB and ODBC providers), ADO.Net code (both SQLClient and ODBC).&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;See Microsoft reference:&lt;br /&gt;http://msdn.microsoft.com/library/default.asp?url=/library/en-us/odbc/htm/odbcjetdate_time_and_timestamp_literals.asp&lt;br /&gt;&lt;br /&gt;It is a pity that there isn't some sort of SQL standard for date representation. Or maybe there is and I don't know it?</description>
      <pubDate>Wed, 21 Sep 2005 05:04:46 GMT</pubDate>
      <guid>http://snippets.dzone.com/posts/show/756</guid>
      <author>Will_Rickards (Will Rickards)</author>
    </item>
    <item>
      <title>Define Identity value for SqlServer</title>
      <link>http://snippets.dzone.com/posts/show/755</link>
      <description>&lt;code&gt;&lt;br /&gt;SET IDENTITY_INSERT MyTable ON;&lt;br /&gt;INSERT INTO MyTable&lt;br /&gt;    (MyIdentityField, MyFirstField, MySecondField)&lt;br /&gt;VALUES&lt;br /&gt;    (12345, 'ABCDE', 'etc...');&lt;br /&gt;SET IDENTITY_INSERT MyTable OFF;&lt;br /&gt;&lt;/code&gt;</description>
      <pubDate>Wed, 21 Sep 2005 01:12:30 GMT</pubDate>
      <guid>http://snippets.dzone.com/posts/show/755</guid>
      <author>ms_michel (Michel)</author>
    </item>
    <item>
      <title>Literal DateTime for SqlServer</title>
      <link>http://snippets.dzone.com/posts/show/754</link>
      <description>&lt;code&gt;&lt;br /&gt;CONVERT(DATETIME, 'yyyymmdd', 112)&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;112 -&gt; ISO date&lt;br /&gt;cf. http://msdn.microsoft.com/library/default.asp?url=/library/en-us/tsqlref/ts_ca-co_2f3o.asp&lt;br /&gt;----------&lt;br /&gt;Edit: a better solution !&lt;br /&gt;&lt;code&gt;&lt;br /&gt;{d 'yyyy-mm-dd'}&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;Thanks to Wild Richard (http://www.bigbold.com/snippets/posts/show/756)</description>
      <pubDate>Wed, 21 Sep 2005 00:42:19 GMT</pubDate>
      <guid>http://snippets.dzone.com/posts/show/754</guid>
      <author>ms_michel (Michel)</author>
    </item>
    <item>
      <title>Convert a number from any Base (between 2 and 36) to Base 10</title>
      <link>http://snippets.dzone.com/posts/show/708</link>
      <description>@base can be anything from 2 to 36. This work is licensed under a Creative Commons Attribution 2.5 License.&lt;br /&gt;&lt;code&gt;&lt;br /&gt;CREATE FUNCTION dbo.f_convert_to_base10&lt;br /&gt;  (@string VARCHAR(255), @base TINYINT)&lt;br /&gt;RETURNS INT AS &lt;br /&gt;BEGIN&lt;br /&gt;&lt;br /&gt;  -- Declarations&lt;br /&gt;  DECLARE @return INT&lt;br /&gt;  DECLARE @len INT&lt;br /&gt;  DECLARE @finished BIT&lt;br /&gt;  DECLARE @pos INT&lt;br /&gt;  DECLARE @thischar CHAR(1)&lt;br /&gt;  DECLARE @thisasc INT&lt;br /&gt;  DECLARE @val INT&lt;br /&gt;&lt;br /&gt;  -- Initialise&lt;br /&gt;  SELECT @base     = CASE WHEN @base &lt; 2 OR @base IS NULL THEN 2 WHEN @base &gt; 36 THEN 36 ELSE @base END&lt;br /&gt;  SELECT @return   = 0&lt;br /&gt;  SELECT @finished = 0&lt;br /&gt;  SELECT @string   = UPPER(@string)&lt;br /&gt;  SELECT @len      = DATALENGTH(@string)&lt;br /&gt;&lt;br /&gt;  -- Failsafe&lt;br /&gt;  IF @len = 0&lt;br /&gt;     SELECT @finished = 1&lt;br /&gt;&lt;br /&gt;  -- Loop over all characters: capitalise first character and those after spaces, replace underscores with spaces&lt;br /&gt;  SELECT @pos = 0&lt;br /&gt;&lt;br /&gt;  WHILE @finished = 0&lt;br /&gt;  BEGIN&lt;br /&gt;&lt;br /&gt;    SELECT @pos = @pos + 1&lt;br /&gt;&lt;br /&gt;    IF @pos &gt; @len&lt;br /&gt;&lt;br /&gt;       -- If we've run out of characters, we're done&lt;br /&gt;       SELECT @finished = 1&lt;br /&gt;&lt;br /&gt;    ELSE&lt;br /&gt;    BEGIN&lt;br /&gt;&lt;br /&gt;       -- Get the character (from right to left)&lt;br /&gt;       SELECT @thischar = SUBSTRING(@string, (@len - (@pos - 1)), 1)&lt;br /&gt;&lt;br /&gt;       -- Get the character's ASCII value&lt;br /&gt;       SELECT @thisasc  = ASCII(@thischar)&lt;br /&gt;&lt;br /&gt;       -- Convert to a numerical value&lt;br /&gt;       SELECT @val = CASE&lt;br /&gt;                       WHEN @thisasc BETWEEN 48 AND 57 -- '0' AND '9'&lt;br /&gt;                         THEN @thisasc - 48&lt;br /&gt;                       WHEN @thisasc BETWEEN 65 AND 90 -- 'A' (= decimal 10) AND 'Z'&lt;br /&gt;                         THEN @thisasc - 65 + 10&lt;br /&gt;                       ELSE 0 END&lt;br /&gt;&lt;br /&gt;       -- Add this portion on&lt;br /&gt;       SELECT @return = @return + (POWER(@base, (@pos - 1)) * @val)&lt;br /&gt;&lt;br /&gt;    END&lt;br /&gt;&lt;br /&gt;  END&lt;br /&gt;&lt;br /&gt;  -- Done&lt;br /&gt;  RETURN @return&lt;br /&gt;&lt;br /&gt;END&lt;br /&gt;GO&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Example of usage:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;SELECT 'FFFF' AS [hex], dbo.f_convert_to_base10('FFFF', 16) AS [decimal]&lt;br /&gt;&lt;/code&gt;</description>
      <pubDate>Wed, 14 Sep 2005 22:42:23 GMT</pubDate>
      <guid>http://snippets.dzone.com/posts/show/708</guid>
      <author>rgedwards (Rich Edwards (rich at semantise dot com))</author>
    </item>
  </channel>
</rss>
