Files
StudyNote/山东理工大学/数据库/作业.md
2026-02-13 23:38:38 +08:00

685 lines
17 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 实验一
> ## 如何建表 create Table
```sql
CREATE TABLE hhh(
id int auto_increment primary key,
name varchar(30) not null,
age int ,
birthday date,
is_actiove boolean default true
);
create table (
,
,
);
```
> ## 如何新增字段 Add column
```sql
Alter table role add age int not null
ALTER TABLE <> ADD <><>[];
```
> ## 如何增加数据
```sql
INSERT INTO products (maker, model, `type`) VALUES('A', '1001', 'pc'),
INSERT INTO (2.....)values `1`,`2`,`3`
```
> ## **DDL DML**
DDLData Definition Language语句 `数据定义语言`,主要是进行定义/改变表的结构、数据类型、表之间的链接等操作。常用的语句关键字有 CREATE、DROP、ALTER 等。
```sql
CREATE TABLE (
1 ,
2 ,
3 ,
...
)
ALTER TABLE ;
egALTER TABLE ADD ;
ALTER TABLE CHANGE ;
ALTER TABLE DROP ;
DROP TABLE ;
DROP DATABASE ;
```
DMLData Manipulation Language语句: `数据操纵语言`,主要是对数据进行增加、删除、修改操作。常用的语句关键字有 INSERT、UPDATE、DELETE 等。
```sql
INSERT INTO (1,2,...) values (,,...),(,,...);
UPDATE SET = WHERE ;
DELETE FROM WHERE ;
```
> ## Like
```sql
SELECT *
FROM customers
WHERE firstname LIKE '%a%';
```
- `%`:匹配任意字符(包括零个字符)。
- `_`:匹配单个字符。
# 实验二
> ## 四种连接 等值连接 自然连接 相关子查询 非相关子查询
> ## join(equal join: comma where join on) 等值连接
```sql
SELECT 1, 2, ...
FROM 1
[INNER] JOIN 2 -- INNER可省略默认就是内连接
ON 1. = 2. -- 明确分离连接条件
WHERE 1. = xxx -- 仅存放过滤条件,可读性更强
[AND 2. = xxx];
select name ,age
from role join user
on role.id=user.id
where role.name="郑笃实" and ....
-- 例子
-- 1. 老式逗号+WHERE写法
SELECT s.student_name, sc.subject, sc.score
FROM student s, score sc -- 逗号分隔两张表,给表起别名简化书写
WHERE s.student_id = sc.student_id -- 等值连接条件
AND sc.score >= 60; -- 过滤及格成绩
-- 2. 标准JOIN ON写法推荐
SELECT s.student_name, sc.subject, sc.score
FROM student s
JOIN score sc
ON s.student_id = sc.student_id -- 明确连接条件
WHERE sc.score >= 60; -- 明确过滤条件
```
> ## natural join(natural join or join using()) 自然连接
```sql
-- 2. 标准JOIN ON写法推荐必须两张表中均存在该列且列名完全一致必须两张表中均存在该列且列名完全一致
SELECT s.student_name, sc.subject, sc.score
FROM student s
JOIN score sc
USING (sc.student_id) -- 明确连接条件 -- ON s.student_id = sc.student_id
WHERE sc.score >= 60; -- 明确过滤条件
-- 其实就跟join on一样而已 只不过是 孔乙己的茴的四种写法罢了......
```
> ## corelated subquery 相关子查询
相关子查询(又称关联子查询)是**依赖外部查询的列值**才能执行的子查询,无法独立运行(子查询中会引用外部查询的表列)。
```sql
-- 需求:查询「个人成绩大于其所在班级平均成绩」的学生姓名和对应科目、成绩
SELECT s.student_name, sc.subject, sc.score
FROM student s
JOIN score sc ON s.student_id = sc.student_id
-- 外部查询的s.class_id传入子查询作为平均成绩的计算条件
WHERE sc.score > (
SELECT AVG(sc2.score) -- 子查询:计算当前学生所在班级的平均成绩
FROM score sc2
JOIN student s2 ON sc2.student_id = s2.student_id
WHERE s2.class_id = s.class_id -- 引用外部查询的s.class_id依赖外部查询
);
sql sql里面
```
> ## noncorelated subquery 非相关子查询
是**不依赖外部查询**的子查询,可以独立执行并返回一个结果集,外部查询直接使用该结果集进行后续计算,是最常用的子查询类型。
```sql
-- 需求查询“数学科目满分100分”的学生姓名
SELECT student_name
FROM student
WHERE student_id = ( -- 子查询返回单行结果时,用=匹配
SELECT student_id
FROM score
WHERE subject = '数学' AND score = 100
LIMIT 1 -- 确保子查询返回单行
);
-- 这个其实就是大多数时候 写的sql语句 (虽然工作中 一般都不这么手写原生的sql语句hhhh
```
> ## UNION 大法
有思路但是不知道这么写?
有多张表但是不知道这么写在一个sql里面
**为什么要写在一个sql里面 UNION大法帮助你**
```sql
SELECT p.model, pc.price
FROM products p
JOIN pcs pc ON pc.model = p.model
WHERE p.maker = 'B'
UNION
SELECT p.model, l.price
FROM products p
JOIN laptops l ON l.model = p.model
WHERE p.maker = 'B'
UNION
SELECT p.model, pr.price
FROM products p
JOIN printers pr ON pr.model = p.model
WHERE p.maker = 'B';
-- left join
SELECT p.model, COALESCE(pc.price, l.price, pr.price) AS price
FROM products p
LEFT JOIN pcs pc ON pc.model = p.model
LEFT JOIN laptops l ON l.model = p.model
LEFT JOIN printers pr ON pr.model = p.model
WHERE p.maker = 'B';
-- 谁最清晰一目了然
```
> ## 小tip
SELECT 分组列, 聚合函数(...)
FROM 表
WHERE 行条件
GROUP BY 分组列
HAVING 组条件(通常含聚合函数)
ORDER BY ... 排序顺序
- GROUP BY 不一定要配合having
- GROUP BY 是按照....分组 就是 类似去重了
- HAVING 就是对于这个分组的限制 一般都是
Find those makers of at least two different computers (PCs or laptops) with speeds of at least 2.80.
```sql
SELECT maker
FROM (
SELECT p.maker, p.model
FROM products p
JOIN pcs pc ON pc.model = p.model
WHERE pc.speed >= 2.80
UNION
SELECT p.maker, p.model
FROM products p
JOIN laptops l ON l.model = p.model
WHERE l.speed >= 2.80
) t
GROUP BY maker
HAVING COUNT(DISTINCT model) >= 2;
```
### 8) Find all customer's information purchased model 1001 and 1002.
(找出**同时**买过 1001 和 1002 的客户信息)
```sql
SELECT c.*
FROM customers c
JOIN sales s ON s.customer_id = c.customer_id
WHERE s.model IN ('1001', '1002')
GROUP BY c.customer_id, c.firstname, c.lastname, c.city, c.address, c.email
HAVING COUNT(DISTINCT s.model) = 2;
```
> 记忆点:`WHERE model IN (...)` 先筛两种型号,再用 `HAVING COUNT(DISTINCT model)=2` 保证“两种都买过”。
------
### 9) Find all laptops whose hard disk is greater than all PCs' hard disk.
(找出所有 laptop使其 hd **大于所有** PC 的 hd
**最稳写法(用 MAX**
```sql
SELECT *
FROM laptops
WHERE hd > (SELECT MAX(hd) FROM pcs);
```
(也可以写 ALL
```sql
SELECT *
FROM laptops
WHERE hd > ALL (SELECT hd FROM pcs);
```
------
### 10) Find all customer that not purchase any products.
(找出从未购买过任何产品的客户)
**方法1LEFT JOIN**
```sql
SELECT c.*
FROM customers c
LEFT JOIN sales s ON s.customer_id = c.customer_id
WHERE s.customer_id IS NULL;
```
**方法2NOT EXISTS**
```sql
SELECT c.*
FROM customers c
WHERE NOT EXISTS (
SELECT 1
FROM sales s
WHERE s.customer_id = c.customer_id
);
```
# 实验三
> ## 触发器 Trigger
```sql
//
CREATE TRIGGER trigger_name
{BEFORE | AFTER} {INSERT | UPDATE | DELETE}
ON table_name FOR EACH ROW
BEGIN
-- 觸發器執行的SQL語句
statement1;
statement2;
statement3;
END;
//
show trigger
//
drop trigger schemaName.triggerName
```
```sql
1AFTER行级触发器PCS的价格发生变化后就自动在价格变化表pcprice_log中增加一条相应记录
create trigger abbc
after update on for each row
begin
insert into log values(old.values,new.values,,,)
end
```
```sql
2AFTER行级触发器Customer中的一个顾客信息后Sales中该顾客的所有购买记录
create trigger abbb
begin DELETE on customer for each row
begin
delete from sales where contomerid=old.contomerid
end
```
```sql
3DML操作的用户进行安全检查
```
```sql
51000010%10%
create trigger asdgfsd
after insert on for each row
begin
DECLARE total_paid DECIMAL(12,2);
SELECT SUM(paid)
INTO total_paid
FROM Sales
WHERE customer_id = NEW.customer_id;
IF total_paid > 10000 THEN
UPDATE Customer
SET discount = 0.1000
WHERE customer_id = NEW.customer_id
AND discount < 0.1000;
END IF;
end
```
```sql
6"AllPaid""AllPaid"
CREATE TRIGGER trg_sales_allpaid_ins
AFTER INSERT ON Sales
FOR EACH ROW
BEGIN
UPDATE Customer
SET AllPaid = AllPaid + NEW.paid
WHERE customer_id = NEW.customer_id;
END
CREATE TRIGGER trg_sales_allpaid_ins
AFTER update ON Sales
FOR EACH ROW
BEGIN
UPDATE Customer
SET AllPaid = AllPaid + NEW.paid
WHERE customer_id = NEW.customer_id;
END$$
CREATE TRIGGER trg_sales_allpaid_ins
AFTER delete ON Sales
FOR EACH ROW
BEGIN
UPDATE Customer
SET AllPaid = AllPaid + NEW.paid
WHERE customer_id = NEW.customer_id;
END$$
```
**关于触发器的new虚拟表格和old虚拟表格**
当进行`insert`的时候new表格可以获取插入的数据。
当进行`delete`的时候old表格可以获取被删除行的数据。
当进行`update`的时候new表格中是修改后的数据old表格中是被修改行的数据。
# 实验四
> ## 存储过程
**我们之前所学习的 MySQL 语句都是针对一个表或几个表的单条 SQL 语句,但是在数据库的实际操作中,经常会有需要多条 SQL 语句处理多个表才能完成的操作。**
**例如:** `张三工资是否大于 所属部门的平均工资` 先知道张三部门,计算平均工资,是否大于
**存储过程**是一组为了完成特定功能的 **SQL 语句集合**
- 减少网络传输量(客户端不需要把所有的 SQL 语句通过网络发给服务器)
- 减少了 SQL 语句暴露在 网上的风险,也提高了数据查询的安全性
- 简化操作提高了sql语句的重用性减少了开发程序员的压力
- 减少操作过程中的失误,提高效率
```sql
# ,SQL每个SQL需要使用 ;
# Mysql ;sql语言的结束语 BEGIN --- END 中的分号会导致声明存储过程的语法结束,报错;
# 使 DELTMITER MYSQL的结束符号 (// , Mysql的结束符号
DELIMITER //
CREATE PROCEDURE (IN|OUT|INOUT ,...)
[characteristics ...]
BEGIN
DECLARE
#
END //
# DELIMITER Mysql的结束符所以执行: END //
DELIMITER ;
# SQL ; .
# DELTMITER Mysql的结束符, ,使,Mysql默认结束符 ; ,
# Java ( ,....){ ; } .
```
| 参数类型 | 作用 | 传递方向 | 特点说明 |
| :------- | :--------------------------------- | :--------------------- | :--------------------------------------------- |
| IN | 输入参数,给存储过程传入值 | 调用时传入,过程内只读 | 过程内不能修改传入值(改变不影响调用者) |
| OUT | 输出参数,存储过程把值返回给调用者 | 过程内写,调用后拿结果 | 调用时不传值,过程内部给它赋值,调用后取出值 |
| INOUT | 输入输出参数,既传入又返回结果 | 调用时传入,过程内读写 | 过程内可以读取初始值并修改,调用结束后返回新值 |
> ## 例子
```sql
CREATE PROCEDURE selId(IN ID INt, NNAME DOUBLE) # in
BEGIN
-- SELECT * FROM employees WHERE employee_id = 100;
SELECT * FROM employees WHERE employee_id = ID;
END
#:
CALL selId(100);
#:
CALL selId('100');
#: ,...
SET @eid = 100
CALL selId(@eid);
```
> ## 存储函数
```sql
-- 存储函数 和 存储过程声明语法大致也相同,
CREATE FUNCTION ([IN] )
RETURNS
[characteristics...]
BEGIN
-- 函数体
-- 函数体中存在 RETURN 语句
END
```
- **参数列表:** 存储函数 声明比较严格,参数只能是 `IN入参` **默认也是IN 所以可以不用声明参数 IN 更加符合编程语言的规范.**
- **RETURNS** 表示存储函数的 返回类型, **存储函数只能有一个返回值. 且`必须有一个返回值.`**
- **[characteristics…]** 和存储过程一样,声明对函数内部的声明约束.
- **BEGIN…END** 和存储过程一样包含方法体,如果只有一条语句,也可以省略.
```sql
# id
DELIMITER $$
CREATE FUNCTION find(empid INT)
RETURNS VARCHAR(60)
BEGIN
DECLARE name VARCHAR(50);
SELECT CONCAT(firstname, lastname) INTO name
FROM employees
WHERE id = empid;
RETURN name;
END$$
DELIMITER ;
#
select find(123);
select find(3123);
```
> **存储函数FUNCTION不支持 `OUT / INOUT` 参数**,只能有 **`IN` 参数**(输入参数)。
```sql
# RateModel(cid, m, r)
# cid m r Ratings
# rating_time
# Products m
#number_of_ratings
#total_rating
CREATE PROCEDURE RateModel(IN cid VARCHAR(20), IN m VARCHAR(20), IN r INT)
BEGIN
DECLARE v_cnt INT;
DECLARE v_sum INT;
-- 1) 插入一条新评分(历史保留)
INSERT INTO Ratings(customer_id, model, rating_time, rating)
VALUES (cid, m, NOW(), r);
-- 2) 重新统计该型号 m 的评分次数和总分(只统计非 NULL
SELECT COUNT(rating),SUM(rating)
INTO v_cnt, v_sum
FROM Ratings
WHERE model = m AND rating IS NOT NULL;
-- 3) 更新 Products
UPDATE Products
SET number_of_ratings = v_cnt,
total_rating = IF(v_cnt = 0, NULL, v_sum)
WHERE model = m;
END
```
```sql
# DeleteRating(cid, m)
#/ cid m
# Ratings
#customer_id = cid
#model = m
#rating = NULL
# rating_time
create procedure DeleteRating(in cid int, in m varchar(50))
begin
```
# Functional Dependency and Normal Form
>请给出 **函数依赖 (Functional Dependency)** 的定义,并解释 **平凡函数依赖 (Trivial FD)****非平凡函数依赖 (Non-trivial FD)**
> 求候选码
```sql
Let relation (i.e. table) R(ABCDEFGH) have the following functional dependencies:
A B
CH A
B E
BD C
EG H
DE F
Find all keys of relation R(ABCDEFG) with functional dependencies.
#FD的所有的候选码
```
1. **先算出所有的RHS**
1. RHS就是在等号右边的 RHS={B A E C H F }
2. **所以我们要以不在RHS的字母开始 也就是C D**
3. **算{C D}+ 就是看 C D 能推出来什么 看起来什么都不能推出来 只有自己**
4. **那就算三个的 {ACD} 能推出全集 那就是 acd是一个key**
1. 然后发现BCD也是
5. **发现剩下的三位的不够了**
6. 看四位的CDGH CDEG 是
7. 最终总结u所有的candidate key 是 {ADG} {BDG} {CDGH} {CDEG}
8. 判断下面是否有冗余的
1. 邪修法门
1. L 只在左边出现过的 (包的)
2. R 只在右边出现过的 (不可能)
3. LR 两边都出现过的 (有可能成为候选码)
> 判断是否符合BCNF
```
The relation R has the attributes R(ABCD) and the functional dependencies F={AB→C, C→D, D→A}, Is the relation R in BCNF? Briefly explain your answer.
```
> 求最小依赖集