关系数据库SQL之可编程性函数(用户自定义函数)

前言

在关系型数据库中除了前面几篇基本的数据库和数据表操作之外,还提供了可编程性的函数、存储过程、事务、触发器及游标。

本文介绍的是函数。

函数分为两种:

  1. 系统函数
  2. 用户自定义函数

准备工作

这里以银行存取款为例说明。

1、创建数据表

--创建账户信息表
create table AccountInfo
(
    --账户ID
    CustID int identity(1,1) primary key,
    --帐户名称
    CustName varchar(20) not null,
    --身份证号
    IDCard varchar(18),
    --电话
    TelePhone varchar(13) not null,
    --地址
    Address varchar(50) default('地址不详')
)

go

--创建卡信息表
create table CardInfo
(
    --银行卡卡号
    CardID varchar(19) primary key,
    --银行卡密码
    CardPassWord varchar(6) not null default('888888'),
    --身份证号
    CustID int references AccountInfo(CustID),
    --存款类型
    SaveType varchar(10) not null ,
    --开户日期
    OpenDate datetime not null default(getdate()),
    --开户金额
    OpenMoney money not null check(OpenMoney>1),
    --可用余额
    LeftMoney money  not null check(LeftMoney>1),
    --是否挂失
    IsLost varchar(2) not null default('否')
)

go

--交易信息表
create table TransInfo
(
    --交易编号
    transID int identity primary key,
    --银行卡卡号
    CardID varchar(19) not null,
    --交易类型
    TransType varchar(4) not null,
    --交易金额
    TransMoney money not null,
    --交易时间
    TransDate datetime default(getdate())
)
go

/*
1.使用T-SQL语句为交易信息表(TransInfo)的银行卡卡号(CardID)字段创建外键
*/

--外键(银行卡卡号CardID)
alter table [dbo].TransInfo  with check add  constraint [fk_CardInfo_TransInfo] foreign key(CardID)
references [dbo].[CardInfo] (CardID)
go

/*
2.使用T-SQL语句为账户信息表(AccountInfo)的银行卡卡号(IDCard)字段创建唯一约束
*/
alter table [dbo].[AccountInfo] add unique (IDCard ASC)
go

/*
3.使用T-SQL语句创建约束,使银行卡信息表(CardInfo)的银行卡卡号(CardID)字段值长度只能为19位
*/
alter table [dbo].[CardInfo] add constraint CK_CardID check(len(CardID) = 19)
go

/*
4.使用T-SQL语句使交易信息表(TransInfo)的交易类型(TransType)字段只能选择'存款'和'取款',
    银行卡信息表(CardInfo)的存款类型(SaveType)字段只能选择'定期'和'活期'
*/
alter table [dbo].TransInfo add constraint CK_TransType 
check(TransType = '存款' or TransType = '取款')
go
alter table [dbo].CardInfo add constraint CK_SaveType 
check(SaveType = '定期' or SaveType = '活期')
go

2、插入基本数据

--插入三个账户信息
insert into AccountInfo values
            ('孙悟空','422322001502110017','027-88888888','花果山'),
            ('唐僧','420322001902140019','027-85368962','大唐'),
            ('沙和尚','410340001572144714','13295654665','通天河')
insert into CardInfo values
            ('1027 3526 1536 1135','888888',1,'定期',default,500,500,'否'),
            ('1029 3326 1536 1235','888888',2,'活期',default,1500,1500,'否'),
            ('1324 3626 7532 1935','888888',1,'活期',default,4500,4500,'否')

系统函数

数据库系统定义的函数,即内置函数。


内置函数调用

SELECT 内置函数名(列名称) FROM <表名>;
函数列别 说明
聚合函数 执行的操作是将多个值合并为一个值。例如 COUNT、SUM、MIN 和MAX。
配置函数 是一种标量函数,可返回有关配置设置的信息。
加密函数 支持加密、解密、数字签名和数字签名验证。
游标函数 返回有关游标状态的信息。
日期和时间函数 可以更改日期和时间的值。
数学函数 执行三角、几何和其他数字运算。
元数据函数 返回数据库和数据库对象的属性信息。
排名函数 是一种非确定性函数,可以返回分区中每一行的排名值。
行集函数 返回可在 Transact-SQL 语句中表引用所在位置使用的行集。
安全函数 返回有关用户和角色的信息。
字符串函数 可更改 char、varchar、nchar、nvarchar、binary 和 varbinary 的值。
系统函数 对系统级的各种选项和对象进行操作或报告。
系统统计函数 返回有关 SQL Server 性能的信息。
文本和图像函数 可更改 text 和 image 的值。

具体的函数如果不清楚请自行搜索,本文着重介绍用户自定义函数。


用户自定义函数

除了系统提供的函数,用户可以根据自己的需求自定义函数;
用户自定义函数,顾名思义,就是数用户自己定义的函数;
用户自定义函数分为两类:表值函数和标量值函数;
其中,表值函数也分两种:内联表值函数和多语句表值函数。


自定义函数调用

