SQL Server用户自定义函数(UDF)
一、UDF的定义
和存储过程很相似,用户自定义函数也是一组有序的T-SQL语句,UDF被预先优化和编译并且可以作为一个单元来进行调用。
UDF和存储过程的主要区别在于返回结果的方式:
- 使用UDF时可传入参数,但不可传出参数。输出参数的概念被更为健壮的返回值取代了。
- 和系统函数一样,可以返回标量值,这个值的好处是它并不像在存储过程中那样只限于整形数据类型,而是可以返回大多数SQL Server数据类型。
UDF有以下两种类型:
- 返回标量值的UDF。
- 返回表的UDF。
创建语法:
CREATE FUNCTION [<schema name>.]<function name>
(
[ <@parameter name> [AS] [<schema name>.]<data type> [= <default value> [READONLY]] [,...n] ]
)
RETURNS { <scalar type> | TABLE [(<table definition>)] }
[ WITH [ENCRYPTION] | [SCHEMABINDING] | [RETURNS NULL ON NULL INPUT | CALLED ON NULL INPUT ] |
[EXECUTE AS {CALLER|SELF|OWNER|<'user name'>}]
[AS] { EXTERNAL NAME <externam method> |
BEGIN
[<function statements>]
{RETURN <type as defined in RETURNS clause | RETURN (<SELECT statement>)}
END}[;]
二、标量值函数:
这种类型的UDF和大多数SQL Server内置函数一样,会向调用脚本或存储过程返回标量值,像GETDATE()或USER()函数就会返回标量值。
UDF的返回值并不限于整数,而是可以返回除了BLOB、游标(cursor)和时间戳以外的任何有效的SQL Server数据类型(包括用户自定义类型)。
与存储过程不同,用户自定义函数返回值的目的是提供有意义的数据(而对于存储过程来说,返回值只能说明成功或失败,如果失败,则会提供一些关于失败性质的特定信息。)
可在查询中内联执行函数(如作为SELECT语句的一部分),而是用存储过程则不行。
例一:应用在where语句中
CREATE FUNCTION DateOnly(@Date DateTime)
RETURNS varchar(12)
AS
BEGIN
RETURN CONVERT(varchar(12),@Date,101)
END
然后试着,运用一下:
SELECT * FROM Nx_comment
WHERE dbo.DateOnly(com_posttime) = '2012.04.28' --注意前面的dbo是必须的。
其实以上SQL语句相当于:
SELECT * FROM Nx_comment
WHERE CONVERT(varchar(12),com_posttime,102) = '2012.04.28'
例二:应用在select语句中
SELECT Name,Age,
(SELECT AVG(Age) FROM Person) AS AvgAge,
Age - (SELECT AVG(Age) FROM Person) AS Difference
FROM Person
这里要说明一下,列的意思分别是,姓名,年龄,平均年龄以及与平均年龄的差值。
下面我们用UDF来实现,先定义两个UDF如下:
CREATE FUNCTION dbo.AvgAge()
RETURNS int
AS
BEGIN
RETURN (SELECT AVG(Age) FROM Person)
END GO CREATE FUNCTION dbo.AgeDifference(@Age int)
RETURNS int
AS
BEGIN
RETURN @Age - dbo.AvgAge(); --在一个UDF内引用另外一个UDF,好华丽的说
END
然后执行查询:
SELECT Name,Age,dbo.AvgAge() AS AvgAge,dbo.AgeDifference(Age) as Difference
FROM Person
三、内联表值函数
SQL Server中的用户自定义函数并不只限于返回标量值,也可以返回表。返回的表在很大程度上和其他表是一样的。可以对返回 表的UDF执行JOIN,甚至对结果应用WHERE条件。
改为用表作为返回值并不难,对于UDF来说,表就像任何其他SQL Server数据类型一样。
例一:像表一样地用UDF
CREATE FUNCTION dbo.fnContactName()
RETURNS TABLE
AS
RETURN (
SELECT Id,LastName + ',' + FirstName AS Name
FROM Man
)
然后我们就可以像表一样地用UDF了。
SELECT * FROM dbo.fnContactName()
例二:带参数返回表
CREATE FUNCTION dbo.fnNameLike(@LName varchar(20))
RETURNS TABLE
AS
RETURN (
SELECT Id,LastName + ',' + FirstName AS Name
FROM Man
WHERE LastName Like @LName + '%'
)
然后查询的时候可以这样用:
SELECT * FROM dbo.fnNameLike('刘')
没有WHERE子句,没有过滤SELECT列表,就可以反复使用该函数,而不需要进行"剪切和粘贴"。
四、多语句表值函数
语法:
CREATE FUNCTION Funtion_name
(
--这里定义传入参数及类型
)
RETURNS
@table_name TABLE
(
--这里定义@table_name的列名
)
AS
BEGIN
--这里写sql语句并且将最终需要返回的结果集塞到@table_name 这张表里面
RETURN
END
GO
这个函数通过传入一个十进制的数字,分别返回对应的二进制、八进制、十六进制。
Create FUNCTION F_TConversion
(
@NUM INT
)
RETURNS
@t_table TABLE
(
[Binary] varchar(64),
Octal varchar(16),
Hexadecimal varchar(8)
)
AS
BEGIN
DECLARE @RESULT2 VARCHAR(500)='',@RESULT8 VARCHAR(500)='',@RESULT16 VARCHAR(500)='';
WITH CTE AS(
SELECT @NUM/2 D2,@NUM%2 S2,@NUM/8 D8,@NUM%8 S8,@NUM/16 D16,@NUM%16 S16,1 [INDEX]
UNION ALL
SELECT D2/2 , D2%2,D8/8 , D8%8,D16/16 , D16%16,[INDEX]+1 FROM CTE WHERE D2>0
)
SELECT @RESULT2+=CAST(S2 AS VARCHAR(1))
,@RESULT8+=CASE WHEN D8=0 AND S8=0 THEN '' ELSE CAST(S8 AS VARCHAR(1)) END
,@RESULT16+=CASE WHEN D16=0 AND S16=0 THEN ''
ELSE CASE CAST(S16 AS VARCHAR(5))
WHEN '10' THEN 'A'
WHEN '11' THEN 'B'
WHEN '12' THEN 'C'
WHEN '13' THEN 'D'
WHEN '14' THEN 'E'
WHEN '15' THEN 'F'
ELSE CAST(S16 AS VARCHAR(5))
END
END
FROM CTE ORDER BY [INDEX] DESC
INSERT INTO @t_table
SELECT @RESULT2,@RESULT8,@RESULT16
RETURN
END
GO
五、理解确定性
用户自定义函数可以是确定性的也可以是非确定性的。如果给定了一组特定的有效输入,每次函数就都能返回相同的结果,那么就说该函数是确定性的。SUM()就是一个确定性的内置函数。3、5、10的总合永远都是18,而GETDATE()的值就是非确定性的,因为每次调用它的时候GETDATE()都会改变。
如果视图或计算列引用非确定性函数,则在该视图或列上将不允许建立任何索引。
如果判定函数是否是确定性的?除了上面描述的规则外,这些信息存储在对象的IsDeterministic属性中,可以利用OBJECTPROPERTY属性检查。
SELECT OBJECTPROPERTY(OBJECT_ID('DateOnly'),'IsDeterministic'); --只是刚才的那个自定义函数
输出结果如下:
居然是非确定性的。原因在于之前在定义该函数的时候,并没有加上这个"WITH SCHEMABINDING"。
ALTER FUNCTION dbo.DateOnly(@Date date)
RETURNS date
WITH SCHEMABINDING --当我们加上这一句之后
AS
BEGIN
RETURN @Date
END
在执行查询,该函数就是确定性的了。
SQL Server用户自定义函数(UDF)的更多相关文章
- SQL Server用户自定义函数
用户自定义函数不能用于执行一系列改变数据库状态的操作,但它可以像系统 函数一样在查询或存储过程等的程序段中使用,也可以像存储过程一样通过EXECUTE 命令来执行.在 SQL Server 中根据函数 ...
- SQL SERVER 用户自定义函数(UDF)深入解析
本文内容概要: UDF 概念.原理.优缺点.UDF 的分类 详细讲述3种 UDF 的创建.调用方法以及注意事项 UDF 的实践建议 基本原理: UDF:user-defined functions,用 ...
- SQL之用户自定义函数
关于SQL Server用户自定义的函数,有标量函数.表值函数(内联表值函数.多语句表值函数)两种. 题外话,可能有部分朋友不知道SQL Serve用户自定义的函数应该是写在哪里,这里简单提示一下,在 ...
- sql server 自定义函数的使用
sql server 自定义函数的使用 自定义函数 用户定义自定义函数像内置函数一样返回标量值,也可以将结果集用表格变量返回 用户自定义函数的类型: 标量函数:返回一个标量值 表格值函数{内联表格值函 ...
- SQL Server 自定义函数(Function)——参数默认值
sql server 自定义函数分为三种类型:标量函数(Scalar Function).内嵌表值函数(Inline Function).多声明表值函数(Multi-Statement Functio ...
- Hive 文件格式 & Hive操作(外部表、内部表、区、桶、视图、索引、join用法、内置操作符与函数、复合类型、用户自定义函数UDF、查询优化和权限控制)
本博文的主要内容如下: Hive文件存储格式 Hive 操作之表操作:创建外.内部表 Hive操作之表操作:表查询 Hive操作之表操作:数据加载 Hive操作之表操作:插入单表.插入多表 Hive语 ...
- SQL Server 聚合函数算法优化技巧
Sql server聚合函数在实际工作中应对各种需求使用的还是很广泛的,对于聚合函数的优化自然也就成为了一个重点,一个程序优化的好不好直接决定了这个程序的声明周期.Sql server聚合函数对一组值 ...
- SQL Server排序函数row_number和rank的区别
SQL Server排序函数row_number和rank的区别 直接看测试结果 declare @table table(name varchar(100),amount int, memo var ...
- 数据库开发基础-SQl Server 聚合函数、数学函数、字符串函数、时间日期函数
SQL 拥有很多可用于计数和计算的内建函数. 函数的语法 内建 SQL 函数的语法是: SELECT function(列) FROM 表 函数的类型 在 SQL 中,基本的函数类型和种类有若干种.函 ...
随机推荐
- Thread -- Request
Servlet容器应该绝大部分(有可能全部)是Thread per Request,每个请求一个线程.此外有Thread per Connection,应该不是用于Servlet容器.请见 How a ...
- 入门系列之在Ubuntu 14.04上备份,还原和迁移MongoDB数据库
欢迎大家前往腾讯云+社区,获取更多腾讯海量技术实践干货哦~ 本文由信姜缘 发表于云+社区专栏 MongoDB是最受欢迎的NoSQL数据库引擎之一.它以可扩展,强大,可靠和易于使用而闻名.在本文中,我们 ...
- 令狐冲和TCP/IP协议的第三层协议的关系(经典)
今天突然想起来去看了看我以前在csdn的博客,发现一篇以前一直被奉为经典的文章,哈哈,再转过来和大家看看: 令狐冲十四岁那年进入华山,那年岳琳珊八岁,岳不群白天给两人指点剑法 ...
- [linux] C语言Linux系统编程-socket回声客户端
回声客户端: 1.所谓“回声”,是指客户端向服务器发送一条数据,服务器再将数据原样返回给客户端,就像声音一样,遇到障碍物会被“反弹回来”. 2.客户端也可以使用 write() / send() 函数 ...
- [linux] C语言Linux系统编程-做成守护进程
守护进程: 必须是init进程的子进程,运行在后台,不与任何控制终端相关联. 通过以下步骤成为守护进程 1.调用fork()创建出来一个新的进程,这个新进程会是将来的守护进程 2.在新守护进程的父进程 ...
- <input>属性为number,maxlength不起作用的解决方案
<input type="text" maxlength="11" /> 效果ok, 当 <input type="number&q ...
- java 简单计算器
package com.direct.demo; import java.text.DecimalFormat; import java.util.Scanner; public class Calc ...
- Luogu2483 [SDOI2010]魔法猪学院(可并堆)
俞鼎力大牛的课件 对于原图以 \(t\) 为根建出任意一棵最短路径树 \(T\),即反着从 \(t\) 跑出到所有点的最短路 \(dis\) 它有一些性质: 性质1: 对于一条 \(s\) 到 \(t ...
- 创业公司感悟录之十个提醒—by李天平
这几年经历过很多事,和朋友创业过, 自己也在创业(动软卓越),看过太多创业的人.创业的事,时不时静下心来把所看所感所想总结一下,记录一下,不足为鉴,仅作为自己在路上的警示与提醒,并和广大准备创业和创业 ...
- 【vue】混合模式
因为工作的分配,写财务的对账部分,因为3个页面的设计和功能基本相同,都是查询筛选表格,所以用混合模式优化了部分代码.用混合把一些共用的东西抽离了出来. 具体使用方法参照文档. https://cn.v ...