CREATE 函数 (Transact-SQL)

适用于:SQL ServerAzure SQL 数据库Azure SQL 托管实例

创建用户定义函数 (UDF),该函数是 Transact-SQL 或公共语言运行时 (CLR) 例程。 用户定义的函数接受参数,执行作(如复杂计算),并将该作的结果作为值返回。 返回值可以是标量(单个)值或表。 使用此语句创建可按以下方式使用的可重用例程:

  • 在 Transact-SQL 语句中,例如 SELECT
  • 在调用函数
  • 在另一个用户定义函数的定义中
  • 参数化视图或改进索引视图的功能
  • 定义表中的列
  • 定义 CHECK 对列的约束
  • 替换存储过程
  • 使用内联函数作为安全策略的筛选条件谓词

本文讨论了 .NET Framework CLR 与 SQL Server 的集成。 CLR 集成不适用于 Azure SQL 数据库。

对于 Azure Synapse Analytics 或 Microsoft Fabric,请参阅 CREATE FUNCTION(Azure Synapse Analytics 和 Microsoft Fabric)。

Transact-SQL 语法约定

语法

Transact-SQL 标量函数的语法。

CREATE [ OR ALTER ] FUNCTION [ schema_name. ] function_name
( [ { @parameter_name [ AS ] [ type_schema_name. ] parameter_data_type [ NULL ]
 [ = default ] [ READONLY ] }
    [ , ...n ]
  ]
)
RETURNS return_data_type
    [ WITH <function_option> [ , ...n ] ]
    [ AS ]
    BEGIN
        function_body
        RETURN scalar_expression
    END
[ ; ]

Transact-SQL 内联表值函数的语法。

CREATE [ OR ALTER ] FUNCTION [ schema_name. ] function_name
( [ { @parameter_name [ AS ] [ type_schema_name. ] parameter_data_type [ NULL ]
    [ = default ] [ READONLY ] }
    [ , ...n ]
  ]
)
RETURNS TABLE
    [ WITH <function_option> [ , ...n ] ]
    [ AS ]
    RETURN [ ( ] select_stmt [ ) ]
[ ; ]

Transact-SQL 多语句表值函数的语法。

CREATE [ OR ALTER ] FUNCTION [ schema_name. ] function_name
( [ { @parameter_name [ AS ] [ type_schema_name. ] parameter_data_type [ NULL ]
    [ = default ] [ READONLY ] }
    [ , ...n ]
  ]
)
RETURNS @return_variable TABLE <table_type_definition>
    [ WITH <function_option> [ , ...n ] ]
    [ AS ]
    BEGIN
        function_body
        RETURN
    END
[ ; ]

Transact-SQL 函数子句的语法。

<function_option> ::=
{
    [ ENCRYPTION ]
  | [ SCHEMABINDING ]
  | [ RETURNS NULL ON NULL INPUT | CALLED ON NULL INPUT ]
  | [ EXECUTE_AS_Clause ]
  | [ INLINE = { ON | OFF } ]
}

<table_type_definition> ::=
( { <column_definition> <column_constraint>
  | <computed_column_definition> }
    [ <table_constraint> ] [ , ...n ]
)
<column_definition> ::=
{
    { column_name data_type }
    [ [ DEFAULT constant_expression ]
      [ COLLATE collation_name ] | [ ROWGUIDCOL ]
    ]
    | [ IDENTITY [ (seed , increment ) ] ]
    [ <column_constraint> [ ...n ] ]
}

<column_constraint> ::=
{
    [ NULL | NOT NULL ]
    { PRIMARY KEY | UNIQUE }
      [ CLUSTERED | NONCLUSTERED ]
      [ WITH FILLFACTOR = fillfactor
        | WITH ( <index_option> [ , ...n ] )
      [ ON { filegroup | "default" } ] ]
  | [ CHECK ( logical_expression ) ] [ , ...n ]
}

<computed_column_definition> ::=
column_name AS computed_column_expression

