Register
Login
 
 Search Articles * TableUDFs  
Creating and Using Table UDFs - By Arthur Fuller
Creating and Using Table UDFs in SQL 2000 and SQL 2005
by Arthur Fuller

Table UDFs (user-defined functions) are one of my favorite features of SQL 2000 and 2005. If you’ve never used them, you may be in for a surprise. A table UDF is similar to a stored procedure that returns a recordset. You might do something as simple as:

<code>

CREATE PROCEDURE simple_ap

( @cityID integer )

AS

       SELECT CustomerID, CompanyName

       FROM Customers

       WHERE Customers.CityID = @cityID

</code>

The result is a recordset with two columns and zero or more rows.

Unfortunately, there is no easy way to re-use the results of such a stored procedure. You can’t feed the recordset to another procedure, for example. Nor can you JOIN the results to a table, view or another recordset. If you could, then your opportunities to re-use code would multiply significantly, and you could design your code with this in mind.

Enter the table UDF. This construct enables you to treat the result set just as if it were a genuine table or view – you can JOIN it to other objects, add a WHERE clause to it, and much more.

In SQL 2000, the syntax to create a table UDF is:

<code>

CREATE FUNCTION [owner].[function_name]

(

       @parm1 <datatpe> = <default>

)

RETURNS TABLE

AS

       RETURN

       (

       SELECT <column1, column2, ...>

       FROM <table, view, etc.>

       WHERE <some condition applies>   -- optional clauses

)

</code>

To turn the stored procedure above into a table UDF, just substitute the appropriate chunks for the place markers in the UDF syntax, so that it looks like this:

<code>

CREATE FUNCTION [dbo].[Customers_By_City_Select]    -- denotes table UDF

(

       @city nvarchar(15)

)

RETURNS TABLE

AS

       RETURN

       (

       SELECT CustomerID, CompanyName

       FROM dbo.Customers

       WHERE Customers.City = @city

       )

</code>

The result set is identical, but with some cool new advantages. First, using the procedure instead, a call would look like:

<code>

EXEC simple_ap 12345

</code>

A call to the UDF would look like this:

<code>

SELECT * FROM Customers_By_City_Select ('Berlin')

</code>

Note that using the UDF, we can add the word DISTINCT to the call, which I did to reduce the result set here:

<code>

ALFKI  Alfreds Futterkiste

ANATR  Ana Trujillo Emparedados y helados

ANTON  Antonio Moreno Taquería

AROUT  Around the Horn

</code>

   This not only demonstrates that a table function is for all intents an actual table. A procedure that allowed this flexibility would have to be more complicated.

The fun is just beginning. We can select any subset of the columns returned by the function:

<code>

SELECT CustomerID FROM Customers_By_City_Select ('Berlin')

</code>

The coolest aspect of table functions is their table-ness: you can JOIN to tables, views and other table functions, referring to the UDF just as if it were a table:

<code>

SELECT Customers_By_City_Select.CustomerID, OrderID 

FROM Customers_By_City_Select ('Berlin')

INNER JOIN Orders ON Orders.CustomerID = Customers_By_City_Select.CustomerID</code>

</code>

This returns the following result set:

<code>

ALFKI  10643

ALFKI  10692

ALFKI  10702

ALFKI  10835

ALFKI  10952

ALFKI  11011

</code>

This ability facilitates what I like to call atomic queries. An atomic query returns results from one table (or view). By combining several atomic queries, you can create a molecular query (consisting of several atoms). Table UDFs enable you to reach a level of granularity and reusability that is impossible to achieve using stored procedures.

 

Site was built using www.BuildPortal.com Portal Generator