From 6483cabaa2f928e1e52cdc82285e80f51701be46 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?33=E8=B0=B7=E5=85=86=E6=98=8E?= <2692544974@qq.com> Date: Wed, 21 Sep 2022 19:30:32 +0800 Subject: [PATCH] =?UTF-8?q?=E5=87=BD=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...75\346\225\260\344\275\234\344\270\232.md" | 85 + ...33\351\230\266\347\254\224\350\256\260.md" | 1492 +++++++++++++++++ 2 files changed, 1577 insertions(+) create mode 100644 "33\350\260\267\345\205\206\346\230\216/9\346\234\21021\346\227\245\345\207\275\346\225\260/9\346\234\21021\346\227\245\345\207\275\346\225\260\344\275\234\344\270\232.md" create mode 100644 "33\350\260\267\345\205\206\346\230\216/9\346\234\21021\346\227\245\345\207\275\346\225\260/sql\350\277\233\351\230\266\347\254\224\350\256\260.md" diff --git "a/33\350\260\267\345\205\206\346\230\216/9\346\234\21021\346\227\245\345\207\275\346\225\260/9\346\234\21021\346\227\245\345\207\275\346\225\260\344\275\234\344\270\232.md" "b/33\350\260\267\345\205\206\346\230\216/9\346\234\21021\346\227\245\345\207\275\346\225\260/9\346\234\21021\346\227\245\345\207\275\346\225\260\344\275\234\344\270\232.md" new file mode 100644 index 0000000..b5ecdac --- /dev/null +++ "b/33\350\260\267\345\205\206\346\230\216/9\346\234\21021\346\227\245\345\207\275\346\225\260/9\346\234\21021\346\227\245\345\207\275\346\225\260\344\275\234\344\270\232.md" @@ -0,0 +1,85 @@ +--查询男生和女生中年龄最大的学生信息,要求显示:姓名,性别,年龄 + +```sql +select birth,姓名,性别 from ( +select birth,name 姓名,gender 性别,row_number() over (partition by gender order by birth ) as birth_rank from tb_student +) as T1 +where T1.birth_rank = 1 +``` + +部门工资最高的员工 + +```sql +SELECT + Department.NAME AS Department, + Employee.NAME AS Employee, + Salary +FROM + Employee, + Department +WHERE + Employee.DepartmentId = Department.Id + AND ( Employee.DepartmentId, Salary ) + IN (SELECT DepartmentId, max( Salary ) + FROM Employee + GROUP BY DepartmentId ) + +``` + +分数排名 + +```sql +select score, dense_rank() over (order by score desc) as 'rank' +from scores; +``` + +(1)编写一个函数求该银行的金额总和 + +```sql +go +create function MoneySum() +returns int +as +begin + return (select sum(CardMoney) from BankCard) +end +go + +select dbo.MoneySum()'金额总和' +``` + +(2)传入账户编号,返回账户真实姓名 + +```sql +go +create function Name(@put int) +returns varchar(20) +as +begin + declare @Name varchar(20) + select @Name=RealName from AccountInfo where AccountId = @put + return @Name +end +go + +select dbo.Name(3) +``` + +(3)传递开始时间和结束时间,返回交易记录(存钱取钱),交易记录中包含 真实姓名,卡号,存钱金额,取钱金额,交易时间。 + +方案一(逻辑复杂,函数内容除了返回结果的sql语句还有其他内容,例如定义变量等): + +```sql + +``` + +(4)查询银行卡信息,将银行卡状态1,2,3,4分别转换为汉字“正常,挂失,冻结,注销”,根据银行卡余额显示银行卡等级 30万以下为“普通用户”,30万及以上为"VIP用户",分别显示卡号,身份证,姓名,余额,用户等级,银行卡状态。 + +方案一:直接在sql语句中使用case when + +方案二:将等级和状态用函数实现 + +(5)编写函数,根据出生日期求年龄,年龄求实岁,例如: + +​ 生日为2000-5-5,当前为2018-5-4,年龄为17岁 +​ 生日为2000-5-5,当前为2018-5-6,年龄为18岁 \ No newline at end of file diff --git "a/33\350\260\267\345\205\206\346\230\216/9\346\234\21021\346\227\245\345\207\275\346\225\260/sql\350\277\233\351\230\266\347\254\224\350\256\260.md" "b/33\350\260\267\345\205\206\346\230\216/9\346\234\21021\346\227\245\345\207\275\346\225\260/sql\350\277\233\351\230\266\347\254\224\350\256\260.md" new file mode 100644 index 0000000..dc51e04 --- /dev/null +++ "b/33\350\260\267\345\205\206\346\230\216/9\346\234\21021\346\227\245\345\207\275\346\225\260/sql\350\277\233\351\230\266\347\254\224\350\256\260.md" @@ -0,0 +1,1492 @@ + + + + + + +# sql server进阶 + +[TOC] + + + +# 数据库设计相关理论 + +## 一、数据库设计是什么?它重要吗? + +1. 根据业务需求的描述,设置或者配置数据库的各项参数,包括数据库、数据库表、数据库表的字段、主键、外键、约束、索引、存储过程、函数、视图等等一系列东西的过程 +2. 重要不?很重要,或者说非常的重要,因为,现代的绝大多数的应用需要数据库的支撑 + +## 如何进行数据库的设计 + +1. 根据业务的需求设计数据库,有一套规范叫 三范式 +2. 还有一种设计工具PowerDesigner + +![img](https://gitee.com/gu-zhaoming/database-advanced-class-notes-1/raw/master/%E8%80%81%E8%83%A1%E6%9D%A5%E4%B9%9F/imgs/db.png) + + + + + +## 数据持久化 + +``` +## 数据易失,希望保存数据,则关系到一个数据持久化的概念 + +## 数据持久化的方式 保存到文件、保存到数据库(实际上也保存到数据库文件当中) + +## 数据放在硬盘上,放在文件当中,那么你总需要这个数据按一定的逻辑或者层次进行摆放 +``` + +## + +# sql server三范式理解 + +### 第一范式: + +```sql +--指数据表的每一列都是不可分割的基本数据项,同一列中不能有多个值,即实体中的 某个属性不能有多个值或者不能有重 复的属性。 +``` + +### 第二范式: + +```sql +--如果一个数据表已经满足第一范式,而且该数据表中的任何一个非主键字段的数值都 依赖于该数据表的主键字段,那么该 数据表满足第二范式。 这个表中,就是这个选出来的字段中,非主键字段要完全依赖主键字段 +``` + +### 第三范式: + +```sql +--如果一个数据表已经满足第二范式,而且该数据表中的任何两个非主键字段的数值之 间不存在函数依赖关系,那么该数据 表满足第三范式。 这个表中,就是这个选出来的字段中,不能有函数依赖关系 +``` + +### BC范式 + +```sql +--在关系模式中每一个决定因素都包含候选键,也就是说,只要属性或属性组A能 够决定任何一个属性B,则A的子集中必须 有候选键。BCNF范式排除了任何属性(不光 是非主属性,2NF和3NF所限制的都是非主属性)对候选键的传递依赖与部分 依赖。 +``` + +# 变量 + +## 局部变量 + +局部变量必须以标记@作为前缀 ,如@age +局部变量的使用是先声明,再赋值 +局部变量只在定义它的局部范围内有效 + + + +声明一个局部变量:**declare @变量名 数据类型** + +```sql +--例: + declare @id int --声明一个名为id的整型变量 + declare @name varchar(50) --声明一个可变长度为50的存放姓名的字符串变量 + +``` + +赋值: + +- set @变量名 = 值 + +- select @变量名 = 值 + +```sql +--例: + select @id = 1001 + set @name = '周飘' +``` + +set与select赋值的区别: + +set赋值给变量指定的值,select一般用于表中查询出的数据赋值给变量,如果查询结果有多条,取最后一条赋值给变量 + +## 全局变量 + +全局变量必须以标记@@作为前缀,如@@version +全局变量由**系统定义和维护**,我们**只能读取,不能修改全局变量的值** +全局变量在整个SQL环境下都可以被访问或调用 + +```sql +--@@ERROR:返回执行的上一个语句的错误号 +--@@IDENTITY:返回最后插入的标识值 +--@@MAX_CONNECTIONS:返回允许同时进行的最大用户连接数 +--@@ROWCOUNT:返回受上一语句影响的行数 +--@@SERVERNAME:返回运行 SQL Server 的本地服务器的名称 +--@@SERVICENAME:返回 SQL Server 正在其下运行的注册表项的名称 +--@@TRANCOUNT:返回当前连接的活动事务数 +--@@LOCK_TIMEOUT:返回当前会话的当前锁定超时设置(毫秒) +``` + +## 输出语句 + +1. print变量或表达式 +2. select变量或表达式 + +```sql +--例: + print '数据库服务器名:' + @@servicename + select 15*8 +``` + + + +#### 使用convert函数 + +​ 由于PRINT 命令向客户端返回一个结果的字符串的信息。如果变量值不是字符串的话必须先用数据类型转换函数 CONVERT 将其转换为字符串。 + +```sql +--显示自动编号 +print '当前自动编号的值:' + convert(varchar(10),@@IDENTITY) +``` + +## 逻辑控制语句 + +### if...else... + +语句: + +```sql +IF(条件表达式) + BEGIN --相当于C#里的{ + 语句1 + …… + END --相当于C#里的} +ELSE + BEGIN + 语句1 + …… + END +``` + +例子: + +```sql +--1.查询S2002总分有没有超过250: 如果没有超过, 打印 不合格 超过250 打印合格 +declare @tscore int + +select @tscore = Chinese+English+Math from StuScore where StuID='S2001' + +print @tscore + +if @tscore>=240 +begin + if @tscore >=245 + begin + print '优秀' + end + else + begin + print '合格' + end +end +else +begin + print '不合格' +end +``` + +```sql +--2.判断男生平均成绩是否高于女生,如果男生平均成绩比女生高,输出男生中的第一名, 否则输出女生中的第一名 +--查出男生,女生的平均成绩 +declare @maleScore float--男生平均成绩 +declare @femaleScore float--女生 +declare @max int --最高分 + +select @maleScore = avg(chinese+english+math) from StuScore where StuSex='男' --男生平均成绩 +select @femaleScore = avg(chinese+english+math) from StuScore where StuSex='女' --女生 + +if @maleScore>@femaleScore +begin + print '男生平均成绩高' + --男生第一名 + --max + --select @max = max(chinese+english+math) from StuScore where StuSex='男' + --print '男生最高分'+@max + select top 1 * from StuScore where Stusex = '男' order by (English+Chinese+Math) desc +end +else +begin + print '女生平均成绩高' + --select @max = max(chinese+english+math) from StuScore where StuSex='女' + --print '女生最高分'+@max + + select top 1 * from StuScore where StuSex='女' order by (English+Chinese+Math) desc +end +``` + +```sql +--3.计算平均分数并输出,如果平均分数超过分输出成绩最高的三个学生的成绩,否则输出后三名的学生 +declare @avg int --定义变量 +select @avg= AVG(english) from Score --为变量赋值 +select '平均成绩'+CONVERT(varchar,@avg) --打印变量的值 + if @avg<60 + begin + select '前三名' + select top 3 * from Score order by english desc + end + else + begin + select '后三名' + select top 3 * from Score order by english + end +``` + +```sql +--4. 为赵云此人进行开户开卡操作,赵云身份证:420107199904054233 +declare @AccountId varchar +if exists(select * from AccountInfo where AccountCode=420107199904054233) + begin + select @AccountId =(select AccountId from AccountInfo WHERE AccountCode='420107199904054233') + insert into BankCard(CardNo,AccountId,CardPwd,CardMoney,CardState) + values('6225547858741233',2,'123456',0,1) + end +else + begin + insert into AccountInfo(AccountCode,AccountPhone,RealName,OpenTime) + values('420107199904054233','17634449035','赵云',GETDATE()) + set @AccountId=@@IDENTITY + insert into BankCard(CardNo,AccountId,CardPwd,CardMoney,CardState) + values('6225547858741666',@AccountId,'123456',0,1) + end +``` + + + +### case-when + +例子: + +```sql +1、case…end (具体的值) +case后面有值,相当于c#中的switch case +注意:case后必须有条件,并且when后面必须是值不能为条件。 +-----------------case--end---语法结构--------------------- +select name , --注意逗号 + case level --case后跟条件 + when 1 then '骨灰' + when 2 then '大虾' + when 3 then'菜鸟' + end as'头衔' +from [user] +``` + +```sql +2、case…end (范围) +case 后面无值,相当于c#中的if…else if…else…. +注意:case后不根条件 +------------------case---end-------------------------------- +select studentId, + case + when english between 80 and 90 then '优' + when english between 60 and 79 then '良' + else '差' + end + from Score +------------------case---end-------------------------------- +select studentId, + case + when english >=80 then '优' + when english >=60 then '良' + else '差' + end + from Score +----------------------------------------------------- +select *, + case + when english>=60 and math >=60 then '及格' + else '不及格' + end +from Score +``` + +```sql +--3.将成绩表中的学生成绩用五分制显示 +select stuName,stuID,english, +case + when english>=80 then '5分' + when english>=60 then '4分' + when english>=40 then '3分' + when english>=20 then '2分' + when english>=0 then '1分' + else '0分' +end '5分制' +from StuScore +inner join StuInfo on StuScore.StuID = StuInfo.StuNo +``` + +```sql +--4.查询银行卡信息,将银行卡状态1,2,3,4分别转换为汉字“正常,挂失,冻结,注销”, +--并且根据银行卡余额显示银行卡等级 30万以下为“普通用户”,30万及以上为"VIP用户", +--显示列分别为卡号,身份证,姓名,余额,用户等级,银行卡状态。 +select CardNo,AccountCode,RealName,CardMoney, +case + when cardmoney>300000 then 'VIP用户' + when cardmoney<300000 then '普通用户' +end '用户等级', + +case + when CardState =1 then '正常' + when CardState =2 then '挂失' + when CardState =3 then '冻结' + when CardState =4 then '注销' +end '银行卡状态' +from BankCard +join AccountInfo on AccountInfo.AccountId=BankCard.AccountId +``` + +```sql +--5.某用户银行卡号为“6225547854125656”,该用户执行取钱操作,取钱5000元, +--余额充足则进行取钱操作,并提示"取钱成功",否则提示“余额不足”。 +declare @mon money,@carno varchar(20)='6225547854125656' +select @mon=CardMoney from BankCard where CarNo = 6225547854125656 +print @mon +if @mon>5000 +begin + update BankCard set CardMoney = CardMoney-5000 where CardNo=@carno + insert into CardExchange values(@carno,0,5000,GETDATE()) + print '取钱成功' +end +else +begin + print '余额不足' +end +``` + + + +### while + +可以通过break和continue控制循环语句中的执行。 + +语句: + +```sql +WHILE(条件表达式) + BEGIN --相当于C#里的{ + 语句 + …… + BREAK + END --相当于C#里的} +``` + +例子: + +```sql +--1.循环打印1到10 +declare @a int = 1 +while (@a <= 10) +begin + print @a + set @a = @a + 1 +end +``` + +```sql +--2.打印99乘法表 +declare @i int = 1 + +while @i<=9 +begin + declare @j int = 1 + declare @result varchar(500) = '' + while @j<=@i + begin + --显示 + --不会自动转换类型,需要强转 + --set @result = @result + convert(varchar(2), @i) + ' * ' + convert(varchar(2), @j) + ' = '+ convert(varchar(2),@i*@j) + char(9) + --cast + set @result = @result + cast(@i as varchar(1)) + ' * ' + cast(@j as varchar(1)) + ' = '+ cast(@i*@j as varchar(1)) + char(9) + --控制J变量 + set @j =@j + 1 + end + print @result + set @i = @i + 1 +end +``` + +```sql +--3.如果不及格的人超过半数(考试题出难了),则给每个人增加分 +select * from Score +declare @conut int,@failcount int,@i int=0 --定义变量 +select @conut =COUNT(*) from Score --统计总人数 +select @failcount =COUNT(*) from Score where english<100 --统计未及格的人数 +while (@failcount>@conut/2) + begin + update Score set english=english+1 + select @failcount=COUNT(*) from Score where english<100 + set @i=@i+1 + end +select @i +update Score set english=100 where english >100 +``` + +### 连接 + +例子: + +```sql +select sName,sAge, + case + when english <60 then '不及格' + when english IS null then '缺考' + else CONVERT(nvarchar, english) + end as'英语成绩' +from student as s +left join Score as c on s.sid =c.sid + +内连接 inner join...on... + 查询满足on后面条件的数据 + + 外连接 + 左连接 + left join...on... + 先查出左表中的所有数据 + 再使用on后面的条件对数据过滤 + 右连接 + right join...on... + 先查出右表中的所有数据 + 再使用on后面的条件对数据过滤 + 全连接 + full join ...on... + +(*)交叉连接 + cross join 没有on + 第一个表的每一行和后面表的每一行进行连接 + 没有条件。是其它连接的基础 +``` + +```sql +--练习:将StuScore成绩表中的学生成绩用五分制显示。 +--​ 5分:80分以上 +--​ 4分:60~79分 +--​ 3分:40~59分 +--​ 2分:20~39分 +--​ 1分:0~19分 +select stuName,stuID,english, +case + when english>=80 then '5分' + when english>=60 then '4分' + when english>=40 then '3分' + when english>=20 then '2分' + when english>=0 then '1分' + else '0分' +end '5分制' +from StuScore +inner join StuInfo on StuScore.StuID = StuInfo.StuNo +``` + +## 批处理语句 + +go语句特点: + +1. 等待go语句前的代码执行完成后,再执行go后面的代码。 +2. 批处理语句的结束标志。 + +```sql +--下面的@num变量作用域为全局 +--declare @num int +--set @num = 0 + +--下面的@num变量的作用域是局部,只在两个go之间可以使用,最后一行代码会报错 +--.........sql代码 +--go +--declare @num int +--set @num = 0 +--go +--set @num = 1 +``` + +### 比较运算符 + +SQLServer中有三个关键字可以修改比较[运算符](https://so.csdn.net/so/search?q=运算符&spm=1001.2101.3001.7020):All、Any和Some,其中Some和Any等价 + +```sql +set nocount on + +use tempdb +go + +if (object_id ('t1') is not null)drop table t1 +create table t1 (n int) +insert into t1 select 2 unionselect 3 + +if (object_id ('t2') is not null)drop table t2 +create table t2 (n int) +insert into t2 select 1 unionselect 2 union select 3 union select 4 + +-- t1表数据 2,3 +-- t2表数据 1,2,3,4 +-- '>all' 表示:t2表中列n的数据大于t1表中列n的数据的数,结果只有4. +select * from t2 where n > all(select n from t1 ) --4 +select * from t2 where n > any(select n from t1 ) --3,4 +select * from t2 where n > some(selectn from t1) --3,4 + +select * from t2 where n = all(select n from t1 ) --无数据 +select * from t2 where n = any(select n from t1 ) --2,3 +select * from t2 where n = some(selectn from t1) --2,3 + +select * from t2 where n < all(select n from t1 ) --1 +select * from t2 where n < any(select n from t1 ) --1,2 +select * from t2 where n < some(selectn from t1) --1,2 + +select * from t2 where n <>all (select n from t1 ) --1,4 +select * from t2 where n <>any (select n from t1 ) --1,2,3,4 +select * from t2 where n <>some(select n from t1) --1,2,3,4 +set nocount off +``` + +注意: + +1. =any 与in 等效. + +2. 如果t1中包含null数据,那么所有All相关的比较运算将不会返回任何结果。因为t1和t2表的null的存在他们和notexists之类的比较符会有一些区别。 + 比如下面两句 + +```sql +select * from t2 a where not exists(select1 from t1 where n>=a.n) + +select * from t2 where n > all(select n from t1) +``` + +# 嵌套/子查询 + +### 子查询的特点和优势 + +1)使用灵活。 + +1. 可以成为SQL 语句的多个部分。 +2. **子查询作为查询条件使用**。 + +### 按结果分类 + +### 标量子查询 : + +**通常可以使用连接查询替代** + +标量子查询是指子查询返回的是**单一值**,如一个数字或一个字符串。 + +```sql +--1.查询书目表(tb_bibliography)中,条码号(barcode)为"TP311.13"图书(需要在图书表中先查找"TP31L13"的ISBN号)的图书名称(name)和作者(author) + + +--2.查询借阅表(tb-record)中姓名为"邓承明"(需要在学生表中先查找"邓承明'的学号)的学生的借阅信息,显示学号(stu-num)和条码号(barcode) +``` + + + +### 列子查询 + +**列子查询是指子查询返回的结果集是N行1列**,该结果通常来自对表某个字段的查询结果,带in关键字的子查询是最常用的一类子查询,在使用in关键字进行查询时,子查询语句返回的结果应该是一个数据列中的多个值,如果仅返回1个数值,则可用标量子查询代替。 + +```sql +--in习题 +--查询学生表(tb-student)中和黄弘相同专业学生读者的学号(stu-num)姓名(name)和专业(major) +--先查询 黄宏的 专业 +select major from tb_student where name='黄弘' +--in代表:只要符合后面的条件就筛选出来 +select * from tb_student where major in (select major from tb_student where name='黄弘') + + +--查询学生表(tb-student)中还未还书的读者的学号(stu-num)和姓名(name) +--查询未还书学生的学号 +select stu_num from tb_record where return_time is null +--通过学号查询学生姓名 +select * from tb_student where stu_num in (select stu_num from tb_record where return_time is null) + + +--all any some 习题 +--1.查询学生表(tb-student)中,比信息学院出生日期最大的还要大的所有学生记录,即比信息学院年龄最小的还要小的所有记录,使用ALL关键字,显示学生的姓名(name)、出生日期(birth)和所属学院(school),同样的结果尝试用max()函数再实现一次。 +--信息学院学生最小年龄 +select birth from tb_student where school='信息学院' +select max(birth) from tb_student where school='信息学院' + +select * from tb_student where birth>(select max(birth) from tb_student where school='信息学院' ) + +--all关键字:>,<,= +select * from tb_student where birth>all(select birth from tb_student where school='信息学院') +--2.查询学生表(tb-student)中,比信息学院出生日期最小的还要大的所有学生记录,即比信息学院年龄最大的还要小的所有记录,使用ANY关键字,显示学生的姓名(name)、出生日期(birth)和所属学院(school)。尝试用SOME关键字代替ANY,重新执行后观察查询结果。 +select * from tb_student where birth>any(select birth from tb_student where school='信息学院') +select * from tb_student where birth>some(select birth from tb_student where school='信息学院') +--3.查询书目表(tb-bibliography)中,使用ANY关键字,每种类型中最贵的图 书名称(name)和价格(price) +-- =any 与 in 等价 +select max(price) 最贵的价格 from tb_bibliography group by category +select name 图书名称,price 价格 from tb_bibliography +where price in (select max(price) 最贵的价格 from tb_bibliography group by category) + +``` + + + +## 行子查询 + +行子查询是指子查询返回的结果集是1行N列,该子查询的结果通常是对表的某行数据进行查询而返回的结果集。 + +```sql +--(1)查询书目表(tb_bibliography)中与《管理信息系统实用教程(第3版)》同作者(author),同类型(category)的书。 +--(2)查询学生表(tb_student)中与"邹睿睿'在同一个学院(school)且同一年级(学号头两位相同则表明在同一年级)学生的学号、姓名和学院。 +``` + + + +## 表子查询(from子查询) + +表子查询是指子查询返回是M行N列的结果集,查询语句可嵌套在FROM关 +键字后,且需要定义别名。 + +```sql +--查询每种图书在馆的本数,显示ISBN号(ISBN)、图书名称(name)和该图书的在馆数量。 +``` + + + +## 按位置分类 + +### exists子查询 + +关键字EXISTS构造子查询时,当子查询的结果集不为空时,则EXISTS返回的结果为TRUE,外层查询语句进行查询;当子查询的结果集为空时,则EXISTS返回的结果为FALSE,外层查询语句不进行查询。 + +```sql +--(1)查询学生表(tb-student)中,是否有学生读者的姓名是"黄弘" +if exists(select stu_num from tb_record where stu_num in (select stu_num from tb_student where name='黄弘') and return_time is null) + print '有' +else + print '没有' + +--(2)查询书目表(tb-bibliography)中,库存数为0的书目名称(name) +``` + +## 排序函数(关联和非关联子查询) + +**排序函数 over( [分组子句] 排序子句[DESC][ASC] ) + +**排序子句 :order by 排序列,排序列…* + +- row_number()函数:生成的排序根据排序子句给出**递增连续的序号** + +- rank() 函数:生成的排序根据排序子句给出**递增的序号,但是存在并列并且跳空** + +- dense_rank():生成的排序根据排序子句给出**递增的序号,但是存在并列不跳空* + + + +- ntile():是将有序分区中的行分发到指定数目的组中,各个组有编号,编号从1开始,就像我们说 的’分区’一样 ,分为几个区,一个区会有多少个。 + +根据上面三个函数,我们可以增加一个序列,但是有时候我们需要对数据进行分组,然后对分组后的数据进行增加序列,PARTITION BY可以与以上三个函数联合使用 + +```sql +--学生的Java成绩,并根据成绩排名 +--row_number() +select StuName 姓名,ROW_NUMBER() over(order by score desc) 排名,score 分数 from StuScore +join stuinfo on StuInfo.StuID = StuScore.StuID +where subject = 'Java' +123456 + +--rank() +select StuName 姓名,rank() over(order by score desc) 排名,score 分数 from StuScore +join stuinfo on StuInfo.StuID = StuScore.StuID +where subject = 'Java' +122456 + +--DENSE_RANK() + select StuName 姓名,dense_rank() over(order by score desc) 排名,score 分数 from StuScore +join stuinfo on StuInfo.StuID = StuScore.StuID +where subject = 'Java' +122345 +``` + + + +```sql +--排序函数 +select birth,姓名,性别 from ( +select birth,name 姓名,gender 性别,row_number() over (order by birth ) as birth_rank from tb_student +) as T1 +where T1.birth_rank = 1 + +--查询男生和女生中年龄最大的学生信息,要求显示:姓名,性别,年龄 +--非关联子查询 +select birth,name 姓名,gender 性别 from tb_student +where birth in (select min(birth) from tb_student group by gender) + +--关联子查询:内部查询需要引用外部表已查询出的信息 +select birth,name 姓名,gender 性别 from tb_student t1 +where birth = (select min(birth) from tb_student t2 where t2.gender=t1.gender) + +--窗口函数:排序 +select birth,姓名,性别 from ( +select birth,name 姓名,gender 性别,row_number() over (partition by gender order by birth ) as birth_rank from tb_student +) as T1 +where T1.birth_rank = 1 +``` + +```sql +--分数排序 +select score, dense_rank() over (order by score desc) as 'rank' +from scores; +``` + + + +# 分页查询 + +# 索引 + +### 1.**含义:** + +索引是一种单独的、物理的对数据库表中一列或多列的值进行排序的特殊数据库结构,它是某 个表中一列或若干列值的[集合](https://so.csdn.net/so/search?q=集合&spm=1001.2101.3001.7020)和相应的指向表中物理标识这些值的数据页的逻辑指针清单。索引的作用相当于图书的目录,可以根据目录中的页码快速找到需要的内容。 + +**理解实例:** + +汉语字典中的汉字按页存放,一般都有汉语拼音目录(索引)、偏旁部首目录等我们可以根据拼音或偏旁部首,快速查找某个字词。 + +![](https://gitee.com/snailclass/tuchuang/raw/master/img/book1-2022-9-1310:41:20.png) + + + +### 2.**作用:** + +- 提高查询速度(数据量大的时候,索引查询效率更快) + +- 保证数据记录的唯一性 + +- 查询优化靠索引起作用 + +- 提高order by, group by 执行速度 + +### 3.**索引分类**: + +​ **1.聚集索引**::根据数据行的键值在表或视图中的排序存储这些数据行,每个表只有一个聚集索 + +​ 引。聚集索引是一种对磁盘上实际数据重新组织以按指定的一列或多列值排序 + +​ (类似字典中的拼音索引),(物理存储顺序)。 + +​ **{主键是聚集索引}** + +​ **2.非聚集索引**:具有独立于数据行的结构,包含非聚集索引键值,且每个键值项都有指向包含 + +​ 该键值的数据行的指针。(类似字典中的偏旁部首索引)(逻辑存储顺序)。 + +​ {unique为非聚集索引} + +#### **其它类型的索引**: + +- 按照数据唯一性分类:唯一索引、非唯一索引 +- 按键列个数区分:单列索引,多列索引 + +- 其他分类:索引视图、包含性列索引、全文索引、XML索引等 + +### 4.利弊: + +1.使用索引是为了避免全表扫描,因为全表扫描是从磁盘上读取表的每一个数据页,如果有索引指向数据值,则只需要读少次数的磁盘就可以。2.带索引的表在数据库中占用更多的空间,同样增、删、改数据的命令所需时间会更长。 + +### 5.注意事项: + +- 使用聚集索引的查询效率要比非聚集索引的效率要高,但是如果需要频繁去改变聚集索引的值,写入性能并不高,因为需要移动对应数据的物理位置。 + +- 非聚集索引在查询的时候可以的话就避免二次查询,这样性能会大幅提升。 + +- 不是所有的表都适合建立索引,只有数据量大表才适合建立索引,且建立在选择性高的列上面性能会更好 + +- 在where后使用or,导致索引失效(尽量少用or) + + 语句: + + ```sql + Select * from table1 where tid in (2,3)和Select * from table1 where tid=2 or tid=3 + + 是一样的,都会引起全表扫描,如果tid上有索引,其索引也会失效。 + ``` + +- 使用like ,like查询是以%开头,以%结尾不会失效 + +- 不符合最左原则(多列索引) + +- 如果列类型是字符串,那一定要在条件中将数据使用引号引用起来,否则不使用索引 + +- 使用in导致索引失效 + +### 6.什么情况下使用 + +- 定义主键的数据列(sql server默认会给主键一个聚集索引)。 +- 定义有外键的数据列 +- 对于经常查询的数据列 +- 对于需要在指定范围内频繁查询的数据列 +- 经常在where子句中出现的数据列 +- 经常出现在关键字 order by、group by、distinct后面的字段。 + +### 7.什么情况不使用 + +- 查询中很少涉及的列,重复值比较多的列。 +- text、image、bit数据类型的列 +- 经常存取的列 +- 经常更新操作的表,索引一般不要超过3个、最多不要5个。虽说提高了访问速度,但会影响更新操作。 + +### 8.例子: + +```sql +--创建索引 +--创建非聚集索引(默认创建非聚集) + +create (nonclustered) index IDX_Name on 表(字段) +``` + +```sql +--使用索引 + +select * from 表名 with(index=索引名) +where 条件 +``` + +```sql +--删除索引: +drop index 索引名 on 表名 +``` + +```sql +--查询索引: +exec 索引名 表名 +``` + +```sql +--查询系统内有多少索引: +select * from dbo.sysindexes where 字段 = 索引名 +``` + +```sql +--更新表中所有索引的统计: +update` `statistics` `ceshi +``` + +```sql +--更新索引名: +https://www.jb51.net/article/248614.htm#_lab2_3_9 +``` + +# 视图 + +### 1.**个人理解**: + +``` +相当于创建了一张基于基表的临时虚拟表。 +注意:当视图虚拟表已经创建时,再修改基表,不会改变虚拟表的数据。(自己已经证明过了) +``` + +### 2.**网页理解**: + +``` +视图包含行和列,就像一个真实的表。视图中的字段就是来自一个或多个数据库中的真实 的表中的字段。我们可以向视图添加 SQL 函数、WHERE 以及 JOIN 语句,我们也可以提交数据,就像这些来自于某个单一的表。 +视图一般情况下是不存储数据的。 +``` + +### 3.作用: + +``` +1.用来简化复杂的查询逻辑,在视图结构的基础上可以做二次处理,但是若视图只有一张表的话,需要包含表中的必填列才可以进行增删改操作 +2.保护数据安全性 +注:数据库的设计和结构不会受到视图中的函数、where 或 join 语句的影响 +``` + +### 4.例子: + +```sql +--判断视图是否存在 +if exists(select * from sysobjects where name='View_ScareQuery') + +https://blog.csdn.net/qq_34202873/article/details/88797637 +``` + + + +```sql +--创建视图 +--1.行列子集视图 +create view 视图名(临时字段名,例:学号,姓名,学院,专业) +as +(select stu_num ,name ,school ,major from tb_student where school='信息学院') +go + +--注意:()里为临时表,也可以进行连表操作,例如join,left join...... +``` + +```sql +--2.with check option:视图更新 +**注意:**视图更新可以,但是最好在基表上面进行 + +create view 视图名(临时字段名,例:学号,姓名,学院,专业) +as +(select stu_num ,name ,school ,major from tb_student where school='信息学院') +with check option +go + + +一.【当对虚拟表进行修改时也会修改基表的数据】 +update V_StuMajor set 姓名='王博文' where 学号=16130201 + + + +二.【当使用 with check option只允许对where后相同条件进行插入,例如:where school='信息学院'才能执行以下操作】 +insert V_StuMajor values(16101011,'蜗牛','信息学院','统计') + +``` + +```sql +--3.带表达式的视图 +定义一个反映学生年龄的视图 +create view V_StuAge(学号,姓名,年龄,学院,专业) +as +(select stu_num ,name ,year(getdate())-year(birth),school,major from tb_student) + +select * from V_StuAge +``` + +```sql +--4.删除视图 +drop view 视图名称 +``` + +```sql +--5.视图可以作为临时表与其他基表连接 +select * from [Rank] +join View_DepartmentNamess on [Rank].RankId=View_DepartmentNamess.序号 +``` + +```sql +--6.基于视图的视图(视图也可作为基表) +create view View_DepartmentNamesss +as +(select 序号,简介 from View_DepartmentNamess) + +select * from View_DepartmentNamesss +``` + +```sql +--7.基于多个基表的视图 + +``` + + + +### 5.视图优缺点 + +```sql +--优点-- +● 简单性。视图不仅可以简化用户对数据的理解,也可以简化他们的操作。那些被经常使用的查询可以被定义为视图,从而使用户不必为以后的操作每次都指定全部的条件。 +● 安全性。通过视图用户只能查询和修改他们所能见到的数据。数据库中的其他数据则既看不见也取不到。数据库授权命令可以使每个用户对数据库的检索限制到特定的数据库对象上,但不能授权到数据库特定行和特定的列上。通过视图,用户可以被限制在数据的不同子集上。 +● 逻辑数据独立性。视图可以使应用程序和数据库表在一定程度上独立。如果没有视图,应用一定是建立在表上的。有了视图之后,程序可以建立在视图之上,从而程序与数据库表被视图分割开来。 + +--缺点-- +● 性能:SQL Server必须把视图的查询转化成对基本表的查询,如果这个视图是由一个复杂的多表查询所定义,那么,即使是视图的一个简单查询,SQL +● 修改限制:当用户试图修改视图的某些行时,SQL Server必须把它转化为对基本表的某些行的修改。对于简单视图来说,这是很方便的,但是,对于比较复杂的视图,可能是不可修改的。 + +``` + +# 事务 + +### 含义: + +``` +事务( Transaction)由一次或者多次基本操作构成,或者说,事务由一条或者多条 SQL 语句构成。 +事务中的所有 SQL 语句是一个整体,共同进退,不可分割,要么全部执行成功,要么全部执行失败。 +``` + +### 四个属性: + +```sql +--1.原子性 +一个事务中的所有 SQL 语句,要么全部执行成功,要么全部执行失败,不会结束在中间的某个环节。事务在执行过程中发生错误,会被回滚(Rollback)到事务开始前的状态,就像这个事务从来没有执行过一样。 +--2. 一致性 +在事务开始之前和事务结束以后,数据库的完整性没有被破坏。这表示写入的数据必须完全符合所有的预设规则,其中包含数据的精确度、串联性以及后续数据库可以自发性地完成预定的工作。 +--3.隔离性 +数据库允许多个并发事务同时对其数据进行读写和修改的能力,隔离性可以防止多个事务并发执行时由于交叉执行而导致数据的不一致。事务隔离分为不同级别,包括读未提交(Read uncommitted)、读提交(read committed)、可重复读(repeatable read)和串行化(Serializable)。 死锁 操作系统 +--4. 持久性 +事务处理结束后,对数据的修改就是永久的,即便系统故障也不会丢失。 +``` + +### 事务流程 + +![](https://gitee.com/snailclass/tuchuang/raw/master/img/image-20220916113630148-2022-9-1611:40:42.png) + +一、begin tran + +```sql +事务的开始:事务的开始可能是事务过程中最容易理解的概念。它唯一的目的就是表示一个单元的开始。如果由于某种原因,不能或者不想提交事务,那么这就是所有数据库活动将要回滚的起点。也就是说,数据库会忽略这个起点之后的最终没有提交的所有语句。 + +use test + go + --启动一个事务向student表中插入一个记录 + begin transaction + insert into student values(100,'陈浩','男',19) + commit tran + select * from student + go +``` + +二、commit tran + +```sql +事务的提交,终点:事务的提交是一个事务的终点。当发出COMMIT TRAN命令时,可以认为该事务是持久的。也就是说,事务的影响现在是持久的并会持续,即使发生系统故障也不受影响(只要有备份或者数据库文件没有被物理破坏就行)。撤销已完成事务的唯一方法是发出一个新的事务。从功能上而言,该事务是对第一个事务的反转。 +``` + +三、rollback tran + +```sql +做的事务回到起点:ROLLBACK做的事情是回到起点。从关联的BEGIN语句开始发生的任何事情事实上都会被忘记。除了允许保存点外,ROLLBACK的语法看上去和BEGIN或COMMIT语句一样: + +--启动一个事务向student表中删除一个记录,然后回滚该事务 + begin transaction + delete student where sno=100 + rollback + + select * from student --由于回滚该事务,因此表中没有插入记录 + go +``` + +四、save tran + +```sql +保存事务,可以回滚到代码的特定点上:保存事务从本质上说就是创建书签(bookmark)。为书签建立一个名称,在建立了"书签"之后,可以在回滚中引用它。创建书签的好处是可以回滚到代码中的特定点上-只要为想要回滚到的那个保存点命名。 + +1 /*在事务内设置保存点*/ +2 begin transaction mytran --启动事务 +3 select * from student +4 save transaction s1 --设置保存点。 +5 insert into student values(200,'王洪','男',22) --插入另一个学生的 +6 rollback transaction s1 --事务回滚到保存点s1 +7 commit transaction +8 go +9 select * from student --陈浩插入到表中而王洪没有插入到表中 +``` + +不能用于事务的操作 + +```sql +操作 相应的SQL语句 +创建数据库 CREATE DATABASE +修改数据库 ALTER DATABASE +删除数据库 DROP DATABASE +恢复数据库 RESTORE DATABASE +加载数据库 LOAD DATABASE +备份日志文件 BACKUP LOG +恢复日志文件 RESTORE LOG +更新统计数据 UPDATE STATISTICS +授权操作 GRANT +复制事务日志 DUMP TRANSACTION +磁盘初始化 DISK INIT + +更新使用sp_configure系统存储过 +程更改的配置选项的当前配置值 RECONFIGURE + +``` + +五、实例 + +```sql +课后自己练习 + +alter table Bank add constraint CK_moneys check(moneys>20) + +begin transaction +declare @sum int =0 +update Bank set Moneys = Moneys-20 where Name='张三' +set @sum = @sum+@@error; +update Bank set moneys = Moneys+20 where Name ='李四' +set @sum +=@@ERROR; + +if @sum>0 + begin + print'交易失败' + rollback + end +else + begin + print'交易成功' + commit + end +``` + + + +```sql +begin tran Tran_Money; --开始事务 +declare @tran_error int; +set @tran_error = 0; + +begin try + update tb_Money set MyMoney = MyMoney - 30 where Name = '刘备'; + set @tran_error = @tran_error + @@ERROR; + + --测试出错代码,看看刘备的钱减少,关羽的钱是否会增加 + --SET @tran_error = 1; + update tb_Money set MyMoney = MyMoney + 30 where Name = '关羽'; + set @tran_error = @tran_error + @@ERROR; +end try +begin catch + print '出现异常,错误编号:' + convert(varchar, error_number()) + ',错误消息:' + error_message(); + + set @tran_error = @tran_error + 1; +end catch; + +if ( @tran_error > 0 ) + begin + --执行出错,回滚事务 + rollback tran; + print '转账失败,取消交易!'; + end; +else + begin + --没有异常,提交事务 + commit tran; + print '转账成功!'; + end; +``` + + + +```sql +设置约束 +alter table BankCard add constraint CK_cardmoney check(CardMoney>=0) + +begin transaction +declare @mon money = 1000 +declare @no varchar(20), @no1 varchar(20) +declare @err int = 0 +declare @zf varchar(5) = (select AccountId from AccountInfo where RealName = '张飞') --张飞ID +declare @lb varchar(5) = (select AccountId from AccountInfo where RealName = '刘备') --刘备ID +select @no = cardno from BankCard where AccountId= @lb --no:刘备的卡号 +select @no1 = cardno from BankCard where AccountId= @zf --No1:张飞的卡号 + +--刘向张转1000 +--刘备余额-1000 +--张飞余额+1000 +--生成转账记录 +--生成交易记录(刘备出,张飞进) +update BankCard set CardMoney = CardMoney-@mon where AccountId = @lb --刘备-1000 +set @err += @@ERROR +update BankCard set CardMoney = CardMoney+@mon where AccountId = @zf --张飞+1000 +--转账记录 +insert CardTransfer values(@no,@no1,@mon,GETDATE()) +--交易记录 +insert CardExchange(CardNo,MoneyInBank,MoneyOutBank,ExchangeTime) values(@no,0,@mon,getdate()) --刘备outmoney +insert CardExchange(CardNo,MoneyInBank,MoneyOutBank,ExchangeTime) values(@no1,@mon,0,getdate()) --张飞inmoney + +if @err>0 + begin + print '转账失败' + rollback transaction + end +else + begin + print'转账成功' + + commit transaction + end +``` + +### 自动提交事务 + +``` +(每次执行sql语句,如插入语句等,执行成功都会自动提交事务,不成功则回滚事务) +SQL Server没有使用BEGIN TRANSACTION语句启动显式事务,或隐性事务模式未打开,将以自动提交模式进行操作。 +当提交或回滚显式事务或者关闭隐性事务模式时,SQL Server将返回到自动提交模式。 +``` + +### 显示事务 + +```sql +需要手动打开,手动提交事务,手动回滚事务 +例子: +begin trans +‘ +’ +commit trans +- +- +rollback transaction + +``` + +### 隐式事务 + +```sql +个人实例: +set implicit_transaction on +在执行上面的语句时,将会一直打开这个隐形事务,例如给表插进去一行数据 +系统会一直进行这个事务,直到运行下面的提交或回滚,查该表才能显示数据 +commit +``` + + + +```sql +隐性事务模式设置为打开之后,当SQL Server首次执行某些Transact-SQL语句时,都会自动启动一个事务,而不需要使用 BEGIN TRANSACTION 语句。 +启动新事务的Transact-SQL语句包括: +--在发出COMMIT或ROLLBACK语句之前,该事务一直保持有效。在第一个事务被提交或回滚之后,下 +--次当连接执行这些语句的任何语句时,SQL Server都将自动启动一个新事务。 +隐性事务模式可以通过使用SET语句来打开或者关闭,其语法格式为: +SET IMPLICIT_TRANSACTIONS { ON | OFF } +set implicit(a.隐性的,含蓄的)_transaction { on | off } +隐性事务模式打开时,用户必须在该事务结束时显式提交或回滚。 +隐性事务模式将保持有效,直到执行 SET IMPLICIT_TRANSACTIONS OFF 语句使连接返回到自动提交模式。 + +例如: + /*演示在将IMPLICIT_TRANSACTIONS设置为ON时显式或隐式启动事务。 + 使用@@trancount函数返回当前连接的活动事务数。 */ + set nocount on + print cast(@@trancount as char(5)) + create table table1(a int) + insert table1 values(1) + go + print cast(@@trancount as char(5)) + + print '使用显式事务' + begin tran + insert table1 values(2) + print '当前连接的活动事务数:'+cast(@@trancount as char(5)) + commit tran + + print '当前连接的活动事务数:'+cast(@@trancount as char(5)) + go + + print '设置 implicit_transactions为on' + set implicit_transactions on + go + print '使用隐式事务' + insert into table1 values(4) --这里不需要begin tran语句来定义事务 + print '当前连接的活动事务数:'+ cast(@@trancount as char(5)) + commit tran + print '当前连接的活动事务数:'+ cast(@@trancount as char(5)) + go + + drop table table1 + set implicit_transactions off + + /*BEGIN TRANSACTION 语句使 @@TRANCOUNT 递增 1。 + ROLLBACK TRANSACTION 将 @@TRANCOUNT 递减为 0, + 但 ROLLBACK TRANSACTION savepoint_name 语句并不影响 + @@TRANCOUNT 值。COMMIT TRANSACTION 将 @@TRANCOUNT 递减 1。*/ +``` + +### 分布式事务 + +```sql +跨越两个或多个服务器上的数据库的事务就是分布式事务。 +与本地事务的不同在于事务的提交(2pc) +控制分布式事务的T-SQL语句包括: begin distributed transaction 、 commit transactioncommit work 、 rollback transactionrollback work +``` + +### 数据的锁定 + +``` +并发问题包括:修改丢失;脏读;不可重复读;幻读 + +事务的隔离级别:未提交读;提交读;可重复读;可串行读 + +SQL SERVER 2005中的锁: 共享锁; 排它锁;更新锁;意向锁;架构锁 + +封锁技术需要解决的问题:死锁 +``` + + + +# 游标 + +### 含义 + +```sql +游标(Cursor)它使用户可逐行访问由SQL Server返回的结果集。使用游标(cursor)的一个主要的原因就是把集合操作转换成**单个记录处理方式**。用SQL语言从数据库中检索数据后,结果放在内存的一块区域中,且结果往往是一个含有多个记录的集合。游标机制允许用户在SQL server内逐行地访问这些记录,按照用户自己的意愿来显示和处理这些记录。 +``` + +### 缺点 + +``` +使用游标会把结果集一条条取出来处理,增加了服务器的负担,再者使用游标的效率远远没有使用默认结果集的效率高。所以,能不用游标就尽量不要 用。 +``` + +### 分类 + +```sql +(1)静态游标(Static):在操作游标的时候,数据发生变化,游标中数据不变 +(2)动态游标(Dynamic):在操作游标的时候,数据发生变化,游标中数据改变,默认值。 +(3)键集驱动游标(KeySet):在操作游标的时候,被标识的列发生改变,游标中数据改变,其他列改变, 游标中数据不变。 +``` + +### 使用 + +```sql +--1、创建游标 +(Scroll代表滚动游标,不加Scroll则是只进的,只能支持fetch next) +declare <游标名> cursor scroll for select stuname from stuinfo + +--2、打开游标 +open <游标名> + +--3、删除游标 +deallocate <游标名> + +--4、关闭游标 +close <游标名> + +``` + +### 提取数据操作 + +```sql +fetch first from <游标名> --结果集的第一行 +fetch last from <游标名> --最后一行 +fetch absolute 1 from <游标名> --从游标的第一行开始数,第n行。 +fetch relative 3 from <游标名> --从当前位置数,第n行。 +fetch next from <游标名> --当前位置的下一行 +fetch prior from <游标名> --当前位置的上一行 +``` + +### + +### 例子 + +```sql +--1.提取数据给变量以供它用(取出第3行学生姓名,查询该学生详细信息): +declare @vari varchar(20) +fetch absolute 3 from <游标名> into @vari +select * from StuInfo where stuName = @vari +``` + +```sql +--2.创建游标指向某行多列数据,并循环显示数据: + +declare @id int,@name varchar(20),@sex varchar(2),@cid int +declare mycursor cursor for(select * from StuInfo) +open mycursor +while @@FETCH_STATUS = 0 --@@FETCH_STATUS=0,提取成功,-1提取失败,-2行不存在 + begin + print convert(varchar(20),@id)+','+@name+','+@sex+','+cast(@cid as varchar(10)) + fetch next from mycursor into @id,@name,@sex,@cid + end + +close mycursor +``` + +# 函数 + + + +```sql +--删除函数 +drop function 函数名 +``` + +### 标量函数 + +含义:标量函数是对单一值操作,返回单一值。能够使用表达式的地方,就可以使用标量函数。像我们经常使用的left、getdate等,都属于标量函数。系统函数中的标量函数包括:数学函数、日期和时间函数、字符串函数、数据类型转换函数等。 + +```sql +--创建函数 +create function 函数名(传值或者不传值) +return 返回类型(int,varchar(20)````) +as + begin + 内容 + end +go +--调用函数 +select dbo.函数名(传值或者不传值) + +``` + +```sql +--例1: +--输入学号 输出该学生的总分 +go +create function GetSumScoreById(@stunum varchar(20)) +returns int +as +begin + + return (select Chinese+English+Math from StuScore where StuId = @stunum) +end +go + +select dbo.GetSumScoreById('S2002') 总分 + + + +--例2: +--实现两个值的加和 1+....+ 10 +go +create function Totalsum(@A int , @B int) +returns int +as +begin + declare @i int = @A + declare @sum int = 0 + while @i<=@B + begin + set @sum += @i --sum = sum + i + set @i += 1 + end + + return @sum +end +go +select dbo.Totalsum(1,10) +``` + +### 内嵌表值函数 + +含义:内嵌表值函数的功能相当于一个参数化的视图。它返回的是一个表,内联表值型函数没有由BEGIN-END 语句括起来的函数体。其返回的表由一个位于RETURN 子句中的SELECT 命令段从数据库中筛选出来。 + +### 多语句表值函数 + +含义:多语句表值函数可以看作标量型和内嵌表值型函数的结合体。它的返回值是一个表,但它和标量型函数一样有一个用BEGIN-END 语句括起来的函数体,返回值的表中的数据是由函数体中的语句插入的。由此可见,它可以进行多次查询,对数据进行多次筛选与合并,弥补了内联表值型函数的不足。 + +```sql +--输入学号 输出该学生信息:学号,姓名,总分 +go +create function GetInfoById(@id varchar(20)) +returns @tableInfo table(stuid varchar(20),stuName varchar(30), sumscore int) +as +begin + --往新表中插入数据 + insert into @tableInfo + --查询语句 + select StuScore.StuID,StuName,(Chinese+English+Math) total + from StuScore join StuInfo on StuInfo.StuNo=StuScore.StuID where StuName like '%'+@id+'%' + --返回 + return +end +go + +--drop function GetInfoById +--返回的表当做新表来查询 +select * from dbo.GetInfoById('无') +``` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -- Gitee