From 93a9d0a7890e84a31c70958da95a4fa479d4f0fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=90=B4=E6=98=8E=E6=9D=B0?= <3090356592@qq.com> Date: Wed, 21 Sep 2022 21:55:30 +0800 Subject: [PATCH] 9.21 --- ...32\344\271\211\345\207\275\346\225\260.md" | 178 ++++++++++++++++++ ...70\346\240\207\347\273\203\344\271\240.md" | 86 +++++++++ ...75\346\225\260\347\273\203\344\271\240.md" | 96 ++++++++++ 3 files changed, 360 insertions(+) create mode 100644 "15\345\220\264\346\230\216\346\235\260/\347\254\224\350\256\260/220921\350\207\252\345\256\232\344\271\211\345\207\275\346\225\260.md" create mode 100644 "15\345\220\264\346\230\216\346\235\260/\347\273\203\344\271\240/220920-\346\270\270\346\240\207\347\273\203\344\271\240.md" create mode 100644 "15\345\220\264\346\230\216\346\235\260/\347\273\203\344\271\240/220921-\345\207\275\346\225\260\347\273\203\344\271\240.md" diff --git "a/15\345\220\264\346\230\216\346\235\260/\347\254\224\350\256\260/220921\350\207\252\345\256\232\344\271\211\345\207\275\346\225\260.md" "b/15\345\220\264\346\230\216\346\235\260/\347\254\224\350\256\260/220921\350\207\252\345\256\232\344\271\211\345\207\275\346\225\260.md" new file mode 100644 index 0000000..f3a9dff --- /dev/null +++ "b/15\345\220\264\346\230\216\346\235\260/\347\254\224\350\256\260/220921\350\207\252\345\256\232\344\271\211\345\207\275\346\225\260.md" @@ -0,0 +1,178 @@ +# 十一、自定义函数 + + **在SQL server中不仅可以可以使用系统自带的函数(时间函数、聚合函数、字符串函数等等),还可以根据需要自定义函数。** + +**用户自定义函数的类型:** + +1. 标量值函数(返回一个标量值) +2. 表格值函数(内联表格值函数、多语句表值函数,返回一个结果集即返回多个值) + +**三种定义函数的不同点与共同点:** + +1. 标量值函数返回的是一个数据类型值 + + 内联表值函数返回的是一个table + + 多语句表值函数返回的是一个table的变量(类似前面两个的结合) + +2. 语法的结构:标量值函数和多语句表值函数都是要有begin.........................end,内联表值函数就没有 + +3. 调用:标量函数要写成在dbo.function_name; + +**共同点:他们的创建定义相同** + +```sql +create function 函数名(传入参数的名称 传入参数的类型) +returns 返回值数据类型 +as +``` + +**函数参数** + +参数可以是常量、表中的某个列、表达式或其他类型的值。在函数中有三种类型的参数。 + +1. 输入:指必须输入一个值。 + +2. 可选值:在执行该参数时,可以选择不输入参数。 + +3. 默认值:函数中默认有值存在,调用时可以不指定该值。 + +********* + +## (一)标量值函数的定义 + +```sql +create function 函数名称(参数名 参数的数据类型) +returns 返回返回值的数据类型 +[with encryption]--如果指定了encryption则函数被加密 +[as] +begin +--函数体(即 t-sql语句) +return 表达式 +end +``` + +示例:通过学生名字输出成绩 + +```sql +create function dbo.student_name_score(@sname nvarchar(30)) +returns int +as +begin + declare @sscore int + select @sscore=score from student where name=@sname + return @sscore +end + +select dbo.student_name_score('张三') name;--调用一定要在名称前加上dbo.,定义的时候如果名称前面没有dbo.调用也要加上 +``` + +****** + +## (二)内联表格值函数 + +**语法:** + +特点:内联表格值函数支持在where子句中使用参数 + +```sql +create function 函数名称(参数名 参数的数据类型) +returns table--返回一个表 +[with encryption]--如果指定了encryption则函数被加密 +[as] +--函数体(即 t-sql语句) +return (一条sql语句) +``` + +**示例:**通过id差姓名和成绩 + +```sql +create function dbo.student_name_score2(@sid int) +returns table +as +return select name,score from student where id=@sid + +select * from dbo.student_name_score2(3) +``` + +********* + +## (三)多语句表值函数 + + 多语句表值函数跟内联表值函数都是表值函数,它们返回的结果都是Table类型。多语句表值函数通过多条语句来创建Table类型的数据。**这里不同于内联表值函数,内联表值函数的返回结果是由函数体内的SELECT语句来决定。而多语句表值函数,则是需要指定具体的Table类型的结构。**也就是说返回的Table已经定义好要哪些字段返回。所以它能够支持多条语句的执行来创建Table数据。 + +**语法:** + +```sql +create function 函数名称(@参数名 参数的数据类型) +returns @Table_Variable_Name table (Column_1 culumn_type,Column_2 culumn_type) +--returns @表变量 table 表的定义(即列的定义和约束) +[with encryption] --如果指定了encryption则函数被加密 +[as] +begin + 函数体(即T-SQL 语句) +return +END +``` + +**示例:**通过id查询该学生所有信息的函数 + +```sql +create function dbo.student_table_id(@sid int) +returns @table_test table(id int ,name nvarchar(30),score int) +as +begin +insert @table_test select id,name,score from student where id=@sid +--把student表查询结果插入@tabel——test +return +end + +select * from dbo.student_table_id(1) +``` + +********* + +## (四)自定义函数的修改和删除 + +### 1.使用alter语句修改自定义函数: + +```sql +alter function 函数名(参数) +returns table +as +return(一条SQL语句) +``` + +### 2.使用drop语句删除: + +```sql +drop function func_date_get_name +``` + +******** + +(五)编写函数的注意事项 + +**标量函数:** + +1. 所有的入参前都必须加@ + +2. create后的返回,单词是returns,而不是return + +3. returns后面的跟的不是变量,而是返回值的类型,如:int,char等。 + +4. 在begin/end语句块中,是return。 + +**内联表格值函数:** + +1. 只能返回table,所以returns后面一定是TABLE + +2. AS后没有begin/end,只有一个return语句来返回特定的记录。 + +**多语句表值函数:** + +1. returns后面直接定义返回的表类型,首先是定义表名,表明前面要加@,然后是关键字TABLE,最后是表的结构。 + +2. 在begin/end语句块中,直接将需要返回的结果insert到returns定义的表中就可以了,在最后return时,会将结果返回。 + +3. 最后只需要return,return后面不跟任何变量。 \ No newline at end of file diff --git "a/15\345\220\264\346\230\216\346\235\260/\347\273\203\344\271\240/220920-\346\270\270\346\240\207\347\273\203\344\271\240.md" "b/15\345\220\264\346\230\216\346\235\260/\347\273\203\344\271\240/220920-\346\270\270\346\240\207\347\273\203\344\271\240.md" new file mode 100644 index 0000000..c477ff5 --- /dev/null +++ "b/15\345\220\264\346\230\216\346\235\260/\347\273\203\344\271\240/220920-\346\270\270\346\240\207\347\273\203\344\271\240.md" @@ -0,0 +1,86 @@ +select * from tb_bibliography --书 +select * from tb_book --书编号 +--select * from tb_inf_student --特长 +select * from tb_record --借书 +select * from tb_student + + + + + +--- 创建学生游标,该游标包含(学生姓名,兴趣爱好,生源地,荣誉总数) + +``` +declare students cursor scroll for(select name,hobby,ori_loca,prize from tb_student s join tb_inf_student i on s.stu_num=i.stu_num) + +open students + +fetch next from students + +close students +``` + +--- 循环遍历161开头的学生信息 + +``` +declare stunum cursor scroll for(select * from tb_student where stu_num like '%161_%') + +open stunum + +declare @stu_num char(8) ,@name varchar(8),@gender bit ,@birth date ,@school varchar(10),@major char(20) +fetch first from stunum --要在第一行才能进来 +while @@FETCH_STATUS=0 +begin + print @stu_num+','+@name+','+cast( @gender as varchar(10))+','+cast( @birth as varchar(10))+','+@school+@major + fetch next from stunum into @stu_num,@name,@gender,@birth,@school,@major +end + +close stunum +``` + +--- 使用游标统计生源地为北京的荣誉总数 + +``` +declare loca cursor scroll for (select ori_loca,count(ori_loca) 荣誉总数 from tb_inf_student where ori_loca='北京' group by ori_loca) + +open loca +fetch first from loca --游标第一行 +declare @oloca varchar(8),@locount int +fetch first from loca into @oloca,@locount +print @oloca+','+cast( @locount as varchar(8)) + +close loca +``` + +--- 合理使用游标和事务,让5-1号前借书的学生将图书归还 + +``` +deallocate xs3 +declare xs3 cursor scroll for (select stu_num,return_time from tb_record where borrow_time<'2019-05-01') +open xs3 +begin transaction +declare @a char(8) +declare @b date +fetch first from xs3 into @a,@b +while @@FETCH_STATUS=0 + begin + if @b is null + begin + update tb_record set return_time = getdate() where stu_num = @a + end + fetch next from xs3 into @a,@b + end +--select * from tb_record +--rollback transaction +declare @err int=0 +set @err +=@@error +if @err>0 + begin + print '失败' + rollback transaction + end +else + begin + select stu_num,return_time from tb_record + end +``` \ No newline at end of file diff --git "a/15\345\220\264\346\230\216\346\235\260/\347\273\203\344\271\240/220921-\345\207\275\346\225\260\347\273\203\344\271\240.md" "b/15\345\220\264\346\230\216\346\235\260/\347\273\203\344\271\240/220921-\345\207\275\346\225\260\347\273\203\344\271\240.md" new file mode 100644 index 0000000..dae128d --- /dev/null +++ "b/15\345\220\264\346\230\216\346\235\260/\347\273\203\344\271\240/220921-\345\207\275\346\225\260\347\273\203\344\271\240.md" @@ -0,0 +1,96 @@ +--(1)编写一个函数求该银行的金额总和 + +``` +go +create function moneysum() +returns table +as + return select sum(CardMoney) 金额总和 from BankCard +go + +select * from moneysum() +``` + +--(2)传入账户编号,返回账户真实姓名 + +``` +go +create function zname(@id int) +returns varchar(20) +as +begin + declare @name varchar(20) + select @name=RealName from AccountInfo where AccountId=@id +return @name +end +go +select dbo.zname(2) +``` + +--(3)传递开始时间和结束时间,返回交易记录(存钱取钱),交易记录中包含 真实姓名,卡号,存钱金额,取钱金额,交易时间。 + + + +``` +go +create function cards(@begindate varchar(20),@enddate varchar(20)) +returns table +as + +return select RealName,b.CardNo,MoneyInBank,MoneyOutBank,ExchangeTime from CardExchange c +join BankCard b on c.CardNo=b.CardNo +join AccountInfo a on b.AccountId=a.AccountId +where ExchangeTime > '2022-09-01 00:00:00' and ExchangeTime < '2022-09-30 23:59:59' +go + +select * from cards('2022-09-01','2022-09-30') + +drop function cards +``` + +--方案一(逻辑复杂,函数内容除了返回结果的sql语句还有其他内容,例如定义变量等): + +--(4)查询银行卡信息,将银行卡状态1,2,3,4分别转换为汉字“正常,挂失,冻结,注销”,根据银行卡余额显示银行卡等级 30万以下为“普通用户”,30万及以上为"VIP用户",分别显示卡号,身份证,姓名,余额,用户等级,银行卡状态。 + +--方案一:直接在sql语句中使用case when + +--方案二:将等级和状态用函数实现 + +``` +go +create function messag() +returns table +as +return select CardNo ,AccountCode ,RealName ,CardMoney ,CardState, +case +when CardState='1' then '正常' +when CardState='2' then '挂失' +when CardState='3' then '冻结' +when CardState='4' then '注销' +end 银行卡状态, +case +when CardMoney >=300000 then 'VIP用户' +when CardMoney <300000 then '普通用户' +end 用户等级 +from BankCard b +join AccountInfo a on b.AccountId=a.AccountId +go + +select * from messag() +``` + + + +--(5)编写函数,根据出生日期求年龄,年龄求实岁,例如: +-- 生日为2000-5-5,当前为2018-5-4,年龄为17岁 +-- 生日为2000-5-5,当前为2018-5-6,年龄为18岁 + +``` +go +create function births() +returns table +as + return select DATEDIFF(yy,empBirth,GETDATE()) as 岁数 from emp +go +``` + -- Gitee