jpa 自定义sql if_跟飞哥学编程:SQL入门-:函数、存储过程和触发器

d2f31d9e9f6cb90f528d40e6404717b3.png

最后不要忘记:SQL是一种结构化(Structured)的语言(Language),所以它具有

编程语言的特性

声明变量和赋值

所谓变量,可以是看成一个存储数据的容器,所有它里面存储的值是可以变化的。使用变量必须首先声明(创建),然后再赋值(将数据装入这个容器中) 。

DECLARE 

也可以一次性声明多个变量:

DECLARE 

还可以在声明变量的同时给他赋值:

DECLARE 

注意,SQL中的变量必须以@开头,以一个@开头的变量被称为局部变量。所谓“局部”,是指他的作用域(也就是能够产生作用、有用的区域)是局部的,而不是全局的。具体来说,局部变量的作用域位于一个批处理语句中。

SQL Server中还有一种变量,是使用@@开头的,被称之为全局变量。全局变量可以不受批处理的约束,可以在任何地方直接使用。但用户不能定义全局变量,全局变量只能由SQL SERVER定义。

但我就是要定义一个全局变量呢?比如:

DECLARE 

SQL Server会将其作为一个名为@name(不是name)的局部变量使用。

演示:局部变量和全局变量的区别

常用的全局变量有:

PRINT 

变量和列值一样,也可以进行运算。根据运算结果,就可以控制:

分支和循环

分支使用的只有两个关键字:

  • IF:“如果”的意思,后面跟条件表达式。如果条件表达式结果为真,继续执行后面的子句……
  • ELSE:必须和IF配合使用,“否则”的意思,后面能再跟条件表达式。当其配合使用的IF表达式结果为假时,执行ELSE后面的子句

我们通过一个例子来学习:

DECLARE 

@age的值是20的时候,输出的是Adult;把@age的值改成13,输出的就是Teenager。

如果IF...ELSE...后面跟的不止是一句SQL语句,就需要使用BEGIN...END,用以界定IF或ELSE的作用范围。比如:

DECLARE 

ELSE后面还可以再跟IF,比如:

DECLARE 

IF和ELSE还可以嵌套,比如:

DECLARE 

SQL只有一个循环关键字:WHILE

WHILE后面接条件,只要条件为真,就会一直循环执行WHILE引导(通常由BEGIN...END界定)的循环体语句。循环无法终止,就是“死循环”,这是一定要注意避免出现的。所以在WHILE的循环体中,通常都会设置语句,使得一定条件下WHILE条件为假,以结束循环。比如:

DECLARE 

运行上述SQL语句,会输入1,2,3,4,5。

使用这些分支循环,就可以构建大量的、复杂的SQL语句,这些SQL语句需要被有效的管理,

函数

应运而生。(复习:人人都是程序猿)我们其实已经学习并使用过很多系统函数(复习:),这里我们来学习如何创建自定义的函数。

SQL Server中函数的最大特点: 必须有一个返回值 。根据返回值类型,我们可以将其分为:

标量函数:返回一个简单类型的单一值。

其函数声明的SQL代码如下:

CREATE 

注意:

  1. 函数不属于任何一张表,而属于整个数据库,所以函数名在整个数据库中不能重复
  2. 函数的命名规则见:,
  3. 函数的参数和变量声明一样,必须用@开头,且指明类型
  4. 标明函数返回类型时使用的关键字是RETURNS,带了一个S;函数体内标明返回值时,使用的是RETURN,没有S
  5. AS可以省略,BEGIN和END是不能省略的
  6. 函数体中:
    1. 不能对数据库中的数据进行修改,比如使用INSERT/UPDATE/DELETE等
    2. RETURN语句只能在函数体的最后

声明函数之后,运行,就可以在SQL Server Object Explorer中看到这个函数了:

4fc13f0734a919bdbd4e70252d9fe2fb.png

可以看到,YzAdd被添加到:数据库17bang -> Programmability -> Functions -> Scalare-valued Functions下面,而且被自动的添加了 dbo 的schema。

然后,我们就可以调用它了:

PRINT 

