N S

Novick Software Management • Design • Programming • Training • Consulting

   

 

 

SQL Server T-SQL User-Defined Function of the Week

Create a Column List for Dynamic SQL

Volume 1 Number 43   September 9, 2003

Check out the UDF Frequently Asked Questions at:
http://www.novicksoftware.com/UdfOfWeek/UDF_FAQ.htm

To ask a UDF related question or to contribute a UDF,
send e-mail to udf@NovickSoftware.com

Sign up for this newsletter at:
http://www.novicksoftware.com/UdfOfWeek/UDFofWeekSignup.htm
In an interesting article on SQLTeam.com Bill Graziano writes
about an interview question that had been posed to one of the
sites readers:

How can you retrieve the first N number of fields using sql 
statement without using field names?

Bill's solution is in the article that he wrote about it here:
http://www.sqlteam.com/item.asp?ItemID=2971

His solution to the problem is this script:
/------- Start copying below this line -------------------------\
set nocount on

Declare @TableName varchar(128), @ColumnList varchar(1000)
Declare @SQL varchar(1000)
set @TableName = 'authors'

SELECT @ColumnList = COALESCE(@ColumnList + ', ', '') + column_name 
FROM INFORMATION_SCHEMA.Columns
WHERE Ordinal_position <= 10
and table_name = @TableName

Set @SQL = 'Select ' + @ColumnList + ' from ' + @TableName

Exec (@SQL)
GO
\-------Stop copying above this line ---------------------------/

As I looked at it I realized that I had a similar solution
available in a UDF, udf_Tbl_ColumnList.  My original UDF
didn't limit the number of columns.  But that's an easy 
enchantment that's now included.

First, here's the CREATE FUNCTION script:
/------- Start copying below this line -------------------------\
SET QUOTED_IDENTIFIER ON 
SET ANSI_NULLS ON 
GO

CREATE  FUNCTION dbo.udf_Tbl_ColumnList (
    
    @TableName sysname -- Name of the table
  , @Prefix sysname = NULL -- Prefix to prepend to each column
     -- NULL indicates no prefix. Brackets can be used around
     -- prefix. Don't include the period that separates the 
     -- prefix from the column name. Generally used for an alias.
  , @Owner sysname = NULL -- Table owner name, NULL for none
  , @NumColumns int = 0 -- Number of columns, 0 for all
)  RETURNS nvarchar(4000) -- Column names quoted.
/*
* Creates a quoted list of the columns in a table, suitable for
* creation of a dynamic SQL statement. Depends on 
* INFORMATION_SCHEMA.COLUMNS.
*
* Related information: See article on a similar non-UDF solution
*                  http://www.sqlteam.com/item.asp?ItemID=2971
*
* Example:
DECLARE @TableName sysname
SELECT TOP 1 @TableName = TABLE_NAME 
    FROM INFORMATION_SCHEMA.TABLES ORDER BY TABLE_NAME
select @TableName as [Table]
    , dbo.udf_Tbl_ColumnList(@TableName, '[alias]', NULL, 3)
* 
* History:
* When          Who     Description
* ------------- ------- ----------------------------------------
* 2003-08-13    ASN     Added @NumColumns parameter.
* 2003-05-10    ASN     Initial Coding
*
* © Copyright 2003 Andrew Novick http://www.NovickSoftware.com
* You may use this function in any of your SQL Server databases
* including databases that you sell, so long as they contain 
* other unrelated database objects. You may not publish this 
* UDF either in print or electronically.
* Published in the T-SQL UDF of the Week Vol 1 #43 9/9/03
http://www.NovickSoftware.com/UDFofWeek/UDFofWeek.htm
****************************************************************/
AS BEGIN

DECLARE @Result nvarchar(4000) -- the result 

SET @Result = '' -- So it's not a null string

