SQL 构建自定义函数(UDF)

UDF:user-defined functions,用户自定义函数。

基本原理:

    UDF是一个例程,它接受参数、执行操作并返回该操作的结果。根据定义,结果可以是标量值(单个)或表。

UDF的优点:

  1. UDF可以把复杂的逻辑嵌入到查询中。UDF可以为复杂的表达式创建新函数。
  2. UDF可以运用在一个表达式或SELECT语句的FROM子句中,并且还可以绑定到架构。此外,UDF还可以接受参数。UDF有助于实施一致性和可重用性。

UDF的缺点:

    该函数一旦误用会产生潜在的性能问题。必须针对WHERE子句的每一行执行的任何函数,不管是用户定义的函数还是系统函数,都将减慢执行速度。

UDF的类型:

    UDF主要有3种类型(Management Studio把内联表值函数与多语句表值函数放到了一个组中):

  1. 标量函数
  2. 内联表值函数
  3. 多语句表值函数

一、标量函数


    标量函数是返回一个具体值的函数。函数可以接收多个参数、执行计算然后返回一个值。返回值通过RETURN命令返回。用户定义的函数中的每个可能代码路径都以RETURN命令结尾。

    标量函数可以运用于SQL Server中的任何表达式,甚至在CHECK约束的表达式中也可以使用(但不推荐这种用法)。

  • 函数限制

    标题函数必须是确定性的,也就是说标量函数必须反复地为相同的输入参数返回相同的值。因此,如newid()函数和rand()函数不允许出现在标量函数中。不允许用户定义标量函数更新数据库、调用存储过程或调用DBCC命令,唯一的例外是可以更新表变量。用户定义函数不能返回BLOB(二进制大型对象)数据,如text、next、timestamp和image数据类型变量。也不能返回表变量可cursor数据类型。对于错误处理,UDF也不包含TRY...CATCH或RAISERROR。

    UDF可以调用嵌套深度为32层以内的其他用户定义函数,或者递归调用自己到32层的深度。当然,这只是理论限制,嵌套函数会严重影响性能,应尽可能避免使用嵌套函数。

  • 创建方法

1 CREATE FUNCTION FunctionName (InputParameters) 
2 RETURNS DataType 
3 AS
4 BEGIN
5   Code;
6   RETURN Expression;
7 END;

     InputParameters输入参数包含数据类型定义。参数可以设置默认值(Parameter = default ),需要注意的是在UDF中有默认值的参数并不能成为可选参数,为在调用函数时请求到默认值,需要把关键字DEFAULT传递到函数的默认值参数位置。

    示例1:下面的UDF执行一个简单的数学计算,其中第二个参数带有默认值。

CREATE FUNCTION dbo.ufnCalculate
(@Numer_a numeric(5,2),
 @Numer_b numeric(5,2) = 1.0)
RETURNS numeric(5,2)
AS
BEGIN
  RETURN @Numer_a / @Numer_b ;
END;
GO

select dbo.ufnCalculate(15.3 , 6.54),
       dbo.ufnCalculate(9.0 , DEFAULT);

结果:
------  ------
2.38      9.00

    示例2:计算并返回某个时间所在月份的天数。

CREATE FUNCTION [dbo].[GetMonthDay](@date datetime)
RETURNS int
AS 
BEGIN
  DECLARE @date1 datetime
  SELECT @date1 =Dateadd(MM,1,@date)
  RETURN day(Dateadd(DD,-day(@date1),@date1))
END;
  • 调用标量函数

    在接受单值的表达式中,标量函数可用于任何地方。用户定义的标量函数必须通过一个最少有两部分的名称(所有者.函数名)来调用。

    下面的脚本演示了在数据库的订单表中调用示例2中的函数及其返回值。

SELECT S.BIL_DD,dbo.GetMonthDay(BIL_DD) as DAYS_M 
FROM Orders S

结果
BIL_DD        DAYS_M
------        ------
2019-01-31     31
2019-02-15     28

二、内联表值函数


 与视图相似,内联表值函数也是为一个存储的SELECT语句封装。内联表值函数保留了视图的优点,还添加了一些参数。

创建方法

    内联表值用户定义函数没有BEGIN / END主体。SELECT语句是作为一个虚拟数据表返回的:

CREATE FUNCTION FunctionName (InputParameters)
RETURNS Table 
AS 
RETURN (Select Statement);

示例:下面的示例返回某个客户所订购产品的汇总情况。

CREATE FUNCTION dbo.ufnGetProductTotalByCust (@custNo varchar (10))
RETURNS Table 
AS
RETURN(
SELECT H.CUS_NO,B.PRD_NO,SUM(B.QTY) as TOTAL_PRD 
FROM TF_POS AS B       --订单货品明细表
LEFT JOIN MF_POS  AS H --订单客户信息表
       ON H.OS_NO=B.OS_NO 
WHERE H.CUS_NO=@custNo  
GROUP BY H.CUS_NO,B.PRD_NO );
GO

调用内联表值函数

    通过dbo.ufnGetProductTotalByCust查询客户代号为"CT060228" 的产品汇总数据,函数出现在SELECT语句的FROM部分:

SELECT PRD_NO,TOTAL_PRD FROM 
dbo.ufnGetProductTotalByCust('CT060228') 
ORDER BY PRD_NO DESC 

返回结果(部分):

PRD_NO           TOTAL_PRD
------------   ------------------------
10910030006	5792.00000000
10910040003	10776.00000000
10912060014	11442.00000000
10913040009	9276.00000000
11410030028	900.00000000
......

与视图的关系

    与视图相比,内联表值函数的优势在于其可以使用参数。而视图不包含参数,而且在运行时想要限制结果需要把WHERE子句添加到调用视图的SELECT语句中来实现。

    示图的调用示例,假设已经存在视图dbo.vwProductTotalByCust,调用视图时,在SELECT语句中添加了一个WHERE子句限制:

    SELECT * FROM dbo.vwProductTotalByCust WHERE cus_no='CT060228' 

关联方法

    

猜你喜欢

转载自www.cnblogs.com/idreamo/p/10767923.html