数据库系统原理与实践——第六次作业
修复了一些错误
This commit is contained in:
		
							parent
							
								
									abdba7cb36
								
							
						
					
					
						commit
						097829e0cc
					
				@ -43,8 +43,6 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
% 将minted的外框修复为framed,修复换行的问题
 | 
					% 将minted的外框修复为framed,修复换行的问题
 | 
				
			||||||
\setlength{\FrameRule}{0pt}
 | 
					\setlength{\FrameRule}{0pt}
 | 
				
			||||||
\BeforeBeginEnvironment{minted}{\begin{framed}}
 | 
					 | 
				
			||||||
\AfterEndEnvironment{minted}{\end{framed}}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
\ExplSyntaxOn
 | 
					\ExplSyntaxOn
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,9 @@
 | 
				
			|||||||
\documentclass[全部作业]{subfiles}
 | 
					\documentclass[全部作业]{subfiles}
 | 
				
			||||||
\input{mysubpreamble}
 | 
					\input{mysubpreamble}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					\BeforeBeginEnvironment{minted}{\begin{framed}}
 | 
				
			||||||
 | 
					\AfterEndEnvironment{minted}{\end{framed}}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
\begin{document}
 | 
					\begin{document}
 | 
				
			||||||
\setcounter{chapter}{2}
 | 
					\setcounter{chapter}{2}
 | 
				
			||||||
\chapter{第三次作业}
 | 
					\chapter{第三次作业}
 | 
				
			||||||
 | 
				
			|||||||
@ -3,7 +3,7 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
\begin{document}
 | 
					\begin{document}
 | 
				
			||||||
\setcounter{chapter}{4}
 | 
					\setcounter{chapter}{4}
 | 
				
			||||||
\chapter{第四次作业}
 | 
					\chapter{第五次作业}
 | 
				
			||||||