SELECT @Result = 
         -- After 1st column, add a comma 
         CASE WHEN LEN(@Result) > 0 
              THEN @Result + ', ' 
              ELSE '' 
              END

         -- Add the prefix if it's specified in the call
       + CASE WHEN @Prefix IS NOT NULL and LEN(@Prefix) > 0
              THEN @Prefix + '.'
              ELSE ''
              END
        -- Quote the column name
      + fn_replquotename (COLUMN_NAME)

    FROM INFORMATION_SCHEMA.Columns
    WHERE TABLE_NAME = @TableName
      AND (@Owner IS NULL or @Owner = TABLE_SCHEMA)
      AND (@NumColumns IS NULL or @NumColumns<1 
              or ORDINAL_POSITION <= @NumColumns)
    ORDER BY Ordinal_Position

RETURN @Result
END
GO

GRANT EXEC ON [dbo].[udf_Tbl_ColumnList] TO [PUBLIC]
GO
\-------Stop copying above this line ---------------------------/

The typical use for this function is when creating dynamic SQL.
So if you've created the UDF in PUBS, you could select the 
first 4 columns of the Authors table with dynamic SQL.  First,
let's look at the sql statement that's going to query the
table:

/------- Start copying below this line -------------------------\
DECLARE @SQL as nvarchar(4000)
SET @SQL = 'SELECT ' 
         + dbo.udf_Tbl_ColumnList ('authors', '[a]', default, 4)
         + ' FROM Authors a '

PRINT @SQL
GO
\-------Stop copying above this line ---------------------------/
(Results - Reformatted with a little wrapping)
SELECT [a].[au_id], [a].[au_lname], [a].[au_fname], [a].[phone] 
     FROM Authors a 

I've used an alias to illustrate that feature.  Since there's
only one table in the query it isn't necessary.

Next, let's create the SQL statement again and feed it to EXEC:
/------- Start copying below this line -------------------------\
DECLARE @SQL as nvarchar(4000)
SET @SQL = 'SELECT ' 
         + dbo.udf_Tbl_ColumnList ('authors', '[a]', default, 4)
         + ' FROM Authors a '

EXEC (@SQL)
GO
\-------Stop copying above this line ---------------------------/
(Results - abridged)
au_id       au_lname         au_fname             phone       
----------- ---------------- -------------------- ------------
172-32-1176 White            Johnson              408 496-7223
213-46-8915 Green            Marjorie             415 986-7020
238-95-7766 Carson           Cheryl               415 548-7723
267-41-2394 O'Leary          Michael              408 286-2428
274-80-9391 Straight         Dean                 415 834-2919
341-22-1782 Smith            Meander              913 843-0462
409-56-7008 Bennet           Abraham              415 658-9932
427-17-2319 Dull             Ann                  415 836-7128
472-27-2349 Gringlesby       Burt                 707 938-6445
.....

There are a couple of interesting things about the function:

1) It allows for an optional alias, which might be useful.
2) It allows for specification of an owner. I always have all
   tables owned by dbo, but there are times when it could come
   into play.

In addition to these features there are a few differences in the
way udf_Tbl_ColumnList is written from the solution in the 
article:

1) I used CASE instead of COALESCE, but this is mostly style.
2) I used an ORDER BY clause.  Information_SCHEMA always seems
   to come out in the correct order but I don't think it's 
   guaranteed.
3) I used the undocumented system UDF fn_replquotename. I could
   have just added the leading and trailing brackets.  I think 
   fn_replquotename is used because the UDF was written while 
   I wrote the chapter in my book about undocumented system UDFs.
   
While I'm at it, did I mention the book?

SQL Server User-Defined Functions
by Andrew Novick

Will be published this fall by Wordware! It's finished and into
the publisher.  I'll let you know when it comes out.
Sign up for this newsletter at:
http://www.novicksoftware.com/UdfOfWeek/UDFofWeekSignup.htm


Do you have a great UDF that you'd like to share?  Or maybe you
have a T-SQL problem that you think could be solved by a UDF
but you don't know how? Send them to:

UDF@NovickSoftware.com 

and they might be published in this newsletter.  I try and 
respond to every request that I get.  

Thanks,  
Andrew Novick


RSS as HTML

Personal Blog

 
New Tips:

Loading SQL Profiler trace (.trc) files with fn_trace_gettrace

Upcoming
Presentations:

Big Data:
Working with Terabytes
in SQL Server

July 9 '08


Full Schedule