注意:Scalar函数必须指定schema_name(这里是dbo),不加schema_name会被认为是系统内置(build-in)函数。

函数还可以被 修改,这需要使用 ALTER 关键字。我们可以使用ALTER,把上述YzAdd函数的一个参数设定一个默认值:

ALTER 

运行上述SQL语句,函数就会被修改,在SQL Server Object Explorer中查看:

d723ee019d43c47f15fe2c9269869360.png

@b已经变成了Default(区别于@a的No default)。

设置了默认值的参数,可以用两种方式调用:

PRINT 

此外,函数还可以被加密,以免被其他用户看到函数的具体实现。未加密的函数,在函数上右键点击 View Code,就能查看到函数的“源代码”

f9882bb31af3f27befbe7a6ed1904bcb.png

但是,如果创建(或修改)函数时添加了WITH ENCRYPTION:

ALTER 

再去View Code,就会发现:无法查看到函数体(函数的定义,如名称、参数、返回值等还是可以看到的)

CREATE 

SQL函数的另一个特殊性,就表现在它的返回值可以是“表”,这种函数被称之为:表值函数。注意这里所称的表,实际上是一种具有表结构的数据,它和使用CREATE Table生成的表不一样:数据库中并没有这样一张表,这张“表”是通过函数运算而“临时”获得的。

表值函数又可以被细分为:

单行表值函数(Inline Function)

其SQL语句如下:

CREATE 

除了RETURNS后直接接TABLEG关键字,这种函数的特点是:函数体只能有一句SELECT语句,且不能由BEGIN...END包裹。其他(如DEFAULT参数和WITH ENCRYTION)都和标量函数一样。

调用YzInlineTable函数,会返回一个“表”,所以,我们也要像表一样使用它:

--不是:PRINT YzInlineTable(2),而是:

注意:调用表值函数时可以不需要使用schema,¯_(ツ)_/¯

如果函数中需要封装更复杂的逻辑,我们就只有使用多行表值函数(Multi-Statement Function)了。它同样是返回一个表,但它和标量型函数一样有一个用BEGIN-END 语句括起来的函数体,返回值的数据是由函数体中的语句插入的。

SQL代码及语法代码如下所示:

CREATE 

很函数相比,SQL中更常用的是

存储过程(Procedure)

和函数非常类似,它也是一组为了完成特定功能的 SQL 语句集合,经编译后存储在数据库中,用户通过指定存储过程的名称并给出参数来执行它。我们首先来

创建

一个最简单的存储过程GetExcellentStudents:

CREATE 

和函数一样,存储过程也可以给参数一个默认值。创建完成之后,我们就可以在SQL Server Object Explorer里看到我们的存储过程:

e39ad80d8ce5dcd62b4d1f1883af3396.png

调用:

DECLARE 

存储过程没有RETURN的使用,但它可以用OUTPUT设置输出参数,一样的实现函数的效果。另外,存储过程没有函数 只读不写 的限制。

所以说,基本上,函数能干的事情存储过程都能干。这就是存储过程的使用比函数更为普遍的原因。一个常见的面试问题:何时使用存储过程何时使用函数 ?除了上述的语法的比较,我们建议再加上很重要的一条:按需要选择。如果你的需求是:

  • 得到 一些数据以便于数据库内部 使用,最好使用函数;否则
  • 请使用存储过程

参考:Function vs. Stored Procedure in SQL Server

调用

存储过程,需要使用EXECUTE(或简写EXEC)。

  1. 如果不指定参数名,应按存储过程定义时参数次序依次赋值;否则可不限定顺序。
  2. 使用默认值需用DEFAULT显式指定
  3. 输出参数要先声明,再使用,而且还要加上OUTPUT标识
DECLARE 

其他和函数一样,

修改

存储过程需要使用ALTER:

ALTER 

删除

需要使用DROP:

DROP 

SQL Server也为我们提供了大量的

系统存储过程

6ad0f254fe11193ab8ad1c972158857a.png

其特点为都以sp_开头。所以,建议用户自定义的存储过程不要以"sp_"开头,而是使用其他字符标识(比如usp_)。

我们介绍两个常用的系统存储过程:

