From 281083bf853f4e9c346a70e0dab6b716359071fa Mon Sep 17 00:00:00 2001 From: smallkun Date: Fri, 21 Mar 2025 10:34:07 +0800 Subject: [PATCH] Auto commit --- 2208/触发器练习题.md | 415 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 414 insertions(+), 1 deletion(-) diff --git a/2208/触发器练习题.md b/2208/触发器练习题.md index 08a557b..4a8d963 100644 --- a/2208/触发器练习题.md +++ b/2208/触发器练习题.md @@ -120,78 +120,491 @@ SET MESSAGE_TEXT = '错误消息'; 创建一个触发器 `before_employee_insert`,在插入 `employee` 表数据之前,检查员工的工资是否在其对应职位的 `min_salary` 和 `max_salary` 范围内。如果超出范围,阻止插入并抛出错误。 +```sql +DELIMITER $$ +DROP TRIGGER IF EXISTS before_employee_insert; +CREATE TRIGGER before_employee_insert +BEFORE INSERT ON employee +FOR EACH ROW +BEGIN + + IF NEW.salary > ( + SELECT j.max_salary + FROM job j + WHERE j.job_id = NEW.job_id + ) OR NEW.salary < ( + SELECT j.min_salary + FROM job j + WHERE j.job_id = NEW.job_id + ) THEN + SIGNAL SQLSTATE '45000' + SET MESSAGE_TEXT = '工资值错误,不在职务工资范围内'; + END IF; +END $$ +DELIMITER ; + +INSERT INTO employee +VALUES(DEFAULT, '雷昊', 0, NOW(), 1, 1); +``` + + + #### 练习题 2: 自动更新部门人数 创建一个触发器 `after_employee_insert`,在插入 `employee` 表数据之后,自动更新 `department` 表中的部门人数(假设 `department` 表新增一个字段 `employee_count`)。 +```sql +ALTER TABLE department ADD employee_count INT UNSIGNED; + +DELIMITER $$ +DROP TRIGGER IF EXISTS after_employee_insert; +CREATE TRIGGER after_employee_insert +AFTER INSERT ON employee +FOR EACH ROW +BEGIN + UPDATE department d + SET d.employee_count = ( + SELECT COUNT(*) + FROM employee e + WHERE e.dept_id = d.dept_id + ); +END $$ +DELIMITER ; + +INSERT INTO employee +VALUES(DEFAULT, '雷昊', 60000.00, NOW(), 1, 1); +``` + + + #### 练习题 3: 工资变更日志 创建一个触发器 `after_employee_update`,在更新 `employee` 表的 `salary` 字段后,将变更记录插入到一个新的日志表 `salary_log` 中,记录员工 ID、旧工资、新工资和变更时间。 +```sql +DROP TABLE IF EXISTS salary_log; +CREATE TABLE salary_log( + emp_id INT, + old_salary DECIMAL(10, 2), + new_slaray DECIMAL(10, 2), + update_date DATE +); + +DELIMITER $$ +DROP TRIGGER IF EXISTS after_employee_update; +CREATE TRIGGER after_employee_update +BEFORE UPDATE ON employee +FOR EACH ROW +BEGIN + IF NEW.salary <> OLD.salary THEN + INSERT INTO salary_log() + VALUES(NEW.emp_id, OLD.salary, NEW.salary, NOW()); + END IF; +END $$ +DELIMITER ; + +UPDATE employee e +SET e.salary = 10 +WHERE e.emp_id = 1; +``` + + + #### 练习题 4: 删除员工时备份数据 创建一个触发器 `before_employee_delete`,在删除 `employee` 表数据之前,将被删除的员工数据插入到一个备份表 `employee_backup` 中。 +```sql +CREATE TABLE employee_backup AS +SELECT * +FROM employee +WHERE 0; + +DELIMITER $$ +DROP TRIGGER IF EXISTS before_employee_delete; +CREATE TRIGGER before_employee_delete +BEFORE DELETE ON employee +FOR EACH ROW +BEGIN + INSERT INTO employee_backup() + VALUES(OLD.emp_id, OLD.emp_name, OLD.salary, OLD.hire_date, OLD.dept_id, OLD.job_id); +END $$ +DELIMITER ; + +DELETE FROM employee +WHERE emp_id = 20; +``` + + + #### 练习题 5: 自动设置默认职位 创建一个触发器 `before_employee_insert`,在插入 `employee` 表数据时,如果未指定 `job_id`,则自动将其设置为 `job` 表中的默认职位(假设默认职位的 `job_id` 为 1)。 +```sql +DELIMITER $$ +DROP TRIGGER IF EXISTS before_employee_insert; +CREATE TRIGGER before_employee_insert +BEFORE INSERT ON employee +FOR EACH ROW +BEGIN + IF NEW.job_id IS NULL THEN + SET NEW.job_id = 1; + END IF; +END $$ +DELIMITER ; + +INSERT INTO employee +VALUES(DEFAULT, '雷昊', 60000.00, NOW(), 1, NULL); +``` + + + #### 练习题 6: 防止修改入职日期 创建一个触发器 `before_employee_update`,在更新 `employee` 表数据时,防止修改 `hire_date` 字段。如果尝试修改,抛出错误。 +```sql +DELIMITER $$ +DROP TRIGGER IF EXISTS before_employee_update; +CREATE TRIGGER before_employee_update +BEFORE UPDATE ON employee +FOR EACH ROW +BEGIN + IF NEW.hire_date <> OLD.hire_date THEN + SIGNAL SQLSTATE '45000' + SET MESSAGE_TEXT='不允许修改用户的入职时间'; + END IF; +END $$ +DELIMITER ; +UPDATE employee e +SET e.hire_date = '2025-3-20' +WHERE e.emp_id = 1; +``` + + + #### 练习题 7: 自动计算工龄 创建一个触发器 `before_employee_insert`,在插入 `employee` 表数据时,自动计算员工的工龄(以年为单位),并将其存储到一个新字段 `years_of_service` 中。 +```sql +ALTER TABLE employee ADD years_of_service INT; + +DELIMITER $$ +DROP TRIGGER IF EXISTS before_employee_insert; +CREATE TRIGGER before_employee_insert +BEFORE INSERT ON employee +FOR EACH ROW +BEGIN + SET NEW.years_of_service = TIMESTAMPDIFF(YEAR,NEW.hire_date,NOW()); +END $$ +DELIMITER ; + +SELECT TIMESTAMPDIFF(YEAR,e.hire_date,NOW()) +FROM employee e; + +INSERT INTO employee +VALUES(DEFAULT, '雷昊', 60000.00, '2022-12-31', 1, 1, NULL); +``` + + + #### 练习题 8: 防止删除部门 创建一个触发器 `before_department_delete`,在删除 `department` 表数据之前,检查该部门是否还有员工。如果有员工,阻止删除并抛出错误。 +```sql +DELIMITER $$ +DROP TRIGGER IF EXISTS before_department_delete; +CREATE TRIGGER before_department_delete +BEFORE DELETE ON department +FOR EACH ROW +BEGIN + IF (SELECT COUNT(*) FROM employee e WHERE e.dept_id = OLD.dept_id) > 0 THEN + SIGNAL SQLSTATE '45000' + SET MESSAGE_TEXT = '该部门有员工无法删除'; + END IF; +END $$ +DELIMITER ; + +DELETE FROM department +WHERE dept_id = 1; +``` + + + #### 练习题 9: 自动更新职位工资范围 创建一个触发器 `after_job_update`,在更新 `job` 表的 `min_salary` 或 `max_salary` 字段后,自动调整 `employee` 表中相关员工的工资,使其符合新的工资范围。 +```sql +DELIMITER $$ +DROP TRIGGER IF EXISTS after_job_update; +CREATE TRIGGER after_job_update +AFTER UPDATE ON job +FOR EACH ROW +BEGIN + UPDATE employee + SET salary = IF(salary > NEW.max_salary, NEW.max_salary, IF(salary < NEW.min_salary, min_salary, salary)) + WHERE job_id = NEW.job_id; +END $$ +DELIMITER ; +``` + + + #### 练习题 10: 记录部门变更 创建一个触发器 `after_employee_update`,在更新 `employee` 表的 `dept_id` 字段后,将变更记录插入到一个新的日志表 `department_change_log` 中,记录员工 ID、旧部门 ID、新部门 ID 和变更时间。 +```sql +CREATE TABLE department_change_log( + emp_id INT, + old_dept_id INT, + new_dept_id INT, + update_date DATE +); + +DELIMITER $$ +DROP TRIGGER IF EXISTS after_employee_update; +CREATE TRIGGER after_employee_update +AFTER UPDATE ON employee +FOR EACH ROW +BEGIN + IF NEW.dept_id <> OLD.dept_id THEN + INSERT INTO department_change_log() + VALUES(NEW.emp_id, OLD.dept_id, NEW.dept_id, NOW()); + END IF; +END $$ +DELIMITER ; +``` + + + #### 练习题 11: 防止插入重复职位 创建一个触发器 `before_job_insert`,在插入 `job` 表数据之前,检查职位名称是否已存在。如果存在,阻止插入并抛出错误。 +```sql +DELIMITER $$ +DROP TRIGGER IF EXISTS before_job_insert; +CREATE TRIGGER before_job_insert +BEFORE INSERT ON job +FOR EACH ROW +BEGIN + IF (SELECT COUNT(*) FROM job WHERE job_id = NEW.job_id) = 1 THEN + SIGNAL SQLSTATE '45000' + SET MESSAGE_TEXT = '职位名称已存在'; + END IF; +END $$ +DELIMITER ; +``` + + + #### 练习题 12: 自动更新员工总数 创建一个触发器 `after_employee_insert`,在插入 `employee` 表数据之后,自动更新一个统计表 `employee_statistics` 中的员工总数。 +```sql +CREATE TABLE employee_statistics( + marking VARCHAR(20), + num INT +); +INSERT INTO employee_statistics() +VALUES('count', 0); + +DELIMITER $$ +DROP TRIGGER IF EXISTS after_employee_insert; +CREATE TRIGGER after_employee_insert +AFTER INSERT ON employee +FOR EACH ROW +BEGIN + UPDATE employee_statistics + SET num = (SELECT COUNT(*) FROM employee) + WHERE marking = 'count'; +END $$ +DELIMITER ; +``` + + + #### 练习题 13: 防止修改部门所在地 创建一个触发器 `before_department_update`,在更新 `department` 表数据时,防止修改 `location` 字段。如果尝试修改,抛出错误。 +```sql +DELIMITER $$ +DROP TRIGGER IF EXISTS before_department_update; +CREATE TRIGGER before_department_update +BEFORE UPDATE ON department +FOR EACH ROW +BEGIN + IF NEW.location <> OLD.location THEN + SIGNAL SQLSTATE '45000' + SET MESSAGE_TEXT = '无法更新部分的位置'; + END IF; +END $$ +DELIMITER ; +``` + + + #### 练习题 14: 自动调整工资 创建一个触发器 `before_employee_insert`,在插入 `employee` 表数据时,如果工资低于职位的最低工资,则自动将其调整为最低工资。 +```sql +DELIMITER $$ +DROP TRIGGER IF EXISTS before_employee_insert; +CREATE TRIGGER before_employee_insert +BEFORE INSERT ON employee +FOR EACH ROW +BEGIN + IF NEW.salary < (SELECT min_salary FROM job WHERE job_id = NEW.job_id ) THEN + SET NEW.salary = min_salary; + END IF; +END $$ +DELIMITER ; +``` + + + #### 练习题 15: 记录职位变更 创建一个触发器 `after_employee_update`,在更新 `employee` 表的 `job_id` 字段后,将变更记录插入到一个新的日志表 `job_change_log` 中,记录员工 ID、旧职位 ID、新职位 ID 和变更时间。 +```sql +CREATE TABLE job_change_log( + emp_id INT, + old_job_id INT, + new_job_id INT, + update_date DATE +); +DELIMITER $$ +DROP TRIGGER IF EXISTS after_employee_update; +CREATE TRIGGER after_employee_update +AFTER UPDATE ON employee +FOR EACH ROW +BEGIN + IF NEW.job_id <> OLD.job_id THEN + INSERT INTO job_change_log() + VALUES(NEW.emp_id, OLD.job_id, NEW.job_id, NOW()); + END IF; +END $$ +DELIMITER ; +``` + + + #### 练习题 16: 防止删除职位 创建一个触发器 `before_job_delete`,在删除 `job` 表数据之前,检查该职位是否还有员工。如果有员工,阻止删除并抛出错误。 +```sql +DELIMITER $$ +DROP TRIGGER IF EXISTS before_job_delete; +CREATE TRIGGER before_job_delete +BEFORE DELETE ON job +FOR EACH ROW +BEGIN + IF (SELECT COUNT(*) FROM employee WHERE job_id = OLD.job_id) > 0 THEN + SIGNAL SQLSTATE '45000' + SET MESSAGE_TEXT = '该职位还有员工'; + END IF; +END $$ +DELIMITER ; +``` + + + #### 练习题 17: 自动更新部门平均工资 创建一个触发器 `after_employee_insert`,在插入 `employee` 表数据之后,自动更新 `department` 表中的部门平均工资(假设 `department` 表新增一个字段 `avg_salary`)。 +```sql +DELIMITER $$ +DROP TRIGGER IF EXISTS after_employee_insert; +CREATE TRIGGER after_employee_insert +AFTER INSERT ON employee +FOR EACH ROW +BEGIN + UPDATE department d + SET d.avg_salary = (SELECT AVG(e.salary) FROM employee e WHERE d.dept_id = e.dept_id) + WHERE NEW.dept_id = d.dept_id; + +END $$ +DELIMITER ; +``` + + + #### 练习题 18: 防止插入未来入职日期 创建一个触发器 `before_employee_insert`,在插入 `employee` 表数据时,检查 `hire_date` 是否晚于当前日期。如果是,阻止插入并抛出错误。 +```sql +DELIMITER $$ +DROP TRIGGER IF EXISTS before_employee_insert; +CREATE TRIGGER before_employee_insert +BEFORE INSERT ON employee +FOR EACH ROW +BEGIN + IF NEW.hire_date < CURDATE() THEN + SIGNAL SQLSTATE '45000' + SET MESSAGE_TEXT = '入职日期不得晚于当前日期'; + END IF; + +END $$ +DELIMITER ; +``` + + + #### 练习题 19: 自动生成员工编号 创建一个触发器 `before_employee_insert`,在插入 `employee` 表数据时,自动生成一个唯一的员工编号(格式为 `EMP-年份-序号`,例如 `EMP-2023-001`),并将其存储到一个新字段 `emp_code` 中。 +```sql +ALTER TABLE employee ADD emp_code VARCHAR(30); + +DELIMITER $$ +DROP TRIGGER IF EXISTS before_employee_insert; +CREATE TRIGGER before_employee_insert +BEFORE INSERT ON employee +FOR EACH ROW +BEGIN + SET NEW.emp_code = CONCAT('EMP-',YEAR(NOW()),'-', (LAST_INSERT_ID()+1)); +END $$ +DELIMITER ; +INSERT INTO employee +VALUES(DEFAULT, '雷昊', 0, NOW(), 1, 1, NULL, NULL); +``` + + + #### 练习题 20: 记录员工离职 -创建一个触发器 `after_employee_delete`,在删除 `employee` 表数据之后,将被删除的员工信息插入到一个离职记录表 `employee_exit_log` 中,记录员工 ID、姓名、离职时间和原因(假设原因由用户输入)。 \ No newline at end of file +创建一个触发器 `after_employee_delete`,在删除 `employee` 表数据之后,将被删除的员工信息插入到一个离职记录表 `employee_exit_log` 中,记录员工 ID、姓名、离职时间和原因(假设原因由用户输入)。 + +```sql +CREATE TABLE employee_exit_log( + emp_id INT, + emp_name VARCHAR(20), + quit_date DATE, + quit_reason VARCHAR(50) +); + +DELIMITER $$ +DROP TRIGGER IF EXISTS after_employee_delete; +CREATE TRIGGER after_employee_delete +AFTER DELETE ON employee +FOR EACH ROW +BEGIN + INSERT INTO employee_exit_log() + VALUES(OLD.emp_id, OLD.emp_name, NOW(), NULL); +END $$ +DELIMITER ; +``` +