diff --git "a/15\345\220\264\346\230\216\346\235\260/\347\254\224\350\256\260/220907\345\255\220\346\237\245\350\257\242.md" "b/15\345\220\264\346\230\216\346\235\260/\347\254\224\350\256\260/220907\345\255\220\346\237\245\350\257\242.md" index 672eda2cd01e44a1910012c971534887e588c745..9b822e573ffa83dfceb19ff731af8e3f479ab8b8 100644 --- "a/15\345\220\264\346\230\216\346\235\260/\347\254\224\350\256\260/220907\345\255\220\346\237\245\350\257\242.md" +++ "b/15\345\220\264\346\230\216\346\235\260/\347\254\224\350\256\260/220907\345\255\220\346\237\245\350\257\242.md" @@ -101,17 +101,3 @@ if exists(子查询) ************ -### 4.使用compute和compute by进行汇总查询 - -**compute 和 compute by子句使您得以用同一select语句即查看明细行,有查看汇总行。可以计算子组的汇总值,也可以计算整个结果集的汇总值** - -当compute不带可选的by子句时,select语句有两个结果集: - ● 每个组的第一个结果集是包含选择列表信息的所有明细行 - ● 第二个结果集有一行,其中包含compute子句中所指定的聚合函数的合计 - -compute子句需要下列信息: - ● 可选by关键字。它基于每一列计算指定的行聚合 - ● 行聚合函数名称 SUM、AVG、MIN、MAX、或 COUNT - ● 要对其执行行聚函数的列 - -对结果先进行分组然后进行汇总计算时使用:compute by进行分组汇总查询 \ No newline at end of file diff --git "a/15\345\220\264\346\230\216\346\235\260/\347\254\224\350\256\260/220908\346\216\222\345\272\217\345\207\275\346\225\260.md" "b/15\345\220\264\346\230\216\346\235\260/\347\254\224\350\256\260/220908\346\216\222\345\272\217\345\207\275\346\225\260.md" index b3d99b4d8231bad7a70c19505b0bb6f82b91a0c6..35ea6eaae3217528b6bbf7f16fb348988f2cbb4d 100644 --- "a/15\345\220\264\346\230\216\346\235\260/\347\254\224\350\256\260/220908\346\216\222\345\272\217\345\207\275\346\225\260.md" +++ "b/15\345\220\264\346\230\216\346\235\260/\347\254\224\350\256\260/220908\346\216\222\345\272\217\345\207\275\346\225\260.md" @@ -29,58 +29,9 @@ `over(order by sroce rows between 5 preceding and 5 following)`:窗口范围为当前行前后各移动5行。 -******* - -## (三)聚合开窗函数 - -over[结束] 关键字==表示把聚合函数当成聚合开窗函数而不是聚合函数。SQL 标准允许将所有聚合函数用做聚合开窗函数。== - - 开窗函数的==over关键字后括号中的可以使用partition by 子句来定义行的分区来供进行聚合计算。与group by子句不同,partition by 子句创建的分区是独立于结果集的,创建的分区只是供进行聚合计算的,而且不同的开窗函数所创建的分区也不互相影响。== - -- 在同一个select语句中可以同时使用多个开窗函数,而且这些开窗函数并不会相互干扰。 -- 如果over关键字后的括号中的选项为空,则开窗函数会对结果集中的所有行进行聚合运算。 - -语法: partition[分区] - -```sql -select 聚合函数(列) over (partition by 字段) from b --()里为选项 -``` - -例:**显示每一个人员信息以及所在的班级人数** - -```sql -select *,count(Name) over(partition by ClassId) 人数 from T_Student -``` - -over(partition by ClassId)表示对ClassId进行分区,并且计算当前行所属的组的聚合行数结构,结构默认按照班级ClassId顺序显示,人数列按照count(UserName)显示 - -运行前: - -| stuno | Name | ClassId | -| ----- | ---- | ------- | -| 1001 | 张三 | 3 | -| 1002 | 李四 | 1 | -| 1003 | 王五 | 3 | -| 1004 | 老六 | 2 | -| 1005 | 老七 | 2 | -| 1006 | 老八 | 2 | - -运行后: - -| stuno | Name | ClassId | 人数 | -| ----- | ---- | ------- | ---- | -| 1002 | 李四 | 1 | 1 | -| 1004 | 老六 | 2 | 3 | -| 1005 | 老七 | 2 | 3 | -| 1006 | 老八 | 2 | 3 | -| 1003 | 王五 | 3 | 2 | -| 1001 | 张三 | 3 | 2 | - - - ****** -## ==(四)排序开窗函数== +## ==(三)排序开窗函数== **对于排序开窗函数来讲,它支持的开窗函数分别为:row_number(行号)、rank(排名)、dense_rank(密集排名)和 ntile(分组排名)。** diff --git "a/15\345\220\264\346\230\216\346\235\260/\347\254\224\350\256\260/220915\350\247\206\345\233\276.md" "b/15\345\220\264\346\230\216\346\235\260/\347\254\224\350\256\260/220915\350\247\206\345\233\276.md" index a69bde74f204d195e53e646eb696c0269e15eabc..2653eecd4d9a8508c383a82c94ceacb3390b1427 100644 --- "a/15\345\220\264\346\230\216\346\235\260/\347\254\224\350\256\260/220915\350\247\206\345\233\276.md" +++ "b/15\345\220\264\346\230\216\346\235\260/\347\254\224\350\256\260/220915\350\247\206\345\233\276.md" @@ -90,12 +90,6 @@ as go --是因为没有加上go,创建视图语句前也得加上go(代表上条语句结束),go与goz ``` -**下列情况必须指定视图中每列的名称** - -- 视图中的任何列都是从算术表达式、内置函数或常量派生而来的 -- 视图中有两列或多列具有相同名称 -- 希望为视图中的列指定一个与其原列不同的名称,也可以在视图中重命名列,无论重名与否,视图列都会继承其源列的数据类型 - ****** ### 1.常见的视图形式 diff --git "a/15\345\220\264\346\230\216\346\235\260/\347\254\224\350\256\260/220920\346\270\270\346\240\207.md" "b/15\345\220\264\346\230\216\346\235\260/\347\254\224\350\256\260/220920\346\270\270\346\240\207.md" index 99fe7dc06aae15e3e211afdf1d098e4b375923bb..52e1fb1d4333969ffb7b47ca407f4fcde61b51b4 100644 --- "a/15\345\220\264\346\230\216\346\235\260/\347\254\224\350\256\260/220920\346\270\270\346\240\207.md" +++ "b/15\345\220\264\346\230\216\346\235\260/\347\254\224\350\256\260/220920\346\270\270\346\240\207.md" @@ -77,28 +77,6 @@ for select 语句 --select查询语句 [for{read only|update[of 列名称]}][,...n]--可修改的列 ``` -参数说明: - -- [Local | Global] :默认为local -- Local:作用域为局部,只在定义它的批处理,存储过程或触发器中有效。 -- Global:作用域为全局,由连接执行的任何存储过程或批处理中,都可以引用该游标。 - -- Scroll:代表滚动游标,不加Scroll则是只进的,只能支持fetch next -- forward_only:指定游标智能从第一行滚到最后一行。Fetch Next是唯一支持的提取选项。如果在指定Forward_Only是不指定Static、KeySet、Dynamic关键字,默认为Dynamic游标。如果Forward_Only和Scroll没有指定,Static、KeySet、Dynamic游标默认为Scroll,Fast_Forward默认为Forward_Only - -- Static:静态游标 -- KeySet:键集游标 -- Dynamic:动态游标,不支持Absolute提取选项 -- Fast_Forward:指定启用了性能优化的Forward_Only、Read_Only游标。如果指定啦Scroll或For_Update,就不能指定他啦。 - - -- Read_Only:不能通过游标对数据进行删改。 -- Scroll_Locks:将行读入游标是,锁定这些行,确保删除或更新一定会成功。如果指定啦Fast_Forward或Static,就不能指定他啦。 -- Optimistic:指定如果行自读入游标以来已得到更新,则通过游标进行的定位更新或定位删除不成功。当将行读入游标时,sqlserver不锁定行,它改用timestamp列值的比较结果来确定行读入游标后是否发生了修改,如果表不行timestamp列,它改用校验和值进行确定。如果已修改改行,则尝试进行的定位更新或删除将失败。如果指定啦Fast_Forward,则不能指定他。 - -- Type_Warning:指定将游标从所请求的类型隐式转换为另一种类型时向客户端发送警告信息。 -- For Update[of column_name ,....] :定义游标中可==更新==的列。 - ********** **示例:** @@ -147,16 +125,6 @@ fetch [global]游标名称--或者@游标变量名称 [into @游标变量名称][,...n] ``` -**参数说明:** - -- First:结果集的第一行 -- Prior:当前位置的上一行 -- Next:当前位置的下一行 -- Last:最后一行 -- Absoute n:从游标的第一行开始数,第n行。 -- Relative n:从当前位置数,第n行。 -- Into @variable_name[,...] : 将提取到的数据存放到变量variable_name中。 - **示例:** **提取数据给变量以供它用(取出第3行学生姓名,查询该学生详细信息):** diff --git "a/15\345\220\264\346\230\216\346\235\260/\347\254\224\350\256\260/220926\345\255\230\345\202\250\350\277\207\347\250\213.md" "b/15\345\220\264\346\230\216\346\235\260/\347\254\224\350\256\260/220926\345\255\230\345\202\250\350\277\207\347\250\213.md" index 832b2f3e711e40e8014f2f7023d58a9b44a4ce19..e938d45c8f8dc4693b8cc75cf21f5ee32ce10794 100644 --- "a/15\345\220\264\346\230\216\346\235\260/\347\254\224\350\256\260/220926\345\255\230\345\202\250\350\277\207\347\250\213.md" +++ "b/15\345\220\264\346\230\216\346\235\260/\347\254\224\350\256\260/220926\345\255\230\345\202\250\350\277\207\347\250\213.md" @@ -186,67 +186,3 @@ print @sch + @name/*输出黄弘和理学院*/ ****** -## (五)raiserror用户自定义错误 - -**怎样处理存储过程中的错误?** - -使用PRINT语句显示错误信息 - -错误信息是临时的,只能显示给用户 - -**RAISERROR 显示用户定义的错误信息时** - -- 可指定严重级别 -- 设置系统变量@@ERROR -- 记录所发生的错误等 - -**raiserror语句的语法:**raiserror[错误处理语句] - -```sql -raiserror (msg_id|msg_str,severity,state WITH option [,...n]) -``` - -- msg_id: 在sysmessages系统表中指定用户定义错误信息 -- msg_str:用户定义的特定信息,最长255个字符 -- severity:定义严重性级别。用户可使用的级别为0-18级,一般定义16级,10级以上触发@@error -- state:表示错误的状态,1至127之间的值 -- option:指示是否将错误记录到服务器错误日志中。 - -示例: - -```sql -raiserror ('及格分数线必须在0-100之间',16,1) -``` - -****** - -(六)例题 - -```sql -create proc sp_student - @core int =60 --及格线默认60 - @sname varchar(20)--课程号 -as - declare @sno int --课程编号 - declare @date datetime --考试日期 - declare @avg float --平均分 -if @core<=0 or @core >100 - begin - raiserror('及格分数线在0-100之间',16,1) - return - end -else - begin - select @sno=根据课程名称求出课程编号 - select @date=根据课程编号求出最早的考试时间 - select @avg=根据课程编号和考试时间求出平均分 -if @avg>70 - print '优秀' -else - print'拉跨' - select 求出小于平均分的所有学生信息 - end -go -exec sp_stuent 70,'C#' -``` - diff --git "a/15\345\220\264\346\230\216\346\235\260/\347\254\224\350\256\260/220927-28\350\247\246\345\217\221\345\231\250.md" "b/15\345\220\264\346\230\216\346\235\260/\347\254\224\350\256\260/220927-28\350\247\246\345\217\221\345\231\250.md" new file mode 100644 index 0000000000000000000000000000000000000000..4b3fe74ef419a9be8b64b59623ae9bb766c5b20c --- /dev/null +++ "b/15\345\220\264\346\230\216\346\235\260/\347\254\224\350\256\260/220927-28\350\247\246\345\217\221\345\231\250.md" @@ -0,0 +1,231 @@ +# 触发器 + +**为什么需要触发器?** + +典型的例子是银行的取款机系统,**取款后余额会自动变更** + +这个时候就需要触发器: + +- 它是一种特殊的存储过程 +- 也具备事务的功能 +- 它能在多表之间执行特殊的业务规则 + +****** + +**什么是触发器?** + +- 触发器是在对表进行插入、更新或删除操作时**==自动执行的存储过程==** +- 触发器通常用于强制业务规则 +- 触发器是一种**==高级约束==**,可以定义比用CHECK约束更为复杂的约束 +- 可执行复杂的SQL语句( if/while/case) +- 可引用其它表中的列 +- 触发器定义在特定的表上,与表相关 +- 自动触发执行不 +- 能直接调用 +- 是一个事务(可回滚) + +**触发器的类型分为** + +- **delete 触发器** +- **insert 触发器** +- **update 触发器** + +******* + +## ==(一)inserted和deleted表== + +**触发器触发时** + +- 系统自动在内存中创建deleted表或inserted表 +- **只读,不允许修改;触发器执行完成后,自动删除** + +**inserted 表** + +- **临时保存了插入或更新后的记录行** +- 可以从inserted表中**检查插入的数据是否满足业务需求** +- 如果不满足,则向用户报告错误消息,并回滚插入操作 + +**deleted 表** + +- **临时保存了删除或更新前的记录行** +- 可以从deleted表中**检查被删除的数据是否满足业务需求** +- 如果不满足,则向用户报告错误消息,并回滚插入操作 + +| 对表的操作 | inserted逻辑表 | deleted逻辑表 | +| ---------------- | ---------------- | ---------------- | +| 增加记录(insert) | 存放增加的记录 | 无 | +| 删除记录(delete) | 无 | 存放被删除的记录 | +| 修改记录(update) | 存放更新后的记录 | 存放更新前的记录 | + +**我们更新的时候是先删除旧记录再添加新记录** + +**这两张表只==保存一条数据==,并且结构和触发的==表结构一样==** + +****** + +## (二)创建触发器 + +语法:trigger[触发器] + +```sql +create trigger triggrt_name --触发器名称 +on table__name --对应表名 +[with encryption]--代码是否加密 +for [delete,insert,update]--触发器类型 +as + T-SQL语句 +go +``` + +**创建好后可以去双击“数据库”->可编程栏->数据库触发器,查看** + +***** + +## (三)insert触发器 + +**insert的工作原理:** + +| **插入**记录行→ | 操作表(支取,存入) | +| --------------- | ------------------------------------------------------------ | +| | ↓ 触发insert触发器向inserted表中插入新行的副本 | +| | **insert表**: | +| | 触发器**检查inserted表中插入的新行数据,确定是否需要回滚或执行其他操作** | + +**示例:** + +**以银行取款系统为例**,当向交易信息表(transInfo)中插入一条交易信息时,我们应自动更新对应帐户的余额。 + +创建交易信息表(translnfo):cstfid,交易日期,交易类型(transtype),交易金额(transmoney) + +bank(保存用户信息):卡号,姓名,余额(balance) + +```sql +create trigger tr1_translnfo +on translnfo --交易时触发所以应该在交易信息表建触发器 +for insert +as + declare @cardid varchar(50)--交易id + declare @transtype varchar(10)--类型 + declare @transmoney float--金额 + select @cardid=cardid,@transtype=transtype,@transtype=transmoney from inserted --inserted表结构和translnfo表一样 + if(@transtype='支取')--如果交易类型为支取 + begin + update bank set balance=balance-@transtype where cardid=@cardid--bank表中余额减去交易金额 + end +else + begin + update bank set balance=balance+@transtype where cardid=@cardid--bank表中余额加上交易金额(这个时候交易类型为存入) + end +``` + +接下来可以对transinfo表进行操作来验证触发器是否有效 + +********** + +## (四)delete触发器 + +**delete触发器的工作原理:** + +| **删除**记录行→ | 操作表(支取,存入) | +| --------------- | ------------------------------------------------------------ | +| | ↓ 触发delete触发器向deleted表中插入被删除的副本 | +| | **deleted表**: | +| | 触发器**检查deleted表中插入的新行数据,确定是否需要回滚或执行其他操作** | + +**示例:** + +**当删除交易信息表时,要求自动备份被删除的数据到表backupTable中** + +创建交易信息表(translnfo):cstfid,交易日期,交易类型(transtype),交易金额(transmoney) + +bank(保存用户信息):卡号,姓名,余额(balance) + +```sql +create trigger tri_transinfo_delete +on transinfo +for delete +as +if not exists(select*from sysobjects where name='backupTable')--判断表是否存在 + begin + select * into backupTable from deleted--不存在就创建一张表并把deleted表里的内容填充到backupTable表 + end +else + begin + insert backupTable select*from deleted--否者把deleted表的内容填充到已经存在的backupTable表中 + end +go +``` + +transinfo表进行删除存在,验证触发器是否成功 + +******** + +## (五)update触发器 + +update触发器的工作原理 + +**delete触发器的工作原理:** + +| **删除**记录行→ | 操作表(支取,存入) | | +| --------------- | ------------------------------------------------------------ | ------------------------------- | +| | ↓ 向deleted表中插入被删除的副本 | ↓ inserted表中插入被添加的副本 | +| | **deleted表(更新前的数据)**: | **inserted表(更新后的数据)** | +| | 检查deleted和inserted表中的数据,确定是否需要回滚或执行其他操作 | | + +示例: + +**跟踪用户的交易,交易金额超过20000元,则取消交易,并给出错误提示。** + +创建交易信息表(translnfo):cstfid,交易日期,交易类型(transtype),交易金额(transmoney) + +bank(保存用户信息):卡号,姓名,余额(balance) + +因为bank表中更新数据所以触发器在bank表中创建 + +```sql +create trigger trig_update_bank +on bank +for update +as + declare @caridi varchar(20) + declare @cldbalnce float --更新前的金额参数 + declare @newbalnce float --更新后的金额参数 + select @cardid=cardid,@cldbalnce=balance from deleted--更新前的金额 + select @newbalnce=balance from inserted --更新后的金额 +if(abs(@newbalace-@cldbalnce)>20000) +--交易类型是存入和支取所以用上绝对值函数abs + begin + raiserror('交易金额不能超过20000',16,1) + rollback transaction--触发器是事务所以可以直接回滚 + end +else + print'操作成功' +go +``` + +******* + +### 1.列级UPDATE触发器 + +- UPDATE触发器除了跟踪数据的变化(修改)外,还可以检查是否修改了某列的数据 +- **使用UPDATE (列)函数检测是否修改了某列** + +**示例:** + +交易日期一般由系统自动产生,默认为当前日期。为了安全起见,一般禁止修改,以防舞弊。 + +```sql +create trigger trig_update +on translnfo +for update +as +if update(trandate)--检查是否修改了交易日期列trandate + begin + print'交易失败' + raisserror('安全警告:交易日期不能修改由系统自动生产',16,1) + rollback transaction --回滚事务,撤销交易 + end +go +``` + +# \ 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/220927-\350\247\246\345\217\221\345\231\250\347\273\203\344\271\240.md" "b/15\345\220\264\346\230\216\346\235\260/\347\273\203\344\271\240/220927-\350\247\246\345\217\221\345\231\250\347\273\203\344\271\240.md" new file mode 100644 index 0000000000000000000000000000000000000000..57e441008a5f29d1feee6e2f741dab3a800bd29e --- /dev/null +++ "b/15\345\220\264\346\230\216\346\235\260/\347\273\203\344\271\240/220927-\350\247\246\345\217\221\345\231\250\347\273\203\344\271\240.md" @@ -0,0 +1,95 @@ +select * from Department +select * from People +--(1)假设有部门表和员工表,在添加员工的时候,该员工的部门编号如果在部门表中找不到,则自动添加部门信息,部门名称为"新部门"。 + +``` +go +create trigger tr_departmentname +on People for insert +as +declare @id varchar(20) +select @id=(select DepartmentId from inserted) +if exists(select * from Department where DepartmentId=@id) + begin + print '部门已经存在' + end + else + begin + insert Department values(@id,'新部门') + end +go +insert People values('007','赵云','男',10000) + +drop trigger tr_departmentname +go +``` + +--(2)触发器实现,删除一个部门的时候将部门下所有员工全部删除。 + +``` +create trigger tr_deletename +on Department for delete +as +delete People where DepartmentId=(select DepartmentId from deleted) +go +delete Department where DepartmentName='市场部' +``` + +--(3)创建一个触发器,删除一个部门的时候 判断该部门下是否有员工,有则不删除,没有则删除。 + +``` +--方法1 +go +create trigger tr_deletenames +on department after delete +as +declare @id varchar(20) +select @id=(select DepartmentId from deleted) +if exists(select * from People where DepartmentId=@id) + begin + print '不删除' + rollback TransAction + end +go + +drop trigger tr_deletenames + + + +--方法2 +go +create trigger tr_deletenss +on department instead of delete +as +if exists(select * from People where DepartmentId=(select DepartmentId from deleted)) + print '有员工,不删除' +else + delete Department where DepartmentId=(select DepartmentId from deleted) +go + +delete Department where DepartmentId='004' +``` + + +--(4)修改一个部门编号之后,将该部门下所有员工的部门编号同步进行修改 先删除,后插入 + +``` +go +create trigger tr_updateid +on Department after update +as +declare @id varchar(20) +declare @ids varchar(20) +select @ids=DepartmentId from deleted --删除之后 +select @id=Departmentid from inserted --更新 +update People set DepartmentId=@id where DepartmentId=@ids + +go + + +update Department set DepartmentId='005'where DepartmentName='总经办' + +drop trigger tr_updateid +``` + +