sp_rename :可更改数据库对象(比如表/列/索引等)名称。使用方法:

-- 将Student表中的Score(列),更名为FinalScore

sp_helptext :获取数据对象的帮助信息,使用方法:

EXEC 

是否使用存储过程,曾经是一个争论异常激烈的话题。存储过程有以下优点:

  1. 因为事先编译,所以可以更快的执行
  2. 因为只需要向数据库传递存储过程名称和参数,所有需要的流量更少

但它的缺点也同样明显:

  1. 可读性差(对于Java/C#/PHP等开发人员而言)
  2. 难以调试(飞哥教过你们调试SQL么?^_^)维护
  3. 不能在不同数据库之间迁移(各个数据库的存储过程语法不一定相同)

随着计算机性能的大幅提升,以及业务逻辑的不断复杂化,目前主流的实践已经是“尽可能少的,或者干脆不使用存储过程”。这同样适用于之前讲的 函数 和接下来要讲的:

触发器

触发器是一种特殊的存储过程:顾名思义,触发器可以在进行某些数据库操作时自动触发,并执行触发器中定义的内容。

这是我们最后一部分内容的学习。“授人以鱼不如授人以渔”,我们课堂讲授的内容始终是有限的,同学们在以后的工作中必然会遇到更多的问题。这就需要同学们能够

查询文档

所以,最后,让我们来一起学习阅读 触发器的MSDN文档。

如果这个内容对我们是全新的,我们可以从头往下阅读。

既然文档里提到了DML和DDL,我们就刚好做一个总结。SQL语言共分为四大类(复习):

  • 数据操纵语言:D(Data)M(manipulate)L(Language),包括增(INSERT)删(DELETE)改(UPDATE)
    • 数据查询语言:DQ(Query)L,查(SELECT)
  • 数据定义语言:DD(define)L,涉及数据库对象的操作,包括{CREATE|ALTER|DROP} {DATABASE|TABLE|INDEX|VIEW|FUNCTION|PROCEDURE} 。传统上DDL不受事务控制。TRUNCATE属于DDL,所以不能回滚。
  • 数据控制语言:DC(control)L。授权相关:GRANT/REVOKE (课程没讲)
  • 事务控制语言:T(transaction)CL:TRANSACTION/COMMIT/ROLLBACK/SAVE

文档中最核心的就是Syntax部分,不要被里面密密麻麻的符号吓坏了,我们一个一个的来看:

  • 大写英语单词:关键字
  • 小写英语单词:需由开发人员填写的内容
  • []:可以使用,也可以不使用
  • {}:必须使用
  • |:并列可选项
  • <>:占位
  • ::=:
  • [ ,...n ]

演示:浏览文档,创建一个TRIGGER

作业

  1. 编写存储过程模拟“一起帮用户注册”的过程,包含以下逻辑:
  • 检查用户名是否重复。如果重复,返回错误代码:1
  • 检查用户密码是否符合“长度不小于4位”的要求。如果不符合,返回错误代码:2
  • 如果有邀请人:
    • 检查邀请人是否存在,如果不存在,返回错误代码:10
    • 检查邀请码是否正确,如果邀请码不正确,返回错误代码:11
  • 将用户名、密码和邀请人存入数据库(Register)
  • 给邀请人增加10个帮帮点积分
  • 通知邀请人(在Message表中生成一条数据)某人使用了他作为邀请人。
  • 确保Problem有“发布时间(PublishTime)”和“最后更新时间(LatestUpdateTime)”两列,创建触发器实现:
  1. 更新一条数据,自动将当前时间计入该行数据的LatestUpdateTime
  2. 插入一条数据,自动将当前时间计入该行数据的PublishTime(提示:INSERTED伪表)

每日单词

4c167dd890d72a8281d95c8e56b00dfd.png

感谢童鞋们的阅读!^_^

我就是:黑律师/包工头/创业狗/老码农……现在还是教书匠的大飞哥。

再次重申这个系列的目标是:

1)通俗易懂。2)实战为主。3)面向就业。

系列内容的完善需要你的反馈!

欢迎点赞和评论,以及加入我们的QQ交流群:326801052。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值