SELECT 字段列表/* FROM [函数所有者.]<函数名称>([参数列表]);

在自定义函数中,函数所有者一般默认情况下是dbo;
在自定义函数中,标量值函数一定要加上函数所有者,否则会报错:提示函数非内置函数;


表值函数

表值函数是返回一个Table类型,相当与一张存储在内存中的一张虚拟表。

内联表值函数

语法

CREATE FUNCTION [函数所有者.]<函数名称> 
(   
    -- 添加函数所需的参数,可以没有参数
    [<@param1> <参数类型>]
    [,<@param1> <参数类型>]…
)
RETURNS TABLE 
AS
RETURN 
(
    -- 查询返回的SQL语句
    SELECT查询语句
)

示例

/*
* 创建内联表值函数,查询交易总额大于1W的开户人个人信息
*/
create function getCustInfo()
returns @CustInfo table  --返回table类型
(
    --账户ID
    CustID int,
    --帐户名称
    CustName varchar(20) not null,
    --身份证号
    IDCard varchar(18),
    --电话
    TelePhone varchar(13) not null,
    --地址
    Address varchar(50) default('地址不详')
)
as
begin
    --为table表赋值
    insert into @CustInfo
    select CustID,CustName,IDCard,TelePhone,Address from AccountInfo 
    where CustID in (select CustID from CardInfo 
    where CardID in (select CardID from TransInfo group by CardID,transID,TransType,TransMoney,TransDate having sum(TransMoney)>10000))
    return
end
go
-- 调用内联表值函数
select * from getCustInfo()
go

多语句表值函数

语法

CREATE FUNCTION [函数所有者.]<函数名称> 
(   
    -- 添加函数所需的参数,可以没有参数
    [<@param1> <参数类型>]
    [,<@param1> <参数类型>]…
)
RETURNS 
<@定义的表名> TABLE 
(
    -- 添加返回数据表的列
    <列名1> <数据类型1>, 
    <列名2> <数据类型2>,
    ……
    <列名n> <数据类型n>]
)
AS
BEGIN
    --为<@定义的表名>赋值的SQL语句
    RETURN 
END

示例

/*
* 创建多语句表值函数,可以查询出一个月内有交易记录的用户姓名,联系电话,身份证号码,银行卡卡号和账户余额
*/
create function getCustInfoMonth()
returns @CustInfo table  --返回table类型
(
    --帐户名称
    CustName varchar(20) not null,
    --电话
    TelePhone varchar(13) not null,
    --身份证号
    IDCard varchar(18),
    --银行卡卡号
    CardID varchar(19) not null,
    --可用余额
    LeftMoney money  not null check(LeftMoney>1)
)
as
begin
    --为table表赋值
    insert into @CustInfo
        select A.CustName, A.TelePhone, A.IDCard, T.CardID, C.LeftMoney
        from AccountInfo as A inner join CardInfo as C on A.CustID = C.CustID 
        inner join TransInfo as T on C.CardID = T.CardID 
        where exists(select * from TransInfo 
        group by CardID,TransDate,transID,TransType,TransMoney
        having datediff(MONTH,TransDate,GETDATE())=0)
    return
end
go
-- 调用多语句表值函数
select * from dbo.getCustInfo()
go

标量值函数

返回一个标量值

语法

CREATE FUNCTION [函数所有者.]<函数名称> 
(
    -- 添加函数所需的参数,可以没有参数
    [<@param1> <参数类型>]
    [,<@param1> <参数类型>]…
)
RETURNS <函数返回数据类型>
AS
BEGIN
    -- 定义返回数据变量
    DECLARE @变量名 数据类型

    -- 通过SQL语句为返回变量赋值
    SELECT @变量名 = SQL语句

    -- 返回结果
    RETURN @变量名

END

示例

/*
7.创建标量值函数,根据用户传入的银行卡卡号,获得该卡交易次数
*/
create function getTransCount
(
    @CardID varchar(19)  --参数银行卡卡号
)
returns int  --返回int类型
as
begin
    declare @count int
    select @count = count(*) from TransInfo where CardID = @CardID
    return @count
end
go
-- 调用标量值函数
-- `标量值函数`一定要加上`函数所有者`,否则会报错:提示函数非内置函数
select dbo.getTransCount('1027 3526 1536 1135') as 次数
go

再次提示:
在自定义函数中,函数所有者一般默认情况下是dbo;
在自定义函数中,标量值函数一定要加上函数所有者,否则会报错:提示函数非内置函数;

自定义函数删除

-- 自定义函数删除语法
DROP FUNCTION [函数所有者.]<函数名称>;

-- 示例
-- 删除查询交易总额大于1W的开户人个人信息内联表值函数
DROP FUNCTION getCustInfo

函数部分介绍到这里,如有疑问,请留言。

谢谢各位看官的浏览。

本文采用知识共享署名-相同方式共享 4.0 国际许可协议进行许可。
基于简书上的作品创作。 可转载、引用,但需经本人同意后署名作者且注明文章出处,并以相同方式共享。

知识共享许可协议
知识共享许可协议

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,736评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,167评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,442评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,902评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,302评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,573评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,847评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,562评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,260评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,531评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,021评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,367评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,016评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,068评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,827评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,610评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,514评论 2 269

推荐阅读更多精彩内容