\begin{enumerate}
 | 
					\begin{enumerate}
 | 
				
			||||||
    \questionandanswer[]{
 | 
					    \questionandanswer[]{
 | 
				
			||||||
        一、数据库介绍
 | 
					        一、数据库介绍
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										527
									
								
								数据库系统原理与实践/平时作业/第六次作业.tex
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										527
									
								
								数据库系统原理与实践/平时作业/第六次作业.tex
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,527 @@
 | 
				
			|||||||
 | 
					\documentclass[全部作业]{subfiles}
 | 
				
			||||||
 | 
					\input{mysubpreamble}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					% 不知道为什么这里又变成不用framed才能不出现换页问题了
 | 
				
			||||||
 | 
					% \BeforeBeginEnvironment{minted}{}
 | 
				
			||||||
 | 
					% \AfterEndEnvironment{minted}{}
 | 
				
			||||||
 | 
					% 这样好像不能替换掉原来的,那就只能把framed移动到需要的部分里了
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					\begin{document}
 | 
				
			||||||
 | 
					\setcounter{chapter}{5}
 | 
				
			||||||
 | 
					\chapter{第六次作业}
 | 
				
			||||||
 | 
					\begin{enumerate}
 | 
				
			||||||
 | 
					    \item \choice[1]{关于游标,选项中说法错误的是()
 | 
				
			||||||
 | 
					    A
 | 
				
			||||||
 | 
					    游标可以定在查询结果集的特定行,也可以从结果集的当前行检索一行或多行
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    B
 | 
				
			||||||
 | 
					    通常我们并不使用游标,但是需要逐条处理数据的时候,游标显得十分重要
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    C
 | 
				
			||||||
 | 
					    游标使用时必须在完成后关闭,以释放资源
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    D
 | 
				
			||||||
 | 
					    游标的 SELECT 语句中可以使用 INTO 子句来创建新表
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    }{4}
 | 
				
			||||||
 | 
					    \item \choice[1]{下列关于触发器的描述正确的是()
 | 
				
			||||||
 | 
					    A
 | 
				
			||||||
 | 
					    MySql的触发器只支持行级出发,不支持语句级触发
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    B
 | 
				
			||||||
 | 
					    触发器可以调用将数据返回客户端的存储程序
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    C
 | 
				
			||||||
 | 
					    在触发器中可以使用显式或者隐式方式开始或结束事务的语句
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    D
 | 
				
			||||||
 | 
					    在MySql中,不可使用new和old引用触发器中发生的记录内容
 | 
				
			||||||
 | 
					    }{1}
 | 
				
			||||||
 | 
					    \item \choice[1]{关于before和after触发器的说法中,哪一项是正确的?()
 | 
				
			||||||
 | 
					    A
 | 
				
			||||||
 | 
					    在 BEFORE 触发器中,可以对 INSERT 和 UPDATE 的 NEW 值进行修改;而在 AFTER 触发器中,无法修改 NEW 值
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    B
 | 
				
			||||||
 | 
					    在 AFTER 触发器中,可以修改 NEW 值,但在 BEFORE 触发器中不能修改
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    C
 | 
				
			||||||
 | 
					    BEFORE 触发器不能用于 UPDATE 操作
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    D
 | 
				
			||||||
 | 
					    AFTER 触发器可以对 INSERT 和 UPDATE 的 NEW 值进行修改
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    }{1}
 | 
				
			||||||
 | 
					    \item \choice[1]{关于 MySQL 触发器中 SELECT 语句的使用,以下哪种说法是正确的?()
 | 
				
			||||||
 | 
					    A
 | 
				
			||||||
 | 
					    触发器中可以包含 SELECT 语句,并且可以返回结果集
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    B
 | 
				
			||||||
 | 
					    触发器中可以包含 SELECT 语句,但不能返回结果集
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    C
 | 
				
			||||||
 | 
					    触发器中必须包含 SELECT 语句,以便执行其他操作
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    D
 | 
				
			||||||
 | 
					    触发器中可以使用 SELECT 语句来更新表的记录
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    }{2}
 | 
				
			||||||
 | 
					    \item \choice[1]{关于存储过程的说法中,哪一项是正确的?()
 | 
				
			||||||
 | 
					    A
 | 
				
			||||||
 | 
					    存储过程可以通过 SELECT 语句直接返回结果集给调用者
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    B
 | 
				
			||||||
 | 
					    存储过程只能接受一个输入参数,并且不能返回任何值
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    C
 | 
				
			||||||
 | 
					    存储过程可以使用 BEGIN ... END 块来定义多个 SQL 语句的执行逻辑
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    D
 | 
				
			||||||
 | 
					    存储过程的定义必须包含 CREATE FUNCTION 关键字
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    }{3}
 | 
				
			||||||
 | 
					    \questionandanswer[]{
 | 
				
			||||||
 | 
					        创建一个名为 check_student_age_trigger 的触发器,该触发器用于在 students 表中插入新记录之前进行年龄检查。要求如下:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					触发器在执行 INSERT 操作之前触发。
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					如果新插入的学生年龄(age 列)小于 18 岁,触发器应该将 age 设置为 18。
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					如果新插入的学生年龄大于 120 岁,触发器应该将 age 设置为 120。
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					触发器应该记录所有插入操作的原始年龄值到一个名为 age_log 的表中,表结构如下:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					log_id: INT, 主键,自增
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					student_id: INT, 学生学号
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					original_age: INT,原始年龄值
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					log_time: DATETIME,记录插入的时间
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					要求:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					(1)编写 SQL 语句创建 age_log 表。
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					(2)编写 SQL 语句创建 check_student_age_trigger 触发器。
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					提示:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					使用 NEW 关键字访问将要插入的记录中的字段。
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					使用 INSERT INTO 语句将原始年龄记录到 age_log 表中。
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					示例:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					如果插入一条记录:INSERT INTO students (name, age) VALUES ('Alice', 16);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					触发器将插入 age 为 18,并在 age_log 表中记录 original_age 为 16。
 | 
				
			||||||
 | 
					    }{}
 | 
				
			||||||
 | 
					    {\kaishu
 | 
				
			||||||
 | 
					        \begin{minted}{SQL}
 | 
				
			||||||
 | 
					create table age_log
 | 
				
			||||||
 | 
					(
 | 
				
			||||||
 | 
					    log_id       int primary key auto_increment,
 | 
				
			||||||
 | 
					    student_id   int comment '学生学号',
 | 
				
			||||||
 | 
					    original_age int comment '原始年龄值',
 | 
				
			||||||
 | 
					    log_time     datetime comment '记录插入的时间'
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					create trigger check_student_age_trigger
 | 
				
			||||||
 | 
					    before insert
 | 
				
			||||||
 | 
					    on students
 | 
				
			||||||
 | 
					    for each row
 | 
				
			||||||
 | 
					begin
 | 
				
			||||||
 | 
					    insert into age_log(student_id, original_age, log_time) value (new.id, new.age, now());
 | 
				
			||||||
 | 
					    case
 | 
				
			||||||
 | 
					        when (new.age < 18) then set new.age = 18;
 | 
				
			||||||
 | 
					        when (new.age > 120) then set new.age = 120;
 | 
				
			||||||
 | 
					        end case;
 | 
				
			||||||
 | 
					end;
 | 
				
			||||||
 | 
					        \end{minted}
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    \begin{verification}
 | 
				
			||||||
 | 
					        {\small
 | 
				
			||||||
 | 
					        \begin{minted}{SQL}
 | 
				
			||||||
 | 
					drop table if exists students;
 | 
				
			||||||
 | 
					drop table if exists age_log;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					create table students
 | 
				
			||||||
 | 
					(
 | 
				
			||||||
 | 
					    id   int primary key,
 | 
				
			||||||
 | 
					    name varchar(100) comment '姓名',
 | 
				
			||||||
 | 
					    age  int comment '年龄'
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					create table age_log
 | 
				
			||||||
 | 
					(
 | 
				
			||||||
 | 
					    log_id       int primary key auto_increment,
 | 
				
			||||||
 | 
					    student_id   int comment '学生学号',
 | 
				
			||||||
 | 
					    original_age int comment '原始年龄值',
 | 
				
			||||||
 | 
					    log_time     datetime comment '记录插入的时间'
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					create trigger check_student_age_trigger
 | 
				
			||||||
 | 
					    before insert
 | 
				
			||||||
 | 
					    on students
 | 
				
			||||||
 | 
					    for each row
 | 
				
			||||||
 | 
					begin
 | 
				
			||||||
 | 
					    insert into age_log(student_id, original_age, log_time) value (new.id, new.age, now());
 | 
				
			||||||
 | 
					    case
 | 
				
			||||||
 | 
					        when (new.age < 18) then set new.age = 18;
 | 
				
			||||||
 | 
					        when (new.age > 120) then set new.age = 120;
 | 
				
			||||||
 | 
					        end case;
 | 
				
			||||||
 | 
					end;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					insert into students(id, name, age)
 | 
				
			||||||
 | 
					values (10001, 'Alice', 16),
 | 
				
			||||||
 | 
					       (10002, 'Bob', 150);
 | 
				
			||||||
 | 
					        \end{minted}
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        students:
 | 
				
			||||||
 | 
					        \begin{csv}
 | 
				
			||||||
 | 
					,id,name,age
 | 
				
			||||||
 | 
					1,10001,Alice,18
 | 
				
			||||||
 | 
					2,10002,Bob,120
 | 
				
			||||||
 | 
					        \end{csv}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        age_log:
 | 
				
			||||||
 | 
					        \begin{csv}
 | 
				
			||||||
 | 
					,log_id,student_id,original_age,log_time
 | 
				
			||||||
 | 
					1,1,10001,16,2024-11-01 15:39:52
 | 
				
			||||||
 | 
					2,2,10002,150,2024-11-01 15:39:52
 | 
				
			||||||
 | 
					        \end{csv}
 | 
				
			||||||
 | 
					    \end{verification}
 | 
				
			||||||
 | 
					    \questionandanswer[]{
 | 
				
			||||||
 | 
					        假设有以下两个表:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        \noindent\includegraphics[width=1\linewidth]{imgs/2024-11-01-16-47-16.png}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        创建一个名为 withdraw_funds 的存储过程,用于从银行账户中提款。要求如下:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					存储过程接受两个参数:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					account_id: INT, 要提款的账户的 ID
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					amount: DECIMAL(10, 2), 要提款的金额
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					在提款前检查该账户的余额是否足够支付提款金额。
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					如果余额不足,存储过程应返回一个错误消息。
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					如果提款成功,更新账户余额,并在 transactions 表中记录提款信息(转出账户为提款账户,转入账户为 NULL,金额为提款金额)。
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    }{}
 | 
				
			||||||
 | 
					    {\kaishu
 | 
				
			||||||
 | 
					        \begin{minted}{SQL}
 | 
				
			||||||
 | 
					create procedure withdraw_funds(in _account_id int, in amount decimal(10, 2))
 | 
				
			||||||
 | 
					begin
 | 
				
			||||||
 | 
					    start transaction;
 | 
				
			||||||
 | 
					    -- 如果账户不存在呢?好像没有交代应该怎么处理
 | 
				
			||||||
 | 
					    if (select accounts.balance from accounts where accounts.account_id = _account_id) < amount then
 | 
				
			||||||
 | 
					        rollback ;
 | 
				
			||||||
 | 
					        signal sqlstate '45000' set message_text = '余额不足';
 | 
				
			||||||
 | 
					    end if;
 | 
				
			||||||
 | 
					    update accounts set balance = balance - amount where accounts.account_id = _account_id;
 | 
				
			||||||
 | 
					    insert into transactions(from_account_id, to_account_id, amount) value (_account_id, null, amount);
 | 
				
			||||||
 | 
					    commit;
 | 
				
			||||||
 | 
					end;
 | 
				
			||||||
 | 
					        \end{minted}
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    \begin{verification}
 | 
				
			||||||
 | 
					        {\small
 | 
				
			||||||
 | 
					        \begin{minted}{SQL}
 | 
				
			||||||
 | 
					drop table if exists accounts;
 | 
				
			||||||
 | 
					drop table if exists transactions;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					create table accounts
 | 
				
			||||||
 | 
					(
 | 
				
			||||||
 | 
					    -- 自增好像是从1开始的
 | 
				
			||||||
 | 
					    account_id     int primary key auto_increment comment '账户唯一标识符',
 | 
				
			||||||
 | 
					    account_holder varchar(100) comment '账户持有者的姓名',
 | 
				
			||||||
 | 
					    balance        decimal(10, 2) comment '账户余额'
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					create table transactions
 | 
				
			||||||
 | 
					(
 | 
				
			||||||
 | 
					    transaction_id   int primary key auto_increment comment '交易的唯一标识符',
 | 
				
			||||||
 | 
					    from_account_id  int comment '转出账户的ID',
 | 
				
			||||||
 | 
					    to_account_id    int comment '转入账户的ID',
 | 
				
			||||||
 | 
					    amount           decimal(10, 2) comment '转账金额',
 | 
				
			||||||
 | 
					    transaction_time datetime default current_timestamp comment '转账时间'
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					insert into accounts(account_holder, balance)
 | 
				
			||||||
 | 
					values ('a', 10),
 | 
				
			||||||
 | 
					       ('b', 100);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					drop procedure if exists withdraw_funds;
 | 
				
			||||||
 | 
					create procedure withdraw_funds(in _account_id int, in amount decimal(10, 2))
 | 
				
			||||||
 | 
					begin
 | 
				
			||||||
 | 
					    start transaction;
 | 
				
			||||||
 | 
					    -- 如果账户不存在呢?好像没有交代应该怎么处理
 | 
				
			||||||
 | 
					    if (select accounts.balance from accounts where accounts.account_id = _account_id) < amount then
 | 
				
			||||||
 | 
					        rollback ;
 | 
				
			||||||
 | 
					        signal sqlstate '45000' set message_text = '余额不足';
 | 
				
			||||||
 | 
					    end if;
 | 
				
			||||||
 | 
					    update accounts set balance = balance - amount where accounts.account_id = _account_id;
 | 
				
			||||||
 | 
					    insert into transactions(from_account_id, to_account_id, amount) value (_account_id, null, amount);
 | 
				
			||||||
 | 
					    commit;
 | 
				
			||||||
 | 
					end;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					call withdraw_funds(2, 10);
 | 
				
			||||||
 | 
					call withdraw_funds(1, 10);
 | 
				
			||||||
 | 
					call withdraw_funds(1, 10);
 | 
				
			||||||
 | 
					        \end{minted}
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        \begin{minted}{text}
 | 
				
			||||||
 | 
					[2024-11-01 16:35:33] [45000][1644] 余额不足
 | 
				
			||||||
 | 
					        \end{minted}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        accounts:
 | 
				
			||||||
 | 
					        \begin{csv}
 | 
				
			||||||
 | 
					,account_id,account_holder,balance
 | 
				
			||||||
 | 
					1,1,a,0.00
 | 
				
			||||||
 | 
					2,2,b,90.00
 | 
				
			||||||
 | 
					        \end{csv}
 | 
				
			||||||
 | 
					        \vspace{1em}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        transactions:\vspace{1em}\\
 | 
				
			||||||
 | 
					        \small\begin{csv}
 | 
				
			||||||
 | 
					,transaction_id,from_account_id,to_account_id,amount,transaction_time
 | 
				
			||||||
 | 
					1,1,2,,10.00,2024-11-01 16:35:33
 | 
				
			||||||
 | 
					2,2,1,,10.00,2024-11-01 16:35:34
 | 
				
			||||||
 | 
					        \end{csv}
 | 
				
			||||||
 | 
					    \end{verification}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    \questionandanswer[]{
 | 
				
			||||||
 | 
					        请根据下图所示的银行数据库,编写一个触发器来执行下列操作:在删除一个账户时,检查该账户的拥有者是否还有其他账户,如果没有,则将其从depositor关系中删除。
 | 
				
			||||||
 | 
					        \includegraphics[width=1\linewidth]{imgs/2024-11-01-21-57-55.png}
 | 
				
			||||||
 | 
					    }{}
 | 
				
			||||||
 | 
					    {\kaishu
 | 
				
			||||||
 | 
					        这里为什么要检测是否有其他账户,删除一个账户时不管这个人有没有其他账户都需要从depositor里删除account_number对应的行吧,那删除最后一个账户时depositor里自然也删完了。
 | 
				
			||||||
 | 
					        \begin{minted}{SQL}
 | 
				
			||||||
 | 
					create trigger delete_account
 | 
				
			||||||
 | 
					    after delete
 | 
				
			||||||
 | 
					    on account
 | 
				
			||||||
 | 
					    for each row
 | 
				
			||||||
 | 
					begin
 | 
				
			||||||
 | 
					    delete from depositor where account_number = old.account_number;
 | 
				
			||||||
 | 
					end;
 | 
				
			||||||
 | 
					        \end{minted}
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    \begin{verification}
 | 
				
			||||||
 | 
					        \begin{minted}{SQL}
 | 
				
			||||||
 | 
					drop table if exists account;
 | 
				
			||||||
 | 
					drop table if exists depositor;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					create table account
 | 
				
			||||||
 | 
					(
 | 
				
			||||||
 | 
					    account_number int primary key,
 | 
				
			||||||
 | 
					    branch_name    varchar(100),
 | 
				
			||||||
 | 
					    balance        int
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					create table depositor
 | 
				
			||||||
 | 
					(
 | 
				
			||||||
 | 
					    customer_name  varchar(100),
 | 
				
			||||||
 | 
					    account_number int references account.account_number
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					insert into account
 | 
				
			||||||
 | 
					values (1, 'a', 100),
 | 
				
			||||||
 | 
					       (2, 'b', 200);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					insert into depositor
 | 
				
			||||||
 | 
					values ('c', 1),
 | 
				
			||||||
 | 
					       ('c', 2);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					create trigger delete_account
 | 
				
			||||||
 | 
					    after delete
 | 
				
			||||||
 | 
					    on account
 | 
				
			||||||
 | 
					    for each row
 | 
				
			||||||
 | 
					begin
 | 
				
			||||||
 | 
					    delete from depositor where account_number = old.account_number;
 | 
				
			||||||
 | 
					end;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					delete from account where account_number = 1;
 | 
				
			||||||
 | 
					select * from depositor;
 | 
				
			||||||
 | 
					        \end{minted}
 | 
				
			||||||
 | 
					        \begin{csv}
 | 
				
			||||||
 | 
					,customer_name,account_number
 | 
				
			||||||
 | 
					1,c,2
 | 
				
			||||||
 | 
					        \end{csv}
 | 
				
			||||||
 | 
					        \begin{minted}{SQL}
 | 
				
			||||||
 | 
					delete from account where account_number = 2;
 | 
				
			||||||
 | 
					select * from depositor;
 | 
				
			||||||
 | 
					        \end{minted}
 | 
				
			||||||
 | 
					        \begin{csv}
 | 
				
			||||||
 | 
					,customer_name,account_number
 | 
				
			||||||
 | 
					,,
 | 
				
			||||||
 | 
					        \end{csv}
 | 
				
			||||||
 | 
					    \end{verification}
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    \questionandanswer[]{
 | 
				
			||||||
 | 
					        假设有一个名为 employees 的员工表和一个名为 departments 的部门表,结构如下:
 | 
				
			||||||
 | 
					        \includegraphics[width=1\linewidth]{imgs/2024-11-02-11-15-08.png}
 | 
				
			||||||
 | 
					        (1)存储过程:名为 increase_salary,用于根据部门名称增加员工工资。要求:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 接受两个参数:dept_name(部门名称)和 percentage(增加的百分比)。
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 如果部门不存在,返回错误消息。
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 如果部门存在,更新该部门所有员工的工资,并返回更新的员工数量。
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    }{}
 | 
				
			||||||
 | 
					    {\kaishu
 | 
				
			||||||
 | 
					        \begin{minted}{SQL}
 | 
				
			||||||
 | 
					create procedure increase_salary(in dept_name varchar(100), in percentage int)
 | 
				
			||||||
 | 
					begin
 | 
				
			||||||
 | 
					    if (select count(*) from departments where dept_name = departments.department_name) <= 0 then
 | 
				
			||||||
 | 
					        signal sqlstate '45000' set message_text = '部门不存在';
 | 
				
			||||||
 | 
					    end if;
 | 
				
			||||||
 | 
					    update employees join departments using (department_id)
 | 
				
			||||||
 | 
					    set salary = salary * (1 + percentage / 100)
 | 
				
			||||||
 | 
					    where department_name = dept_name;
 | 
				
			||||||
 | 
					    -- 存储过程怎么返回更新的员工数量
 | 
				
			||||||
 | 
					    -- 30 ms 中有 2 行受到影响 返回的影响行数应该就能反映更新的员工数量了
 | 
				
			||||||
 | 
					end;
 | 
				
			||||||
 | 
					        \end{minted}
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    \questionandanswer[]{
 | 
				
			||||||
 | 
					(2)函数:名为 get_average_salary,用于获取指定部门的平均工资。要求:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					接受一个参数:dept_id(部门 ID)。
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					返回该部门员工的平均工资,如果没有员工,则返回 0。
 | 
				
			||||||
 | 
					    }{}
 | 
				
			||||||
 | 
					    {\kaishu
 | 
				
			||||||
 | 
					        \begin{minted}{SQL}
 | 
				
			||||||
 | 
					create function get_average_salary(dept_id int) returns decimal(10, 2)
 | 
				
			||||||
 | 
					begin
 | 
				
			||||||
 | 
					    declare result decimal(10, 2);
 | 
				
			||||||
 | 
					    if (select count(*) from employees where department_id = dept_id) <= 0 then
 | 
				
			||||||
 | 
					        set result = 0;
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
					        select avg(employees.salary) into result from employees where department_id = dept_id;
 | 
				
			||||||
 | 
					    end if;
 | 
				
			||||||
 | 
					    return result;
 | 
				
			||||||
 | 
					end;
 | 
				
			||||||
 | 
					        \end{minted}
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    \begin{verification}
 | 
				
			||||||
 | 
					        \begin{minted}{SQL}
 | 
				
			||||||
 | 
					drop table if exists employees;
 | 
				
			||||||
 | 
					drop table if exists departments;
 | 
				
			||||||
 | 
					drop procedure if exists increase_salary;
 | 
				
			||||||
 | 
					drop function if exists get_average_salary;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					create table employees
 | 
				
			||||||
 | 
					(
 | 
				
			||||||
 | 
					    employee_id   int primary key auto_increment comment '员工唯一标识符',
 | 
				
			||||||
 | 
					    employee_name varchar(100) comment '员工姓名',
 | 
				
			||||||
 | 
					    department_id int comment '部门ID',
 | 
				
			||||||
 | 
					    salary        decimal(10, 2) comment '员工工资'
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
					create table departments
 | 
				
			||||||
 | 
					(
 | 
				
			||||||
 | 
					    department_id   int primary key auto_increment comment '部门唯一标识符',
 | 
				
			||||||
 | 
					    department_name varchar(100) comment '部门名称'
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
					        \end{minted}
 | 
				
			||||||
 | 
					        \quad
 | 
				
			||||||
 | 
					        % 大概知道了,只要在前一页结束前的位置加一个minted分段,并且在这个分段前面或后面存在一个字符,即使是空白的\quad 也可以,就不会出现分页异常的问题了
 | 
				
			||||||
 | 
					        \begin{minted}{SQL}
 | 
				
			||||||
 | 
					create procedure increase_salary(in dept_name varchar(100), in percentage int)
 | 
				
			||||||
 | 
					begin
 | 
				
			||||||
 | 
					    if (select count(*) from departments where dept_name = departments.department_name) <= 0 then
 | 
				
			||||||
 | 
					        signal sqlstate '45000' set message_text = '部门不存在';
 | 
				
			||||||
 | 
					    end if;
 | 
				
			||||||
 | 
					    update employees join departments using (department_id)
 | 
				
			||||||
 | 
					    set salary = salary * (1 + percentage / 100)
 | 
				
			||||||
 | 
					    where department_name = dept_name;
 | 
				
			||||||
 | 
					    -- 存储过程怎么返回更新的员工数量
 | 
				
			||||||
 | 
					    -- 30 ms 中有 2 行受到影响 返回的影响行数应该就能反映更新的员工数量了
 | 
				
			||||||
 | 
					end;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					create function get_average_salary(dept_id int) returns decimal(10, 2)
 | 
				
			||||||
 | 
					begin
 | 
				
			||||||
 | 
					    declare result decimal(10, 2);
 | 
				
			||||||
 | 
					    if (select count(*) from employees where department_id = dept_id) <= 0 then
 | 
				
			||||||
 | 
					        set result = 0;
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
					        select avg(employees.salary) into result from employees where department_id = dept_id;
 | 
				
			||||||
 | 
					    end if;
 | 
				
			||||||
 | 
					    return result;
 | 
				
			||||||
 | 
					end;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					insert into departments
 | 
				
			||||||
 | 
					values (101, 'aaa'),
 | 
				
			||||||
 | 
					       (102, 'bbb');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					insert into employees(employee_name, department_id, salary)
 | 
				
			||||||
 | 
					values ('a', 101, 10),
 | 
				
			||||||
 | 
					       ('b', 101, 100),
 | 
				
			||||||
 | 
					       ('c', 102, 1000);
 | 
				
			||||||
 | 
					        \end{minted}
 | 
				
			||||||
 | 
					        \begin{minted}{SQL}
 | 
				
			||||||
 | 
					select get_average_salary(101);
 | 
				
			||||||
 | 
					        \end{minted}
 | 
				
			||||||
 | 
					        \begin{csv}
 | 
				
			||||||
 | 
					,get_average_salary(101)
 | 
				
			||||||
 | 
					1,55.00
 | 
				
			||||||
 | 
					        \end{csv}
 | 
				
			||||||
 | 
					        \begin{minted}{SQL}
 | 
				
			||||||
 | 
					select get_average_salary(103);
 | 
				
			||||||
 | 
					        \end{minted}
 | 
				
			||||||
 | 
					        \begin{csv}
 | 
				
			||||||
 | 
					,get_average_salary(103)
 | 
				
			||||||
 | 
					1,0.00
 | 
				
			||||||
 | 
					        \end{csv}
 | 
				
			||||||
 | 
					        \begin{minted}{SQL}
 | 
				
			||||||
 | 
					call increase_salary('aaa', 50);
 | 
				
			||||||
 | 
					        \end{minted}
 | 
				
			||||||
 | 
					        \begin{minted}{text}
 | 
				
			||||||
 | 
					[2024-11-02 11:13:13] 30 ms 中有 2 行受到影响
 | 
				
			||||||
 | 
					        \end{minted}
 | 
				
			||||||
 | 
					        \begin{minted}{SQL}
 | 
				
			||||||
 | 
					select * from employees;
 | 
				
			||||||
 | 
					        \end{minted}
 | 
				
			||||||
 | 
					        \begin{csv}
 | 
				
			||||||
 | 
					,employee_id,employee_name,department_id,salary
 | 
				
			||||||
 | 
					1,1,a,101,15.00
 | 
				
			||||||
 | 
					2,2,b,101,150.00
 | 
				
			||||||
 | 
					3,3,c,102,1000.00
 | 
				
			||||||
 | 
					        \end{csv}
 | 
				
			||||||
 | 
					        \begin{minted}{SQL}
 | 
				
			||||||
 | 
					call increase_salary('ccc', 100);
 | 
				
			||||||
 | 
					        \end{minted}
 | 
				
			||||||
 | 
					        \begin{minted}{text}
 | 
				
			||||||
 | 
					[2024-11-02 11:22:51] [45000][1644] 部门不存在
 | 
				
			||||||
 | 
					        \end{minted}
 | 
				
			||||||
 | 
					    \end{verification}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    \questionandanswer[]{
 | 
				
			||||||
 | 
					        存储过程、函数和触发器的区别?
 | 
				
			||||||
 | 
					    }{
 | 
				
			||||||
 | 
					        存储过程不能使用return语句返回结果,只能通过传入参数设置为out来返回结果;而函数可以直接使用return语句返回结果。
 | 
				
			||||||
 | 
					        触发器没有传入参数也不能返回结果,只能通过old和new获取更新前后的值。
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    \questionandanswer[]{
 | 
				
			||||||
 | 
					        触发器的作用?Mysql表中允许有多少个触发器?
 | 
				
			||||||
 | 
					    }{
 | 
				
			||||||
 | 
					        触发器定义了一系列操作,这一系列操作称为触发程序,当触发事件发生时,触发程序会自动运行。
 | 
				
			||||||
 | 
					        触发器主要用于监视某个表的插入(insert)、更新(update)和删除(delete)等更新操作,这些操作可以分别激活该表的insert、update和delete类型的触发程序运行,从而实现数据的自动维护。
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        在5.7.2版本以前,同一个表不能创建两个相同触发时间、触发事件的触发程序,那么就是6个触发器:
 | 
				
			||||||
 | 
					        before insert、after insert、before update、after update、before delete、after delete。
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        在5.7.2版本之后没有此限制,那么对触发器的数量就没有限制了。
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					\end{enumerate}
 | 
				
			||||||
 | 
					\end{document}
 | 
				
			||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user