用户定义函数建议
用户定义函数建议
本节包含有关使用用户定义函数的建议和提示,包括有关标量和表值函数的信息、更改架构对函数的可能影响以及用以简化复杂函数的嵌套函数的使用。
标量函数的用途
当需要在代码中的多个位置进行相同的数学计算时,标量函数十分有用。例如,如果应用程序中遍布基于百分率、本金和年份的利息计算,则可以将它编码为可调用的函数,如下
所示。
create function calc_interest ( @principal int , @rate numeric(10,5) , @years int )
returns int
as
begin
declare @interest int
set @interest = @principal * @rate * @years / 100
RETURN(@interest)
end
使用系统函数作为构件块
系统函数可以用作用户定义函数的构件块。例如,如果需要计算某个数字的四倍值,使用 SQUARE 系统函数来得到该值,而不必从头编写整个函数。
将函数嵌套以划分和简化复杂函数
允许将函数嵌套;因此,将复杂函数划分为较简单的函数,并将这些较简单的函数一起使用以得到结果可能效果更好。将复杂函数划分为较小的函数的优点是,该代码可以在应用
程序中的更多地方重新使用。
例如,假定需要计算一小块土地的面积,且输入单位可以是米或英尺,但面积必须始终以平方英尺为单位显示。可以将任务划分为两个函数,而不是编写一个函数来完成所有工作
:
cnvt_meters_feet 进行从米到英尺的转换
calc_Area_ft 以英尺为单位计算面积
这样,便可以在代码的其它位置使用 cnvt_meters_feet 函数。
USE pubs
GO
CREATE FUNCTION cnvt_meters_feet ( @value numeric(10,3) )
RETURNS numeric(10,3)
AS
BEGIN
DECLARE @ret_feet numeric(10,3)
SET @ret_feet = @value * 3.281 ---1 Meter=3.281 Feet
RETURN(@ret_feet)
END
GO
CREATE FUNCTION calc_area_ft ( @length numeric(10,3), @width numeric(10,3), @Unit char(2) )
RETURNS numeric(10,3)
AS
BEGIN
DECLARE @area numeric(10,3)
---Check for unit, if meters(MT), convert it to feet(FT)
IF @Unit = 'MT'
BEGIN
SET @length = pubs.dbo.cnvt_meters_feet( @length )
SET @width = pubs.dbo.cnvt_meters_feet (@width )
END
---Calculate Area
SET @area = @length * @width
RETURN ( @area )
END
GO
SELECT pubs.dbo.calc_area_ft ( 100.0, 50.0, 'MT') AS 'Area in Feet'
SELECT pubs.dbo.calc_area_ft ( 100.0, 50.0, 'FT') AS 'Area in Feet'
go
避免返回所有行的默认情况
当将函数的输入参数用作 WHERE 子句中的条件时,应为所有可能的值考虑返回的行数。
例如,如果使用条件"WHERE name like '@value%'"作为唯一条件,并依赖用户指定起始值,但用户未指定任何值,那么此 WHERE 条件转换为"WHERE name like '%'",这将返回表
中的所有行。这对于具有数百万行的表是十分有害的。为避免这种过多的结果集,可以实现一种默认检查机制,以便当未指定输入时只返回行的一部分。
考虑对架构更改的影响
如果函数中使用了"SELECT * FROM <table>",应考虑函数创建后对架构更改的影响。如果函数未用 SCHEMA_BINDING 选项创建,则结果中不反映对架构的更改。
例如,如果在函数创建之后向表添加一个新列,并且该函数不是 SCHEMA 绑定的,则结果集中将不显示新列。如果在函数创建之后删除一个列,并且该函数不是 SCHEMA 绑定的,
则结果集中已删除列处将显示 NULL 值。
使用子集来合并存储过程和用户定义函数
可以定义表值函数来返回宽的结果集。于是不同的用户可以使用结果的子集来检索数据。这可以用来合并多个存储过程或用户定义函数。
例如,可以创建如下函数:
FunctionA 返回 TableA 的 Col1、Col2、Col3、... Col10
FunctionB 返回 FunctionA 的 Col1、Col3。
FunctionC 返回 FunctionA 的 Col2、Col4。
现在不同的用户可以通过使用 FunctionB 或 FunctionC 来检索较小的子集。他们还可以通过使用简单的 SELECT 语句来选择 FunctionA 返回的列的子集。
例如:Select Col10 from FunctionA。
消除临时表使用
多语句表值函数可用于消除中间结果处理的临时表使用。
何时将存储过程转换为表值函数
评估转换的原因;不要仅为了一致便将存储过程转换为表值函数。尽管预期会有某些改善,但是请仔细测试转换以确认例外情况,并检查是否有不希望的副作用。