From 3e4af81e3c7cb4e70385707dfb65080a8f1c7447 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=94=A1=E7=8E=AE=E9=93=AD?= <2373854303@qq.com> Date: Mon, 21 Oct 2024 22:34:47 +0800 Subject: [PATCH] =?UTF-8?q?=E6=8F=90=E4=BA=A41021=E4=BD=9C=E4=B8=9A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...40\345\217\212\347\273\203\344\271\240.md" | 651 ++++++++++++++++++ 1 file changed, 651 insertions(+) create mode 100644 "\350\224\241\347\216\256\351\223\255/20241021 \350\257\276\347\250\213\345\244\215\344\271\240\345\217\212\347\273\203\344\271\240.md" diff --git "a/\350\224\241\347\216\256\351\223\255/20241021 \350\257\276\347\250\213\345\244\215\344\271\240\345\217\212\347\273\203\344\271\240.md" "b/\350\224\241\347\216\256\351\223\255/20241021 \350\257\276\347\250\213\345\244\215\344\271\240\345\217\212\347\273\203\344\271\240.md" new file mode 100644 index 0000000..360488b --- /dev/null +++ "b/\350\224\241\347\216\256\351\223\255/20241021 \350\257\276\347\250\213\345\244\215\344\271\240\345\217\212\347\273\203\344\271\240.md" @@ -0,0 +1,651 @@ +## 课程复习 + +#### 数据库高级设计: + +##### 一、数据库设计 + +1. RBAC + + 基于角色的访问控制机制,主要用于计算机系统和网络环境中,通过对用户赋予不同的角色,从而控制用户能够执行的操作。这种机制使得系统的安全性管理更加灵活且易于维护,因为管理员只需要管理角色而不是直接管理每个用户的权限。 + + - CDM 概念模型 + - LDM 逻辑模型 + - PDM 物理模型 + +2. SKU + + 是零售业中用来标识库存商品的唯一识别码。每个SKU代表了一种独特的商品类型,包括了该商品的所有特定属性。 + +3. SPU + + 有时指的是“标准产品单元”或“商品单元”,这是在一些电商环境中使用的术语,但它不像SKU那样广泛使用。SPU可能指的是一个更高级别的产品标识符,它描述了一组具有相同基本特征但具有不同SKU的产品集合。 + +##### 二、视图 + +1. 概念 + + 视图是一种虚拟的表,是一个为了简化复杂查询语句的书写,另外也提高了数据库一定的安全性。 + + 查询是利用sql语句按照用户的需求自定义查询,更加灵活,查一次用一次。select查询的是一个结果集。 + +2. 优点 + + 1. 简化用户操作 + 2. 多角度查看同一数据 + 3. 提供逻辑独立性 + 4. 保护机密数据 + 5. 更清晰地表达查询 + +3. 语法 + + ```sql + -- 创建或更新一个视图 + create or replace view 视图名 as select * from 表名 where 条件 + + -- 修改视图名 + rename table 旧视图名 to 新视图名; + + -- 删除视图 + drop view 视图名; + + -- 查询视图 + select * from 视图名; + + -- 查看表和视图的类型及名称 + show full tables; + ``` + +##### 三、存储过程 + +1. 概念 + + 存储过程是数据库中一组为了完成特定功能的 SQL 语句集,经编译后存储在数据库中。用户通过指定存储过程的名字并给出参数(如果该存储过程带有参数)来执行它。 + +2. 优点 + + - 提高性能 + - 增强安全性 + - 提高代码的可维护性 + +3. 语法 + + ```sql + -- 修改分隔符 + delimiter // + + -- -------------------- + -- 一、in 参数 -- + create procedure 存储过程名称(in 参数名 参数类型) + begin + sql 语句集 + end; + + call 存储过程名称(值); -- 调用 + + -- 二、out 参数 -- + create procedure 存储过程名称(out 参数名 参数类型) + begin + sql 语句集 + end; + + set @outputVariable = NULL; -- 调用 + call 存储过程名称(@outputVariable); + select @outputVariable; + + -- 三、inout 参数 -- + create procedure 存储过程名称(inout 参数名 参数类型) + begin + sql 语句集 + end; + + set @inoutVariable = 初始值; -- 调用 + call 存储过程名称(@inoutVariable); + select @inoutVariable; + -- -------------------- + + -- 还原分隔符 + delimiter ; + + -- 调用存储过程 + call 存储过程名称(值[没参数可省略]); + + -- 删除存储过程 + drop procedure 存储过程名称; + + -- 查询现有的存储过程有哪些 + show procedure status where db = '数据库名称' and name like 'pro%'; + ``` + +##### 四、条件判断及循环 + +1. 条件判断: + + 1. if (表达式1,表达式2,表达式3) + + 2. ifnull (表达式1,表达式2) + + 3. if else + + if 条件表达1 then 语句1 ... [elseif 条件表达2 then] 语句块2 ... [else 语句块3 ... ] end if + + 4. case when + + 1. 单值判断 + + case 字段 when 值 then 结果1 + + when 值 then 结果2 + + else 结果3 end; + + 2. 根据范围区间判断 + + case + + when 条件1 then结果1 when 条件2 then结果2 else 结果3 end case; + +2. 循环: + + 1. while + + while 条件 do sql逻辑 ... + + end while ; + + 2. repeat + + repeat 要循环的语句 + + until 退出的条件 + + end repeat; + + 3. loop + leave + + [循环名:] loop sql逻辑 ... + end loop[循环] + +##### 五、普通常用函数 + +1. 字符串函数 + - CONCAT(str1, str2, ...):连接两个或多个字符串。 + - LENGTH(str):返回字符串的长度。 + - LOWER(str):将字符串转换为小写。 + - UPPER(str):将字符串转换为大写。 + - TRIM(str):删除字符串两端的空格。 + - LTRIM(str):删除字符串左侧的空格。 + - RTRIM(str):删除字符串右侧的空格。 + - REPLACE(str, search_str, replace_str):替换字符串中的子串。 + +2. 数值函数 + - ABS(x):返回数字的绝对值。 + - CEIL(x)`或`CEILING(x):返回大于或等于数字的最小整数。 + - FLOOR(x):返回小于或等于数字的最大整数。 + - MOD(x, y):返回两数相除的余数。 + - ROUND(x, d):将数字四舍五入到指定的小数位数。 + - RAND():返回一个随机数。 + +3. 日期和时间函数 + - NOW():返回当前的日期和时间。 + - CURDATE():返回当前的日期。 + - CURTIME():返回当前的时间。 + - DATEDIFF(date1, date2):返回两个日期之间的天数差。 + - TIMESTAMPDIFF(unit, datetime1, datetime2):返回两个日期/时间之间的差值。 + - DATE_ADD(date, INTERVAL expr unit):给日期加上一个时间间隔。 + - DATE_SUB(date, INTERVAL expr unit):从日期减去一个时间间隔。 + +##### 六、变量 + +1. 系统变量(@@) + 1. 会话变量 @@session + 2. 全局变量 @@global +2. 自定义变量(@) + 1. 用户变量 @变量名 + 2. 局部变量 + 1. begin end 之间 + 2. declare 变量名 数据类型 +3. 赋值 + 1. set 变量名 = 值 + 2. select 值 into 变量名 + 3. select 字段列表 into 变量名列表 from 表 where条件 + +##### 七、窗口函数 + +1. 可以保留原来表的结构和行数,但是使用前需要有over()子句。 +2. 把分组的group by 换成 partition 写在over()里。 +3. over()里不写表示整个表所有行都参与运算。 +4. over()里写order by 表示累计。 +5. 三种排名窗口函数: + - ROW_NUMBER():为每个组内的行分配一个唯一的连续整数。 + - RANK():为每个组内的行分配一个排名,如果存在相同的值,则分配相同的排名。 + - DENSE_RANK():与 RANK() 类似,但是排名是连续的,即使有相同的值。 +6. LEAD():返回当前行的下一行的某个列的值。 +7. LAG():返回当前行的上一行的某个列的值。 +8. SUM():计算某个列的总和。 +9. AVG():计算某个列的平均值。 +10. MIN() 和 MAX():分别计算某个列的最小值和最大值。 +11. FIRST_VALUE() 和 LAST_VALUE():分别计算出最大极值和最小极值。 + +##### 八、存储函数 + +1. 概念: + + - 存储函数和存储过程都是数据库中用于封装SQL代码的对象,它们都存储在数据库服务器上,可以在需要时被调用执行。 + + + - 存储函数可以有输入参数,但必须有返回值。 + + + - 存储函数必须返回一个值,这个值可以被SQL语句直接使用在`SELECT`子句中。 + + + +2. 具体语法: + + ```sql + -- 创建存储函数 + create function 名称(参数名类型 参数名类型) returns 返回值类型 + DETERMINISTIC / no sql / reads sql data + begin + declare 变量 类型; + select xx into 变量 from emp where 条件; + return 变量; + end; + + -- 调用存储函数 + select function 名称(参数); + + -- 删除存储函数 + drop function 名称; + ``` + +##### 九、游标 + +1. 主要特点: + + 1. 逐行处理:游标允许对查询结果集中的每一行进行相同或不同的操作。 + 2. 减少缓存:游标不是一次性对整个结果集进行同一种操作,减少了数据库的缓存。 + +2. 使用步骤: + + ```sql + 1. 声明游标: + declare 游标名称 cursor for select ...; + 2. 打开游标: + open 游标名称; + 3. 获取数据: + fetch 游标名称 变量名; + 4. 关闭游标: + close 游标名称; + ``` + +##### 十、触发器 + +1. 概念: + + MySQL中的触发器(Trigger)是一种特殊的存储过程,它在指定的数据库表上发生特定的事件(如INSERT、UPDATE或DELETE操作)时自动执行。触发器可以用来自动执行数据的完整性约束、数据的审核跟踪以及自动更新表中的数据等任务。 + +2. 基本语法: + + ```sql + -- 1.创建 + create trigger 触发器名称 触发时机(before / after) (insert / update / delete) on 表名 for each row + begin + -- 要触发的内容... + end; + + -- 2.查询 + show triggers; -- 查询所有触发器 + show triggers from 数据名 like '表名'; -- 查询具体表的触发器 + show triggers where 'TRIGGER' like 触发器名称; -- 查询具体的触发器 + + -- 3.修改 + 触发器和存储过程和自定义函数一样只能删除再建,不能修改 + + -- 4.删除 + drop trigger 触发器名称; + + -- 5.主动报错或抛出异常 + SIGNAL SQLSTATE 'XXXXX' set MESSAGE_TEXT = '提示信息’; + ``` + +##### 十一、事务 + +1. 概念: + + 现代的数据库系统为了解决数据库的多用户并发问题,通常会采用事务机制来保证数据的可靠性、精确性、一致性和完整性。 + +2. 四个特征: + + 1. 原子性(Atomicity):事务中多条SQL语句作为一个整体被执行,事务中的全部操作要么全部成功执行,要么都不执行。 + 2. 一致性(Consistency):事务应确保数据库的状态从一个一致状态转变为另一个一致状态,要么同时成功要么同时失败。 + 3. 隔离性(Isolation):多个事务并发执行时,一个事务的执行不应影响其他事务的执行。 + 4. 持久性(Durability):已提交的事务对数据库的修改应该永久保存在数据库中。 + +3. 基础语法: + + ```sql + -- 关闭系统全局的全动提交 + set @@autocommit = 0; + + -- 开启事务 + start transaction; + + -- 保存点的名字 + savepoint 保存点名字; + + -- 删除保存点 + release savepiont 保存点名字; + + -- 回滚 + rollback; + + -- 将事物回滚回保存点 + rollback to 保存点名字; + + -- 事物提交 + commit; + ``` + +##### 十二、索引 + +1. 概念 + + 索引是数据库表中一个特殊的数据结构,用于快速查找和访问表中的数据。它类似于书籍的目录。加速数据检索,优化查询性能,避免全表扫描。 + +2. 类型 + + - 单列索引:只包含单个列的索引。 + - 复合索引:由多个列组成的索引,用于加速涉及多个列的查询,使用要遵循最左原则。 + - 唯一索引:确保索引列中的值是唯一的,不允许重复。 + - 主键索引:一种特殊的唯一索引,且不允许为空,通常用于唯一标识一行数据。 + - 全文索引:用于对文本数据进行全文检索,主要用于查找大文本字段中的关键词。 + - 空间索引:用于地理数据类型的索引,加速空间查询。 + +3. 语法: + + ```sql + -- 创建索引 + create index 索引名 on 表名(字段名); + alter table 表名 add index 索引名(字段名); + + -- 建表时 + create table 表名( + id int primary key auto_increment, + 字段名 类型, + index 索引名 (字段名) + ); + + -- 删除索引 + drop index 索引名 on 表名; + alter table 表名 drop index 索引名; + + -- 查看查询的执行计划,分析索引的使用情况 + explain select * from 表名 WHERE 条件; + ``` + +## 课堂练习: + +二、综合题(第1大题40分,第2大题30分,共70分) + + +1. 利用另外一个文件`initDb.sql`,完成以下题目: + + 1.1. (10分) 对学生姓名创建普通索引(`idx_StudentName`) + + ```sql + create index idx_StudentName on student(StudentName); + ``` + + 1.2. (10分) 创建视图`V_StudentHobbyInfo`,其中包含姓名(`StudentName`),爱好(`Hobby`),特长(`Specility`)列,并分别取别名为`vw_StudentName`,`vw_Hoppy`,`vw_Speclitiy` + + ```sql + create view V_StudentHobbyInfo as select + st.StudentName vw_StudentName, + si.Hobby vw_Hoppy, + si.Speciality vw_Speclitiy + from studentextinfo si join student st on st.StudentCode = si.StudentCode; + ``` + + ` + 1.4. (5分) 查询学生`马又云`的生源地,要求显示:姓名(`StudentNameame`),生源地(`OriginPosition`)` + + ```sql + select + st.StudentName 姓名, + si.OriginPosition 生源地 + from student st join studentextinfo si on si.StudentCode = st.StudentCode + where st.StudentName = '马又云'; + ``` + + ` + 1.5. (5分) 查询学生表(`StudentInfo`)中还未还书的读者的学号(`StudentCode`)和姓名(`StudentName`),以及借书时间(`BorrowTime`)` + + ```sql + select + st.StudentCode 学号, + st.StudentName 姓名, + bo.BorrowTime 借书时间 + from student st join borrowrecord bo on bo.StudentCode = st.StudentCode + where bo.ReturnTime is null; + ``` + + ` + 1.6. (5分) 查询借阅过书籍《射雕英雄传》的学生,要求显示:学生姓名(`StudentName`),学院(`School`),图书名(`BookName`),借阅时间(`BorrowTime`) + + ```sql + with + bo as (select * from bookinfo), + bi as (select * from bookextinfo), + bw as (select * from borrowrecord), + st as (select * from student) + select + st.StudentName 学生姓名, + st.School 学院, + bo.Bookname 图书名, + bw.BorrowTime 借阅时间 + from bo,bi,bw,st + where + bo.ISBN = bi.ISBN and + bi.Barcode = bw.Barcode and + bw.StudentCode = st.StudentCode and + bo.BookName = '射雕英雄传'; + ``` + + +2. (30分)某医院病房计算机管理中心需要如下信息: + + ``` + 科室:科编号、科名、科地址、科电话、医生姓名 + 病房:病房号、床位号、所属科室名 + 医生:姓名、职称、所属科室名、年龄、工作证号 + 病人:病历号、姓名、性别、诊断、主治医生、病房号 + ``` + + 2.1. (10分)其中,一个科室有多个病房、多个医生;一个病房只能属于一个科室,一名医生只属于一个科室,但可负责多名病人的诊治,一个病人的主主治生只有一个。科编号是标识列,从1开始自增长,步进值为1,医生职称有:实习,初级,中级,高级。 + 请设计该表关系模式结构(数据库物理模型),要求: + + ``` + a. 中文名和英文名称清晰(可借助有道翻译工具,不允许开网页) + b. 表关系准确,包括主键,外键,标识列 + c. 将完成的设计截图,并且保存物理模型文件,命名为恰当的名称 + d. 将截图和物理模型文件放在自己的文件夹中 + ``` + + - CDM 概念模型 + + ![image-20241021171931208](https://gitee.com/hyo-ja/picture-warehouse/raw/master/images/202410211719253.png) + + - LDM 逻辑模型 + + ![image-20241021171943347](https://gitee.com/hyo-ja/picture-warehouse/raw/master/images/202410211719398.png) + + - PDM 物理模型 + + ![image-20241021171857988](https://gitee.com/hyo-ja/picture-warehouse/raw/master/images/202410211718039.png) + + ```sql + -- sql数据 + drop database if exists hospital; + + create database if not exists hospital; + + use hospital; + + /*==============================================================*/ + /* DBMS name: MySQL 5.0 */ + /* Created on: 2024/10/21 16:59:31 */ + /*==============================================================*/ + + + drop table if exists administrative_office; + + drop table if exists doctor; + + drop table if exists inpatient_ward; + + drop table if exists patient; + + /*==============================================================*/ + /* Table: administrative_office */ + /*==============================================================*/ + create table administrative_office + ( + administrative_office_id int not null auto_increment, + administrative_office_name varchar(20), + administrative_office_address varchar(20), + administrative_office_phone varchar(11), + doctor_name varchar(10), + primary key (administrative_office_id) + ); + + /*==============================================================*/ + /* Table: doctor */ + /*==============================================================*/ + create table doctor + ( + doctor_name varchar(10), + role varchar(10), + administrative_office_name varchar(20), + age int, + card_number int not null, + administrative_office_id int not null, + primary key (card_number) + ); + + /*==============================================================*/ + /* Table: inpatient_ward */ + /*==============================================================*/ + create table inpatient_ward + ( + inpatient_ward_id int not null auto_increment, + administrative_office_id int not null, + Seat_umber varchar(20), + administrative_office_name varchar(20), + primary key (inpatient_ward_id) + ); + + /*==============================================================*/ + /* Table: patient */ + /*==============================================================*/ + create table patient + ( + patient_id int not null auto_increment, + card_number int not null, + name varchar(10), + sex char(1), + diagnose varchar(255), + attending_doctor varchar(10), + primary key (patient_id) + ); + + alter table doctor add constraint FK_link5 foreign key (administrative_office_id) + references administrative_office (administrative_office_id) on delete restrict on update restrict; + + alter table inpatient_ward add constraint FK_link foreign key (administrative_office_id) + references administrative_office (administrative_office_id) on delete restrict on update restrict; + + alter table patient add constraint FK_link4 foreign key (card_number) + references doctor (card_number) on delete restrict on update restrict; + + -- 插入数据 + INSERT INTO administrative_office (administrative_office_name, administrative_office_address, administrative_office_phone, doctor_name) VALUES + ('Office A', '123 Main St', '12345678901', '张三'), + ('Office B', '456 Elm St', '23456789012', '李四'), + ('Office C', '789 Oak St', '34567890123', '王五'); + + INSERT INTO doctor (doctor_name, role, administrative_office_name, age,card_number, administrative_office_id) VALUES + ('张三', '初级', 'Office A', 22,10086,1), + ('李四', '中级', 'Office B', 38,10087,2), + ('王五', '高级', 'Office C', 52,10088,3); + + INSERT INTO patient (card_number,`name`, sex, diagnose, attending_doctor) VALUES + (10086, '肖飞鹏', '男', '感冒', '张三'), + (10087, '卢比伦', '女', '发烧', '李四'), + (10088, '陈俊杰', '男', '头疼', '王五'); + + INSERT INTO inpatient_ward (administrative_office_id,Seat_umber,administrative_office_name) VALUES + (1, 'Room 101, Bed 1', 'Office A'), + (2, 'Room 202, Bed 2', 'Office B'), + (3, 'Room 303, Bed 3', 'Office C'); + ``` + + 2.2. (10分)创建存储过程实现:传入病历号,查询其对应的主治医生及其所在的病房号、床位号。 + + ```sql + -- 判断存储过程是否存在并删除 + drop procedure if exists pro_patient; + + -- 修改分隔符 + delimiter // + + -- 创建存储过程 + create procedure pro_patient(in patientId int) + begin + -- 主治医生 + declare AttendingPhysician varchar(10); + -- 病床号 + declare BedId varchar(10); + -- 床位号 + declare BedNumber varchar(20); + + -- 查询主治医生 + select doc.doctor_name into AttendingPhysician from patient pat join + doctor doc on doc.card_number = pat.card_number + where pat.patient_id = patientId; + + -- 查询所在的病房号、床位号 + select + inw.administrative_office_id 病房号, + inw.Seat_umber 床位号 into BedId,BedNumber from patient pat join + doctor doc on doc.card_number = pat.card_number + join inpatient_ward inw on inw.administrative_office_name = doc.administrative_office_name + where pat.patient_id = patientId; + + -- 输出 + select AttendingPhysician 主治医生,BedId 病房号,BedNumber 床位号; + end // + + -- 还原分隔符 + delimiter ; + + call pro_patient(1); + ``` + + ![image-20241021190714939](https://gitee.com/hyo-ja/picture-warehouse/raw/master/images/202410211907959.png) + + 2.3. (10分)创建触发器实现:当医生离职时,检查其是否还有未完成医治的病人,如果还存在病人则不予离职,否则可以离职。 + + ```sql + -- 创建触发器 + create trigger tri_doctor before delete on doctor for each row + begin + declare patient_count int; + -- 查询当前医生是否还有病人 + select count(*) into patient_count from patient where card_number = old.card_number; + -- 检查其是否还有未完成医治的病人,如果还存在病人则不予离职,否则可以离职。 + if patient_count is null then + SIGNAL SQLSTATE '66666' set MESSAGE_TEXT = '该医生还有病人,不予离职'; + end if; + end; + ``` -- Gitee