The following
sections discuss in more detail the CREATE FUNCTION syntax and
the types of operations allowed in functions. These sections also show
how to create and manage T-SQL functions by using SQL Server Management
Studio (SSMS).
1. Creating User-Defined Functions
You create T-SQL functions by using T-SQL statements. You can enter the T-SQL code in sqlcmd,
SSMS, or any other third-party query tool that allows you to enter ad
hoc T-SQL code. The following sections first show the basic syntax for
creating functions and then show how you can create functions by using
the features of SSMS.
Creating T-SQL Functions
User-defined functions can accept 0–2,100 input
parameters but can return only a single result: either a single scalar
value or table result set.
The T-SQL syntax for the CREATE FUNCTION command for scalar functions is as follows:
CREATE FUNCTION [ schema_name. ] function_name
( [ { @parameter_name [AS] [ schema_name.]scalar_datatype [ = default ] }
[ ,...n ] ] )
RETURNS scalar_datatype
[ WITH { [ ENCRYPTION ]
[ , SCHEMABINDING ]
[ , RETURNS NULL ON NULL INPUT | CALLED ON NULL INPUT ]
[ , EXECUTE_AS_Clause ]
} ]
[ AS ]
BEGIN
SQL_Statements
RETURN scalar_expression
END
The syntax for the CREATE FUNCTION command for inline table-valued functions is as follows:
CREATE FUNCTION [ schema_name. ] function_name
( [ { @parameter_name [AS] [ schema_name.]scalar_datatype [ = default ] }
[ ,...n ] ] )
RETURNS TABLE
[ WITH { [ ENCRYPTION ]
[ , SCHEMABINDING ]
[ , RETURNS NULL ON NULL INPUT | CALLED ON NULL INPUT ]
[ , EXECUTE_AS_Clause ]
} ]
[ AS ]
RETURN [ ( ] select-stmt [ ) ]
The syntax for the CREATE FUNCTION command for multistatement table-valued functions is as follows:
CREATE FUNCTION [ schema_name. ] function_name
( [ { @parameter_name [AS] [ schema_name.]scalar_datatype [ = default ] }
[ ,...n ] ] )
RETURNS @table_variable TABLE ( { column_definition | table_constraint }
[ ,...n ] )
[ WITH { [ ENCRYPTION ]
[ , SCHEMABINDING ]
[ , RETURNS NULL ON NULL INPUT | CALLED ON NULL INPUT ]
[ , EXECUTE_AS_Clause ]
} ]
[ AS ]
BEGIN
SQL_Statements
RETURN
END
The types of SQL statements allowed in a function include the following:
DECLARE statements to define variables and cursors that are local to the function.
Assignments of values to variables that are local to the function, using the SET command or an assignment select.
Cursor operations on local cursors that are declared, opened, closed, and de-allocated within the function. FETCH statements must assign values to local variables by using the INTO clause.
Control-of-flow statements such as IF, ELSE, WHILE, GOTO, and so on, excluding the TRY...CATCH statements.
UPDATE, INSERT, and DELETE statements that modify table variables defined within the function.
EXECUTE statements that call an extended stored procedure. (Any results returned by the extended stored procedure are discarded.)
Other user-defined functions, up to a maximum nesting level of 32.
If you specify the ENCRYPTION option, the SQL statements used to define the function are stored encrypted in the syscomments table. This prevents anyone from viewing the function source code in the database.
Note
If you choose to encrypt the function code, you
should be sure to save a copy of the script used to create the function
to a file outside the database, in case you ever need to modify the
function or re-create it. After the source code for the function is
encrypted, you cannot extract the original unencrypted source code from
the database.
If a function is created with the SCHEMABINDING
option, the database objects that the function references cannot be
altered or dropped unless the function is dropped first or the schema
binding of the function is removed, using the ALTER FUNCTION command and without specifying the SCHEMABINDING option. A CREATE FUNCTION statement with the SCHEMABINDING option specified fails unless all the following conditions are met:
Any user-defined functions and views referenced within the function are also schema bound.
Any objects referenced by the function are referenced using a two-part name (schema.object_name).
The function and the objects it references belong to the same database.
The user executing the CREATE FUNCTION statement has REFERENCES permission on all database objects that the function references.
You can specify the SCHEMABINDING option only for T-SQL functions. The following example modifies the AveragePricebyType2 function by specifying the SCHEMABINDING option:
ALTER FUNCTION AveragePricebyType2 (@price money = 0.0)
RETURNS @table table (type varchar(12) null, avg_price money null)
with schemabinding
AS
begin
insert @table
SELECT type, avg(price) as avg_price
FROM dbo.titles
group by type
having avg(price) > @price
return
end
The following example shows what happens if you try to modify a column in the titles table referenced by the function:
alter table titles alter column price smallmoney null
go
Msg 5074, Level 16, State 1, Line 1
The object 'AveragePricebyType2' is dependent on column 'price'.
Msg 5074, Level 16, State 1, Line 1
The statistics 'price' is dependent on column 'price'.
Msg 4922, Level 16, State 9, Line 1
ALTER TABLE ALTER COLUMN price failed because one or more objects access this
column.
If the RETURNS NULL ON NULL INPUT option is specified, the function automatically returns NULL as a result, without invoking the function body. If this option is not specified, the default option of CALLED ON NULL INPUT is applied. The following example shows the difference between these two options:
CREATE FUNCTION striptime (@datetimeval datetime)
RETURNS datetime
AS
BEGIN
DECLARE @dateval datetime
SELECT @dateval = convert(date, isnull(@datetimeval, getdate()))
RETURN @dateval
END
GO
CREATE FUNCTION striptime2(@datetimeval datetime)
RETURNS datetime
WITH RETURNS NULL ON NULL INPUT
AS
BEGIN
DECLARE @dateval datetime
SELECT @dateval = convert(date, isnull(@datetimeval, getdate()))
RETURN @dateval
END
GO
select dbo.striptime(NULL), dbo.striptime2(NULL)
----------------------- -----------------------
2006-06-05 00:00:00.000 NULL
The EXECUTE AS
clause allows you to specify the security context under which the
user-defined function will execute. This way, you can control which user
account SQL Server uses to validate permissions on any database objects
referenced by the function. This option cannot be specified for inline
table-valued functions.
Another key restriction on user-defined functions is
that SQL statements within a function cannot generate side effects; that
is, a user-defined function cannot generate permanent changes to any
resource whose scope extends beyond the function. For example, a
function cannot modify data in a table, operate on cursors not local to
the function, create or drop database objects, issue transaction control
statements, or generate a result set other than the defined function
result via a SELECT statement or an extended stored procedure
that would be returned to the user. The only changes that can be made by
the SQL statements in a function are to the objects local to the
function, such as local cursors or variables.
A new feature in SQL Server 2008 is that you can now
include most built-in system functions within a user-defined function,
even ones that are nondeterministic (that is, functions that can return
different data values on each call). For example, the getdate()
function is considered nondeterministic because even though it is
always invoked with the same argument, it returns a different value each
time it is executed. However, the following nondeterministic built-in
functions are still not allowed in user-defined functions:
newid()
newsequentialid()
rand()
textptr()
User-defined functions can also call other
user-defined functions, with a limit of 32 levels of nesting. Nesting of
functions can help improve the modularity and reusability of function code.
CREATE FUNCTION dbo.getonlydate()
RETURNS datetime
as
BEGIN
DECLARE @date datetime
SET @date = dbo.striptime( getdate())
RETURN @date
end