<table_constraint> ::=
{
    { PRIMARY KEY | UNIQUE }
      [ CLUSTERED | NONCLUSTERED ]
      ( column_name [ ASC | DESC ] [ , ...n ]
        [ WITH FILLFACTOR = fillfactor
        | WITH ( <index_option> [ , ...n ] )
  | [ CHECK ( logical_expression ) ] [ , ...n ]
}

<index_option> ::=
{
    PAD_INDEX = { ON | OFF }
  | FILLFACTOR = fillfactor
  | IGNORE_DUP_KEY = { ON | OFF }
  | STATISTICS_NORECOMPUTE = { ON | OFF }
  | ALLOW_ROW_LOCKS = { ON | OFF }
  | ALLOW_PAGE_LOCKS = { ON | OFF }
}

CLR 标量函数的语法。

CREATE [ OR ALTER ] FUNCTION [ schema_name. ] function_name
( { @parameter_name [ AS ] [ type_schema_name. ] parameter_data_type [ NULL ]
    [ = default ] }
    [ , ...n ]
)
RETURNS { return_data_type }
    [ WITH <clr_function_option> [ , ...n ] ]
    [ AS ] EXTERNAL NAME <method_specifier>
[ ; ]

CLR 表值函数的语法。

CREATE [ OR ALTER ] FUNCTION [ schema_name. ] function_name
( { @parameter_name [ AS ] [ type_schema_name. ] parameter_data_type [ NULL ]
    [ = default ] }
    [ , ...n ]
)
RETURNS TABLE <clr_table_type_definition>
    [ WITH <clr_function_option> [ , ...n ] ]
    [ ORDER ( <order_clause> ) ]
    [ AS ] EXTERNAL NAME <method_specifier>
[ ; ]

CLR 函数子句的语法。

<order_clause> ::=
{
   <column_name_in_clr_table_type_definition>
   [ ASC | DESC ]
} [ , ...n ]

<method_specifier> ::=
    assembly_name.class_name.method_name

<clr_function_option> ::=
{
    [ RETURNS NULL ON NULL INPUT | CALLED ON NULL INPUT ]
  | [ EXECUTE_AS_Clause ]
}

<clr_table_type_definition> ::=
( { column_name data_type } [ , ...n ] )

本机编译的标量用户定义函数的内存中 OLTP 语法。

CREATE [ OR ALTER ] FUNCTION [ schema_name. ] function_name
 ( [ { @parameter_name [ AS ] [ type_schema_name. ] parameter_data_type
    [ NULL | NOT NULL ] [ = default ] [ READONLY ] }
    [ , ...n ]
  ]
)
RETURNS return_data_type
     WITH <function_option> [ , ...n ]
    [ AS ]
    BEGIN ATOMIC WITH (set_option [ , ... n ] )
        function_body
        RETURN scalar_expression
    END

<function_option> ::=
{
  |  NATIVE_COMPILATION
  |  SCHEMABINDING
  | [ EXECUTE_AS_Clause ]
  | [ RETURNS NULL ON NULL INPUT | CALLED ON NULL INPUT ]
}

论据

或 ALTER

适用于:SQL Server 2016 (13.x) SP 1 及更高版本,以及 Azure SQL 数据库。

仅当函数已存在时,才有条件地更改该函数。

可选 OR ALTER 语法可用于 CLR,从 SQL Server 2016 (13.x) SP 1 CU 1 开始。

schema_name

用户定义函数所属的架构的名称。

function_name

用户定义函数的名称。 函数名称必须符合 标识符 规则,并且在数据库及其架构中必须是唯一的。

函数名称后需要括号,即使未指定参数也是如此。

@parameter_name

用户定义函数中的参数。 可以声明一个或多个参数。

一个函数最多可以有 2,100 个参数。 执行函数时,用户必须提供每个声明的参数的值,除非定义了参数的默认值。

通过使用 at 符号 (@) 作为第一个字符来指定参数名称。 参数名称必须符合标识符的规则。 参数是函数的本地参数;其他函数中可以使用相同的参数名称。 参数只能代替常量;它们不能用于代替表名、列名或其他数据库对象的名称。

ANSI_WARNINGS 在存储过程、用户定义函数中传递参数或在 Batch 语句中声明和设置变量时,不遵循。 例如,如果将一个变量定义为 char(3),然后将其值设置为大于三个字符,则数据会被截断为定义的大小,并且 INSERT 语句可以成功执行。

[ type_schema_name. ] parameter_data_type

参数数据类型,以及它所属的架构(可选)。 对于 Transact-SQL 函数,允许除 timestamp 数据类型之外的所有数据类型,包括 CLR 用户定义类型和用户定义表类型。 对于 CLR 函数,允许所有数据类型,包括 CLR 用户定义类型,但 textntextimage、用户定义的表类型和 timestamp 数据类型除外。 非标量类型( 游标)不能在 Transact-SQL 或 CLR 函数中指定为参数数据类型。

如果未指定 type_schema_name ,则数据库引擎将按以下顺序查找 scalar_parameter_data_type

  • 包含 SQL Server 系统数据类型名称的架构。
  • 当前数据库中当前用户的默认架构。
  • 当前数据库中的 dbo 架构。

[ = 默认 ]

参数的默认值。 如果定义了 默认值 ,则可以在不为该参数指定值的情况下执行该函数。

可以为 CLR 函数指定默认参数值, 但 varchar(max)varbinary(max) 数据类型除外。

当函数的参数具有默认值时,必须在调用函数以检索默认值时指定关键字 DEFAULT 。 此行为与在存储过程中使用具有默认值的参数不同,在存储过程中,省略参数也意味着默认值。 但是, DEFAULT 当使用 EXECUTE 语句调用标量函数时,该关键字不是必需的。

只读

指示无法在函数定义中更新或修改参数。 READONLY 对于用户定义的表类型参数 (TVP) 是必需的,不能用于任何其他参数类型。

return_data_type

标量用户定义函数的返回值。 对于 Transact-SQL 函数,允许除 timestamp 数据类型之外的所有数据类型,包括 CLR 用户定义类型。 对于 CLR 函数,允许使用除 textntextimagetimestamp 数据类型之外的所有数据类型,包括 CLR 用户定义类型。 非标量类型( cursortable)不能在 Transact-SQL 或 CLR 函数中指定为返回数据类型。

function_body

指定一系列 Transact-SQL 语句(它们一起不会产生副作用,例如修改表)定义函数的值。 function_body 仅用于标量函数和多语句表值函数 (MSTVF)。

在标量函数中, function_body 是一系列 Transact-SQL 语句,这些语句一起计算为标量值。

在 MSTVF 中, function_body 是一系列填充 TABLE return 变量的 Transact-SQL 语句。

scalar_expression

指定标量函数返回的标量值。

表格

指定表值函数 (TVF) 的返回值为表。 只有常量和 @local_variables 可以传递给 TVF。

在内联 TVF 中, TABLE 返回值是通过单个 SELECT 语句定义的。 内联函数没有关联的 return 变量。

在 MSTVF 中, @return_variable 是一个 TABLE 变量,用于存储和累积应作为函数值返回的行。 @ return_variable 只能为 Transact-SQL 函数指定,而不能为 CLR 函数指定。

select_stmt

定义内联表值函数 (TVF) 的返回值的单个 SELECT 语句。

订购 (<order_clause>)

指定从表值函数返回结果的顺序。 有关详细信息,请参阅本文后面的在 CLR 表值函数中使用排序顺序 部分。

外部名称 <method_specifier>assembly_nameclass_namemethod_name

适用于:SQL Server 2008 (10.0.x) SP 1 及更高版本。

指定创建的函数名称应引用的程序集和方法。

  • assembly_name - 必须与 列中SELECT * FROM sys.assemblies;的值name匹配。

    对帐单上使用 CREATE ASSEMBLY 的名称。

  • class_name - 必须与 列中SELECT * FROM sys.assembly_modules;的值assembly_name匹配。

    该值通常包含嵌入的句点或点。 在这种情况下,Transact-SQL 语法要求值用一对方括号 ()[] 或一对双引号 ()"" 括起来。

  • method_name - 必须与 列中SELECT * FROM sys.assembly_modules;的值method_name匹配。

    方法必须是静态的。

在 的典型示例中 MyFood.dll,所有类型都位于命名空间中 MyFoodEXTERNAL NAME 该值可以是 MyFood.[MyFood.MyClass].MyStaticMethod

默认情况下,SQL Server 无法执行 CLR 代码。 您可以创建、修改和删除引用公共语言运行时模块的数据库对象。 但是,在启用 clr enabled 选项之前,您无法在 SQL Server 中执行这些引用。 要启用此选项,请使用 sp_configure。 此选项在包含的数据库中不可用。

< > table_type_definition ( { <column_definition><column_constraint | <> computed_column_definition } [ <table_constraint> ] [ , ...n ] )

定义 Transact-SQL 函数的表数据类型。 表声明包括列定义和列或表约束。 该表始终放在主文件组中。

< > clr_table_type_definition ( { column_namedata_type } [ , ...n ] )

适用于:SQL Server 2008 (10.0.x) SP 1 及更高版本,以及 Azure SQL 数据库(在某些区域提供预览版)。

定义 CLR 函数的表数据类型。 表声明仅包括列名和数据类型。 该表始终放在主文件组中。

NULL |NOT NULL

仅支持本机编译的标量用户定义函数。 有关详细信息,请参阅 适用于 In-Memory OLTP 的标量 User-Defined 函数

本地编译

指示用户定义的函数是否是本机编译的。 本机编译的标量用户定义函数需要此参数。

从 ATOMIC 开始

对于本机编译的标量用户定义函数是必需的,并且仅支持。 有关更多信息,请参见 本机过程中的原子块

SCHEMABINDING

SCHEMABINDING 参数对于本机编译的标量用户定义函数是必需的。

以...身份执行

EXECUTE AS 对于本机编译的标量用户定义函数是必需的。

< > function_option ::= 和 <clr_function_option> ::=

指定函数具有以下一个或多个选项。

加密

适用于:SQL Server 2008 (10.0.x) SP 1 及更高版本。

指示数据库引擎将语句的原始 CREATE FUNCTION 文本转换为模糊格式。 模糊处理的输出在任何目录视图中都不会直接可见。 无权访问系统表或数据库文件的用户无法检索经过混淆处理的文本。 但是,该文本可供特权用户使用,这些用户可以通过 数据库管理员的 Diagnostic 连接 访问系统表,也可以直接访问数据库文件。 此外,可以将调试器附加到服务器进程的用户可以在运行时从内存中检索原始过程。 有关访问系统元数据的更多信息,请参阅 元数据可见性配置

使用此选项可防止函数作为 SQL Server 复制的一部分发布。 不能为 CLR 函数指定此选项。

SCHEMABINDING

指定函数绑定到它引用的数据库对象。 指定后 SCHEMABINDING ,不能以影响函数定义的方式修改基对象。 必须首先修改或删除函数定义本身,以删除对要修改的对象的依赖关系。

仅当发生以下作之一时,才会删除函数与其引用的对象的绑定:

  • 该函数被删除。
  • 使用 ALTER 带有 SCHEMABINDING option not specified的语句修改函数。

仅当满足以下条件时,函数才能进行架构绑定:

  • 该函数是一个 Transact-SQL 函数。
  • 函数引用的用户定义函数和视图也是架构绑定的。
  • 函数引用的对象使用由两部分组成的名称进行引用。
  • 该函数及其引用的对象属于同一个数据库。
  • 执行 CREATE FUNCTION 该语句的用户对函数引用的数据库对象具有 REFERENCES 权限。

在 NULL 输入时返回 NULL |在 NULL 输入时调用

OnNULLCall指定标量函数的属性。 如果未指定, CALLED ON NULL INPUT 则默认为 implation。 换句话说,即使 NULL 作为参数传递,函数体也会执行。

如果在 RETURNS NULL ON NULL INPUT CLR 函数中指定,则表示 SQL Server 可以在它收到的任何参数为 NULL时返回NULL,而无需实际调用函数的主体。 如果 中指定的 <method_specifier> CLR 函数的方法已经具有指示 RETURNS NULL ON NULL INPUT的自定义属性, CREATE FUNCTION 但该语句指示 CALLED ON NULL INPUT,则该 CREATE FUNCTION 语句优先。 OnNULLCall不能为 CLR 表值函数指定该属性。

以...身份执行

指定在其下执行用户定义函数的安全上下文。 因此,您可以控制 SQL Server 使用哪个用户帐户来验证函数引用的任何数据库对象的权限。

EXECUTE AS 不能为内联表值函数指定。

有关详细信息,请参阅 EXECUTE AS 子句(Transact-SQL)。

内联 = { ON |关闭 }

适用于: SQL Server 2019 (15.x) 及更高版本,以及 Azure SQL 数据库。

指定是否应内联此标量 UDF。 此子句仅适用于标量用户定义函数。 该 INLINE 子句不是必需的。 如果未指定子句, INLINE 则会自动将其设置为 ONOFF 基于 UDF 是否可内联。 如果 INLINE = ON 指定了,但发现 UDF 不可内联,则会引发错误。 有关详细信息,请参阅 标量 UDF 内联

< > column_definition ::=

定义表数据类型。 表声明包括列定义和约束。 对于 CLR 函数,只能指定 column_namedata_type

column_name

表中列的名称。 列名必须符合标识符的规则,并且在表中必须是唯一的。 column_name 可以由 1 到 128 个字符组成。

data_type

指定列数据类型。 对于 Transact-SQL 函数,允许除 timestamp 之外的所有数据类型,包括 CLR 用户定义类型。 对于 CLR 函数,允许除 textntextimagecharvarchar、varchar(max)timestamp 之外的所有数据类型,包括 CLR 用户定义类型。不能在 Transact-SQL 或 CLR 函数中将非标量类型游标指定为列数据类型。

默认 constant_expression

如果在插入过程中未显式提供值,则指定为列提供的值。 constant_expression 是常量 或 NULL系统函数值。 DEFAULT 定义可以应用于任何列,但具有 property 的 IDENTITY 列除外。 DEFAULT 不能为 CLR 表值函数指定。

分套 collation_name

指定列的排序规则。 如果未指定,则为该列分配数据库的默认排序规则。 排序规则名称既可以是 Windows 排序规则名称,也可以是 SQL 排序规则名称。 有关排序规则的列表和详细信息,请参阅 Windows 排序规则名称 (Transact-SQL)SQL Server 排序规则名称 (Transact-SQL)。

COLLATE 子句只能用于更改 charvarcharncharnvarchar 数据类型的列的排序规则。 COLLATE 不能为 CLR 表值函数指定。

ROWGUIDCOL

指示新列是行全局唯一标识符列。 每个表只能将一个 uniqueidentifier 列指定为该 ROWGUIDCOL 列。 该 ROWGUIDCOL 属性只能分配给 uniqueidentifier 列。

ROWGUIDCOL 属性不强制列中存储的值的唯一性。 它也不会自动生成插入到表中的新行的值。 要为每个列生成唯一值,请使用 NEWID 函数 on INSERT statements。 可以指定默认值;但是, NEWID 不能指定为 default。

身份

指示新列是标识列。 向表中添加新行时,SQL Server 会为该列提供唯一的增量值。 标识列通常与 PRIMARY KEY 约束一起使用,以用作表的唯一行标识符。 该 IDENTITY 属性可以分配给 tinyintsmallintintbigintdecimal(p,0)numeric(p,0) 列。 每个表只能创建一个标识列。 绑定默认值和 DEFAULT 约束不能与标识列一起使用。 您必须同时指定 seedincrement ,或者两者都不指定。 如果二者都未指定,则取默认值 (1,1)。

IDENTITY 不能为 CLR 表值函数指定。

seed

要分配给表中第一行的整数值。

increment

要添加到表中连续行的 种子 值的整数值。

< > column_constraint ::= 和 <table_constraint> ::=

定义指定列或表的约束。 对于 CLR 函数,唯一允许的约束类型是 NULL. 不允许使用命名约束。

NULL |NOT NULL

确定列中是否允许 null 值。 NULL 不是严格意义上的约束,但可以像 NOT NULL. NOT NULL 不能为 CLR 表值函数指定。

主键

通过唯一索引对指定列强制执行实体完整性的约束。 在表值用户定义函数中, PRIMARY KEY 只能对每个表的一列创建约束。 PRIMARY KEY 不能为 CLR 表值函数指定。

独一无二

一个约束,该约束通过唯一索引为一个或多个指定列提供实体完整性。 一个表可以有多个 UNIQUE 约束。 UNIQUE 不能为 CLR 表值函数指定。

CLUSTERED |NONCLUSTERED

指示为 or UNIQUE 约束创建PRIMARY KEY聚集索引或非聚集索引。 PRIMARY KEY 约束使用 CLUSTEREDUNIQUE 约束使用 NONCLUSTERED

CLUSTERED 只能为一个约束指定。 如果CLUSTERED为约束指定了约束,并且PRIMARY KEY还指定了约束,则使用 PRIMARY KEYNONCLUSTEREDUNIQUE

CLUSTEREDNONCLUSTERED 并且不能为 CLR 表值函数指定。

核对

一个约束,该约束通过限制可输入一列或多列中的可能值来强制实现域完整性。 CHECK 不能为 CLR 表值函数指定约束。

logical_expression

返回 TRUE or 的 FALSE逻辑表达式。

< > computed_column_definition ::=

指定计算列。 有关计算列的更多信息,请参阅 CREATE TABLE (Transact-SQL)。

column_name

计算列的名称。

computed_column_expression

定义计算列的值的表达式。

< > index_option ::=

指定 or UNIQUE 索引的PRIMARY KEY索引选项。 有关索引选项的更多信息,请参阅 CREATE INDEX (Transact-SQL)。

PAD_INDEX = { ON |OFF }

指定索引填充。 默认值为 OFF

FILLFACTOR = fillfactor

指定一个百分比,该百分比指示在索引创建或更改期间,数据库引擎应使每个索引页的叶级别填充的程度。 fillfactor 必须是介于 1 到 100 的整数值。 默认值为 0。

IGNORE_DUP_KEY = { ON |OFF }

指定在插入操作尝试向唯一索引插入重复键值时的错误响应。 IGNORE_DUP_KEY 选项仅适用于创建或重新生成索引后发生的插入操作。 默认值为 OFF

STATISTICS_NORECOMPUTE = { ON |OFF }

指定是否重新计算分布统计信息。 默认值为 OFF

ALLOW_ROW_LOCKS = { ON |OFF }

指定是否允许使用行锁。 默认值为 ON

ALLOW_PAGE_LOCKS = { ON |OFF }

指定是否允许页锁。 默认值为 ON

最佳做法

如果未使用 SCHEMABINDING 子句创建用户定义的函数,则对基础对象所做的更改可能会影响函数的定义,并在调用该函数时产生意外结果。 我们建议实现以下方法之一,以便确保函数不会由于对于其基础对象的更改而过期:

  • WITH SCHEMABINDING在创建函数时指定子句。 此选项可确保无法修改函数定义中引用的对象,除非该函数也被修改。

  • 在修改函数定义中指定的任何对象后执行 sp_refreshsqlmodule 存储过程。

有关内联表值函数 (内联 TVF) 和多语句表值函数 (MSTVF) 的详细信息和性能注意事项,请参阅创建用户定义的函数(数据库引擎)。

数据类型

如果在 CLR 函数中指定了参数,则它们应为前面为 scalar_parameter_data_type 定义的 SQL Server 类型。 有关将 SQL Server 系统数据类型与 CLR 集成数据类型或 .NET Framework 公共语言运行时数据类型进行比较的更多信息,请参见 映射 CLR 参数数据

要使 SQL Server 在类中重载时引用正确的方法,中 <method_specifier> 指示的方法必须具有以下特征:

  • 接收与 中指定的相同数量的参数 [ , ...n ]
  • 按值而不是按引用接收所有参数。
  • 使用与 SQL Server 函数中指定的类型兼容的参数类型。

如果 CLR 函数的返回数据类型指定了表类型 (),RETURNS TABLE则 中的 <method_specifier> 方法的返回数据类型应为 IEnumeratorIEnumerable类型,并且它假定该接口由函数的创建者实现。 与 Transact-SQL 函数不同,CLR 函数不能在 PRIMARY KEYCHECKUNIQUE<table_type_definition>. 中指定的 <table_type_definition> 列的数据类型必须与执行时 method 返回 <method_specifier> 的结果集的相应列的类型匹配。 创建函数时不会执行此类型检查。

有关如何对 CLR 函数进行编程的更多信息,请参见 CLR User-Defined 函数

注解

可以在使用标量表达式(包括计算列和 CHECK 约束定义)的位置调用标量函数。 标量函数也可以使用 EXECUTE (Transact-SQL) 语句来执行。 标量函数必须至少使用函数 ()<schema>.<function> 的两部分名称来调用。 有关分段名称的更多信息,请参阅 Transact-SQL 语法约定 (Transact-SQL)。 如果 、 UPDATEINSERTDELETE 、 或 statements 的子句SELECTFROM允许使用表表达式,则可以调用表值函数。 有关更多信息,请参阅 执行用户定义的函数

互操作性

以下语句在函数中有效:

  • 赋值语句。
  • Control-of-Flow 语句,语句除外 TRY...CATCH
  • DECLARE 定义局部数据变量和局部游标的语句。
  • SELECT 包含选择列表的语句,这些列表具有为局部变量赋值的值的表达式。
  • 引用函数中声明、打开、关闭和释放的本地游标的游标作。 只 FETCH 允许使用 子句 assign 值给局部变量 INTO 的语句; FETCH 不允许使用将数据返回给客户端的语句。
  • INSERTUPDATEDELETE 修改局部表变量的语句。
  • EXECUTE 调用扩展存储过程的语句。

有关详细信息,请参阅创建用户定义的函数(数据库引擎)。

计算列互作性

函数具有以下属性。 这些属性的值确定函数是否可以在可以持久保存或编制索引的计算列中使用。

资产 DESCRIPTION 注释
IsDeterministic 函数是确定性的或非确定性的。 在确定性函数中允许本地数据访问。 例如,每当使用一组特定的输入值调用函数时,如果函数始终返回相同的结果,并且具有相同的数据库状态,则这些函数将被标记为 deterministic。
IsPrecise 函数是精确的还是不精确的。 不精确函数包含浮点运算等作。
IsSystemVerified 函数的精度和确定性属性可由 SQL Server 验证。
SystemDataAccess 函数访问 SQL Server 本地实例中的系统数据(系统目录或虚拟系统表)。
UserDataAccess 函数访问 SQL Server 本地实例中的用户数据。 包括用户定义的表和临时表,但不包括表变量。

Transact-SQL 函数的精度和确定性属性由 SQL Server 自动确定。 CLR 函数的数据访问和确定性属性可由用户指定。 有关更多信息,请参见 CLR 集成:CLR 例程的自定义属性

要显示这些属性的当前值,请使用 OBJECTPROPERTYEX (Transact-SQL)。

重要

必须创建 Functions SCHEMABINDING 才能具有确定性。

当用户定义函数具有以下属性值时,可以在索引中使用调用用户定义函数的计算列:

  • IsDeterministictrue
  • IsSystemVerifiedtrue (除非持久保存计算列)
  • UserDataAccessfalse
  • SystemDataAccessfalse

有关详细信息,请参阅计算列索引

从函数调用扩展存储过程

从函数内部调用扩展存储过程时,无法将结果集返回给客户端。 任何将结果集返回给客户端的 ODS API 都会返回 FAIL. 扩展存储过程可以连接回 SQL Server 的实例;但是,它不应尝试联接与调用扩展存储过程的函数相同的事务。

与从批处理或存储过程进行调用类似,扩展存储过程在运行 SQL Server 的 Windows 安全帐户的上下文中执行。 存储过程的所有者在向用户授予 EXECUTE 存储过程的权限时应考虑此方案。

局限性

用户定义函数不能用于执行修改数据库状态的操作。

用户定义函数不能包含将表作为其目标的 OUTPUT INTO 子句。

以下 Service Broker 语句不能包含在 Transact-SQL 用户定义函数的定义中:

  • BEGIN DIALOG CONVERSATION
  • END CONVERSATION
  • GET CONVERSATION GROUP
  • MOVE CONVERSATION
  • RECEIVE
  • SEND

用户定义的函数可以嵌套;也就是说,一个用户定义的函数可以调用另一个函数。 当调用的函数开始执行时,嵌套级别会递增,并在调用函数完成执行时递减。 用户定义的函数最多可以嵌套 32 个级别。 超过嵌套的最大级别会导致整个调用函数链失败。 对 Transact-SQL 用户定义函数中托管代码的任何引用都会计算为 32 级嵌套限制中的一个级别。 从托管代码内部调用的方法不计入此限制。

在 CLR 表值函数中使用排序顺序

ORDER在 CLR 表值函数中使用子句时,请遵循以下准则:

  • 您必须确保结果始终按指定顺序排序。 如果结果未按指定顺序排列,则 SQL Server 会在执行查询时生成错误消息。

  • ORDER如果指定了子句,则必须根据列的排序规则(显式或隐式)对表值函数的输出进行排序。 例如,如果列排序规则为中文,则返回的结果必须按照中文排序规则进行排序。 (排序规则在 DDL 中为表值函数指定,或从数据库排序规则中获取。

  • SQL Server 在返回结果时始终验证 ORDER 子句(如果已指定),无论查询处理器是否使用它来执行进一步的优化。 仅当您知道该子句对查询处理器有用时,才使用 ORDER 该子句。

  • 在以下情况下,SQL Server 查询处理器会自动利用该 ORDER 子句:

    • 插入子句与索引兼容的查询 ORDER
    • ORDER BYORDER 子句兼容的子句。
    • 聚合,其中 GROUP BY is compatible with ORDER 子句。
    • DISTINCT 聚合,其中 distinct 列与 ORDER 子句兼容。

ORDER 子句不保证在执行查询时 SELECT 有序的结果,除非 ORDER BY 在查询中也指定了它。 有关如何查询表值函数的排序顺序中包含的列的信息,请参阅 sys.function_order_columns (Transact-SQL)。

元数据

下表列出了可用于返回有关用户定义函数的元数据的系统目录视图。

系统视图 DESCRIPTION
sys.sql_modules 请参阅 Examples 部分中的示例 E。
sys.assembly_modules 显示有关 CLR 用户定义函数的信息。
sys.parameters 显示有关在用户定义的函数中定义的参数的信息。
sys.sql_expression_dependencies 显示函数引用的基础对象。

权限

需要在数据库中具有 CREATE FUNCTION 权限,并对创建函数时所在的架构具有 ALTER 权限。 如果函数指定用户定义类型,则需要对该类型具有 EXECUTE 权限。

例子

有关 UDF 的更多示例和性能注意事项,请参阅创建用户定义的函数(数据库引擎)。

答: 使用计算 ISO 周的标量值用户定义函数

以下示例创建 user-defined function ISOweek。 此函数采用 date 参数并计算 ISO 周数。 要使此函数正确计算, SET DATEFIRST 1 必须在调用该函数之前调用该函数。

该示例还演示如何使用 EXECUTE AS Clause (Transact-SQL) 子句来指定可在其中执行存储过程的安全上下文。 在该示例中,该选项 CALLER 指定在调用过程的用户的上下文中执行该过程。 您可以指定的其他选项包括 SELFOWNERuser_name

下面是函数调用。 将 DATEFIRST 设置为 1

CREATE FUNCTION dbo.ISOweek (@DATE DATETIME)
RETURNS INT
WITH EXECUTE AS CALLER
AS
BEGIN
    DECLARE @ISOweek INT;

    SET @ISOweek = DATEPART(wk, @DATE) + 1 -
        DATEPART(wk, CAST(DATEPART(yy, @DATE) AS CHAR(4)) + '0104');

    --Special cases: Jan 1-3 may belong to the previous year
    IF (@ISOweek = 0)
        SET @ISOweek = dbo.ISOweek(CAST(DATEPART(yy, @DATE) - 1 AS CHAR(4))
           + '12' + CAST(24 + DATEPART(DAY, @DATE) AS CHAR(2))) + 1;

    --Special case: Dec 29-31 may belong to the next year
    IF ((DATEPART(mm, @DATE) = 12)
        AND ((DATEPART(dd, @DATE) - DATEPART(dw, @DATE)) >= 28))
    SET @ISOweek = 1;

    RETURN (@ISOweek);
END;
GO

SET DATEFIRST 1;

SELECT dbo.ISOweek(CONVERT(DATETIME, '12/26/2004', 101)) AS 'ISO Week';

结果集如下。

ISO Week
----------------
52

B. 创建内联表值函数

以下示例返回 AdventureWorks2022 数据库中的内联表值函数。 它返回三列 ProductIDName,以及按商店 YTD Total 向商店销售的每种产品的年初至今总计的聚合。

CREATE FUNCTION Sales.ufn_SalesByStore (@storeid INT)
RETURNS TABLE
AS
RETURN (
    SELECT P.ProductID, P.Name, SUM(SD.LineTotal) AS 'Total'
    FROM Production.Product AS P
    INNER JOIN Sales.SalesOrderDetail AS SD ON SD.ProductID = P.ProductID
    INNER JOIN Sales.SalesOrderHeader AS SH ON SH.SalesOrderID = SD.SalesOrderID
    INNER JOIN Sales.Customer AS C ON SH.CustomerID = C.CustomerID
    WHERE C.StoreID = @storeid
    GROUP BY P.ProductID, P.Name
);
GO

要调用该函数,请运行此查询。

SELECT * FROM Sales.ufn_SalesByStore (602);

C. 创建多语句表值函数

以下示例在AdventureWorks2022数据库中创建表值函数fn_FindReports(InEmpID)。 当提供有效的员工 ID 时,该函数将返回一个表,该表对应于直接或间接向员工报告的所有员工。 该函数使用递归公用表表达式 (CTE) 生成员工的分层列表。 有关递归 CTE 的更多信息,请参阅 WITH common_table_expression (Transact-SQL)。

CREATE FUNCTION dbo.ufn_FindReports (@InEmpID INT)
RETURNS @retFindReports TABLE (
    EmployeeID INT PRIMARY KEY NOT NULL,
    FirstName NVARCHAR(255) NOT NULL,
    LastName NVARCHAR(255) NOT NULL,
    JobTitle NVARCHAR(50) NOT NULL,
    RecursionLevel INT NOT NULL
    )
    --Returns a result set that lists all the employees who report to the
    --specific employee directly or indirectly.
AS
BEGIN
    WITH EMP_cte (
        EmployeeID,
        OrganizationNode,
        FirstName,
        LastName,
        JobTitle,
        RecursionLevel
        ) -- CTE name and columns
    AS (
        -- Get the initial list of Employees for Manager n
        SELECT e.BusinessEntityID,
            OrganizationNode = ISNULL(e.OrganizationNode, CAST('/' AS HIERARCHYID)),
            p.FirstName,
            p.LastName,
            e.JobTitle,
            0
        FROM HumanResources.Employee e
        INNER JOIN Person.Person p
            ON p.BusinessEntityID = e.BusinessEntityID
        WHERE e.BusinessEntityID = @InEmpID
        
        UNION ALL
        
        -- Join recursive member to anchor
        SELECT e.BusinessEntityID,
            e.OrganizationNode,
            p.FirstName,
            p.LastName,
            e.JobTitle,
            RecursionLevel + 1
        FROM HumanResources.Employee e
        INNER JOIN EMP_cte
            ON e.OrganizationNode.GetAncestor(1) = EMP_cte.OrganizationNode
        INNER JOIN Person.Person p
            ON p.BusinessEntityID = e.BusinessEntityID
        )
    -- Copy the required columns to the result of the function
    INSERT @retFindReports
    SELECT EmployeeID,
        FirstName,
        LastName,
        JobTitle,
        RecursionLevel
    FROM EMP_cte

    RETURN
END;
GO

-- Example invocation
SELECT EmployeeID,
    FirstName,
    LastName,
    JobTitle,
    RecursionLevel
FROM dbo.ufn_FindReports(1);
GO

D. 创建 CLR 函数

该示例创建 CLR 函数 len_s。 在创建函数之前, SurrogateStringFunction.dll 程序集将在本地数据库中注册。

适用于:SQL Server 2008 (10.0.x) SP 1 及更高版本。

DECLARE @SamplesPath NVARCHAR(1024);

-- You may have to modify the value of this variable if you have
-- installed the sample in a ___location other than the default ___location.
SELECT @SamplesPath = REPLACE(physical_name,
    'Microsoft SQL Server\MSSQL13.MSSQLSERVER\MSSQL\DATA\master.mdf',
    'Microsoft SQL Server\130\Samples\Engine\Programmability\CLR\'
)
FROM master.sys.database_files
WHERE name = 'master';

CREATE ASSEMBLY [SurrogateStringFunction]
FROM @SamplesPath + 'StringManipulate\CS\StringManipulate\bin\debug\SurrogateStringFunction.dll'
    WITH PERMISSION_SET = EXTERNAL_ACCESS;
GO

CREATE FUNCTION [dbo].[len_s] (@str NVARCHAR(4000))
RETURNS BIGINT
AS
EXTERNAL NAME [SurrogateStringFunction].[Microsoft.Samples.SqlServer.SurrogateStringFunction].[LenS];
GO

有关如何创建 CLR 表值函数的示例,请参阅 CLR Table-Valued 函数

E. 显示用户定义函数的定义

SELECT DEFINITION,
    type
FROM sys.sql_modules AS m
INNER JOIN sys.objects AS o
    ON m.object_id = o.object_id
    AND type IN ('FN', 'IF', 'TF');
GO

使用该 ENCRYPTION 选项创建的函数的定义不能通过使用 sys.sql_modules;但是,将显示有关加密函数的其他信息。