第一次练习:【SQL Server】一次数据库练习——题目+思路+答案
第二次练习:【SQL Server】又次数据库练习——题目+思路+答案
use NetMusicShop
go
---- PPT7 —— 触发器 ----
-- 为Users表创建一个触发器,不允许插入名为admin或"管理员"的用户,也不允许将用户名修改为admin或"管理员"
-- Requirements :
-- 1. 分别用 after(for) 和 instead of 两种触发器来实现,并比较它们的不同
-- 2. 给出测试代码验证该触发器
-- after(for)触发器
-- 基本思路:
-- 1. 先通过deleted表中是否有记录,来判断触发触发器的是insert还是update:
-- 如果deleted表有记录,则进行了更新(update)操作;如果deleted表为空,则进行了插入(insert)操作
-- 2. 核心思路是【对Users表进行相反的操作】:
-- 如果是更新,就更新回去;如果是插入,就对Users表进行一次删除
create trigger tri_lolisuki on Users
after insert, update
as
begin
declare @deleled_name nvarchar(20);
select @deleled_name = (select userName from deleted);
if(@deleled_name is not null) -- 如果deleted表非空,则一定是进行了更新操作
begin
update Users
set UserName = @deleled_name where UserName = 'admin' or UserName = '管理员';
end
else -- 否则进行的是插入操作
begin
delete from Users
where UserName = 'admin' or UserName = '管理员';
end
end
-- instead of 触发器
-- 基本思路:
-- 1. 同样根据deleted表是否为空,对insert和update进行区分
-- 2. 核心思路是【根据inserted表预先进行判断,是否需要手动进行insert或update的操作】
-- 3. 因为instead of 触发器拦截了所有的insert和update操作(即使与UserName无关!)
-- 这些操作都需要我们手动完成,逐条把inserted表的记录移到Users表中,极其麻烦
-- 所以在设计表时,一个表不要有太多的属性列
create trigger tri_lolisaikou on Users
instead of insert, update
as
begin
declare @deleted_name varchar(20);
select @deleted_name = (select UserName from deleted);
declare @UserName varchar(20); select @UserName = (select UserName from inserted);
declare @UserPassword varchar(6); select @UserPassword = (select UserPassword from inserted);
declare @UserSex char(2); select @UserSex = (select UserSex from inserted);
declare @UserRealName varchar(20); select @UserRealName = (select UserRealName from inserted);
declare @UserAgeRange char(8); select @UserAgeRange = (select UserAgeRange from inserted);
declare @UserAddress varchar(256); select @UserAddress = (select UserAddress from inserted);
declare @UserPostCode CHAR(6); select @UserPostCode = (select UserPostCode from inserted);
declare @UserPhone varchar(32); select @UserPhone = (select UserPhone from inserted);
declare @UserEmail varchar(50); select @UserEmail = (select UserEmail from inserted);
declare @UserRegisterTime smalldatetime; select @UserRegisterTime = (select UserRegisterTime from inserted);
declare @UserAdvancePayment numeric(8, 2); select @UserAdvancePayment = (select UserAdvancePayment from inserted);
if(@inserted_name in ('admin', '管理员')) -- 如果更新或插入的UserName不合规,则不再进行手动update或insert操作
select '无法更新和删除';
else
begin
if(@deleted_name is not null) -- 分情况,进行手动update和insert
begin
update Users
set UserName = @UserName, UserPassword = @UserPassword, UserSex = @UserSex, UserRealName = @UserRealName,
UserAgeRange = @UserAgeRange, UserAddress = @UserAddress, UserPostCode = @UserPostCode,UserPhone = @UserPhone,
UserEmail = @UserEmail, UserRegisterTime = @UserRegisterTime, UserAdvancePayment = @UserAdvancePayment
where UserName = @deleted_name;
end
else
begin
insert Users(UserName,UserPassword,UserSex,UserRealName,UserAgeRange,
UserAddress,UserPostCode,UserPhone,UserEmail, UserRegisterTime, UserAdvancePayment)
values(@UserName, @UserPassword, @UserSex, @UserRealName, @UserAgeRange,
@UserAddress, @UserPostCode, @UserPhone, @UserEmail, @UserRegisterTime, @UserAdvancePayment)
end
end
end
-- test
drop trigger tri_lolisuki
drop trigger tri_lolisaikou
select * from Users -- 查看效果
insert into Users(UserName,UserPassword,UserSex,UserRealName,UserAgeRange,UserAddress,UserPostCode,UserPhone,UserEmail)
values('管理员','123456','男','loli','12~13岁','山东省临沂市','100000','13331022500','[email protected]')
-- 尝试插入UserName为'管理员'的一条记录,插入失败(符合预期)
insert into Users(UserName,UserPassword,UserSex,UserRealName,UserAgeRange,UserAddress,UserPostCode,UserPhone,UserEmail)
values('lolikon','123456','男','loli','12~13岁','山东省临沂市','100000','13331022500','[email protected]')
-- 尝试插入UserName为'lolikon'的一条记录,插入成功(符合预期)
update Users
set UserName = '管理员' where UserName = 'wz'
-- 尝试修改某条记录的UserName为'管理员',更新失败(符合预期)
update Users
set UserName = 'lolikon' where UserName = 'wz'
-- 尝试修改某条记录的UserName为'lolikon',更新成功(符合预期)
-- after(for)触发器 和 instead of 触发器 的异同:
-- 1. 不管是"之后"还是"之前"哪一种触发器,deleted表和inserted表都已经有记录了
-- 2. 但它们的使用场景差别很大:
-- after触发器已经完成了所有的操作,它发挥作用的关键通常在于deleted表和inseted表的记录
-- instead of 触发器会拦截操作,只是一个引火索,真正执行的代码是触发器中的代码(一次它内部的语句通常分支众多且代码量大)
---- PPT8 —— T-SQL ----
-- 1.查询订单表Orders,将所有的订单状态列OrderIsConfirm, OrderIsPayment, OrderIsConsignment, OrderIsPigeonhole
-- 的 0 / 1 值显示为中文的"未确认""已确认", "未付款""已付款", "未发货""已发货", "未归档""已归档"
select OrderID,
OrderIsConfirm = case OrderIsConfirm when 0 then '未确认' when 0 then '已确认' end,
OrderIsPayment = case OrderIsPayment when 0 then '未付款' when 1 then '已付款' end,
OrderIsConsignment = case OrderIsConsignment when 0 then '未发货' when 1 then '已发货' end,
OrderIsPigeonhole = case OrderIsPigeonhole when 0 then '未归档' when 1 then '已归档' end
from Orders
-- 分析:普通的case语句(另外注意case语句有两种形式,对应离散和连续值的微妙差别)
-- 2. 计算0~1所有自然数之和
create function getSum() returns int // 封装了一个函数
as
begin
declare @n int;
declare @sum int;
set @n = 0;
set @sum = 0;
while(@n <= 100)
begin
set @sum += @n;
set @n += 1;
end
return @sum;
end
declare @sum int
set @sum = dbo.getSum()
select @sum -- 输出5050