init
This commit is contained in:
684
山东理工大学/数据库/作业.md
Normal file
684
山东理工大学/数据库/作业.md
Normal file
@@ -0,0 +1,684 @@
|
||||
# 实验一
|
||||
|
||||
> ## 如何建表 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**
|
||||
|
||||
DDL(Data Definition Language)语句: `数据定义语言`,主要是进行定义/改变表的结构、数据类型、表之间的链接等操作。常用的语句关键字有 CREATE、DROP、ALTER 等。
|
||||
|
||||
```sql
|
||||
CREATE TABLE 表名(
|
||||
列名1 数据类型,
|
||||
列名2 数据类型,
|
||||
列名3 数据类型,
|
||||
...
|
||||
)
|
||||
|
||||
ALTER TABLE 表名;
|
||||
eg:ALTER TABLE 表名 ADD 列名 数据类型;(添加一个列)
|
||||
ALTER TABLE 表名 CHANGE 列名 新列名 新数据类型;(修改列名)
|
||||
ALTER TABLE 表名 DROP 列名;
|
||||
|
||||
DROP TABLE 表名;
|
||||
DROP DATABASE 数据库名;
|
||||
```
|
||||
|
||||
|
||||
|
||||
DML(Data 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.
|
||||
|
||||
(找出从未购买过任何产品的客户)
|
||||
|
||||
**方法1:LEFT JOIN**
|
||||
|
||||
```sql
|
||||
SELECT c.*
|
||||
FROM customers c
|
||||
LEFT JOIN sales s ON s.customer_id = c.customer_id
|
||||
WHERE s.customer_id IS NULL;
|
||||
```
|
||||
|
||||
**方法2:NOT 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
|
||||
(1)定义AFTER行级触发器,当电脑表PCS的价格发生变化后就自动在价格变化表pcprice_log中增加一条相应记录
|
||||
|
||||
create trigger abbc
|
||||
after update on 电脑表 for each row
|
||||
begin
|
||||
insert into log values(old.values,new.values,,,)
|
||||
end
|
||||
|
||||
```
|
||||
|
||||
|
||||
|
||||
```sql
|
||||
(2)定义AFTER行级触发器,当删除顾客表Customer中的一个顾客信息后,同时删除购买信息表Sales中该顾客的所有购买记录
|
||||
|
||||
create trigger abbb
|
||||
begin DELETE on customer for each row
|
||||
begin
|
||||
delete from sales where contomerid=old.contomerid
|
||||
end
|
||||
|
||||
```
|
||||
|
||||
|
||||
|
||||
```sql
|
||||
(3)需要对在表上进行DML操作的用户进行安全检查,看是否具有合适的特权
|
||||
|
||||
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
```sql
|
||||
(5)如果一个特定客户支付的总金额高于10000,该客户的折扣小于10%然后将该客户的折扣设置为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.
|
||||
```
|
||||
|
||||
|
||||
|
||||
> 求最小依赖集
|
||||
|
||||
|
||||
Reference in New Issue
Block a user