DDL
CREATE TABLE Users (
user_id INT AUTO_INCREMENT PRIMARY KEY COMMENT '用户ID',
username VARCHAR(50) NOT NULL UNIQUE COMMENT '用户名',
password VARCHAR(255) NOT NULL COMMENT '密码',
gender ENUM('男', '女') NOT NULL COMMENT '性别',
email VARCHAR(100) UNIQUE COMMENT '邮箱'
);
CREATE TABLE Roles (
role_id INT AUTO_INCREMENT PRIMARY KEY COMMENT '角色ID',
role_name VARCHAR(50) NOT NULL UNIQUE COMMENT '角色名称'
);
CREATE TABLE UserRoles (
user_id INT COMMENT '用户ID',
role_id INT COMMENT '角色ID',
PRIMARY KEY (user_id, role_id),
FOREIGN KEY (user_id) REFERENCES Users(user_id),
FOREIGN KEY (role_id) REFERENCES Roles(role_id)
);
CREATE TABLE Projects (
project_id INT AUTO_INCREMENT PRIMARY KEY COMMENT '项目ID',
project_name VARCHAR(100) NOT NULL COMMENT '项目名称',
project_description TEXT COMMENT '项目描述',
principal_investigator_id INT COMMENT '主研人ID',
start_date DATE NOT NULL COMMENT '开始日期',
end_date DATE NOT NULL COMMENT '结束日期',
status ENUM('申请中', '审批中', '执行中', '结题') NOT NULL COMMENT '项目状态',
FOREIGN KEY (principal_investigator_id) REFERENCES Users(user_id)
);
CREATE TABLE Funds (
fund_id INT AUTO_INCREMENT PRIMARY KEY COMMENT '资金ID',
project_id INT NOT NULL COMMENT '项目ID',
source VARCHAR(100) NOT NULL COMMENT '资金来源',
amount DECIMAL(10, 2) NOT NULL COMMENT '资金金额',
FOREIGN KEY (project_id) REFERENCES Projects(project_id)
);
CREATE TABLE Achievements (
achievement_id INT AUTO_INCREMENT PRIMARY KEY COMMENT '成果ID',
project_id INT NOT NULL COMMENT '项目ID',
achievement_name VARCHAR(100) NOT NULL COMMENT '成果名称',
achievement_type ENUM('论文', '专利', '获奖', '其他') NOT NULL COMMENT '成果类型',
description TEXT COMMENT '成果描述',
FOREIGN KEY (project_id) REFERENCES Projects(project_id)
);
CREATE TABLE ProjectLogs (
log_id INT AUTO_INCREMENT PRIMARY KEY COMMENT '日志ID',
project_id INT NOT NULL COMMENT '项目ID',
user_id INT NOT NULL COMMENT '用户ID',
log_date DATETIME NOT NULL COMMENT '日志日期',
log_content TEXT NOT NULL COMMENT '日志内容',
FOREIGN KEY (project_id) REFERENCES Projects(project_id),
FOREIGN KEY (user_id) REFERENCES Users(user_id)
);
DML
INSERT INTO Roles (role_name) VALUES
('管理员'),
('项目负责人'),
('项目成员');
INSERT INTO Users (username, password, gender, email) VALUES
('诸葛亮', '123', '男', 'zhugeliang@example.com'),
('孙悟空', '123', '男', 'sunwukong@example.com'),
('林黛玉', '123', '女', 'lindaiyu@example.com');
INSERT INTO UserRoles (user_id, role_id) VALUES
(1, 1), -- 诸葛亮是管理员
(2, 2), -- 孙悟空是项目负责人
(2, 3), -- 孙悟空也是项目成员
(3, 3); -- 林黛玉是项目成员
INSERT INTO Projects (project_name, project_description, principal_investigator_id, start_date, end_date, status) VALUES
('三国历史研究项目', '研究三国历史背景', 1, '2023-01-01', '2023-12-31', '执行中'),
('西游记文化研究', '探究西游记的文学价值', 2, '2023-02-01', '2024-01-31', '申请中'),
('红楼梦解读', '分析红楼梦的深层含义', 2, '2023-03-01', '2023-11-30', '审批中');
INSERT INTO Funds (project_id, source, amount) VALUES
(1, '国家社会科学基金', 50000.00),
(2, '企业赞助', 30000.00),
(3, '学校科研基金', 45000.00),
(1, '地方政府资助', 20000.00); -- 同一个项目可以有多个经费来源
INSERT INTO Achievements (project_id, achievement_name, achievement_type, description) VALUES
(1, '三国历史研究报告', '论文', '详细分析了三国时期的历史事件'),
(2, '西游记文化解读', '论文', '深入探讨了西游记的文化内涵'),
(3, '红楼梦人物分析', '论文', '对红楼梦中的主要人物进行了深入剖析'),
(2, '西游记新发现', '专利', '发现了西游记中的新文学元素'); -- 同一个项目可以有多个成果
INSERT INTO ProjectLogs (project_id, user_id, log_date, log_content) VALUES
(1, 1, '2023-01-10 10:00:00', '项目启动会议召开'),
(2, 2, '2023-02-15 15:30:00', '提交项目申请书至学院'),
(3, 3, '2023-03-20 09:45:00', '开始收集红楼梦相关资料'),
(1, 1, '2023-04-01 14:15:00', '第一阶段研究成果汇报');
ER图
ER图
模型图
简单查询
一、查询用户信息,仅显示用户的姓名与项目名称,用中文显示列名
SELECT DISTINCT
u.username AS 用户名,
p.project_name AS 项目名称
FROM
Users u
JOIN
Projects p ON u.user_id = p.principal_investigator_id;
二、根据项目名称进行模糊查询,模糊查询要进行索引,需要给出explain语句
EXPLAIN SELECT project_id, project_name
FROM Projects
WHERE project_name LIKE '%三国%';
三、统计用户的项目信息,查询所有用户的项目数量,并进行倒序排列
SELECT
u.username AS 用户名,
COUNT(p.project_id) AS 项目数量
FROM
Users u
LEFT JOIN
Projects p ON u.user_id = p.principal_investigator_id
GROUP BY
u.user_id, u.username
ORDER BY
项目数量 DESC;
复杂查询
一、查询用户的基本信息,项目信息
SELECT
u.user_id,
u.username,
u.gender,
u.email,
p.project_id,
p.project_name,
p.project_description,
p.start_date,
p.end_date,
p.status
FROM
Users u
LEFT JOIN
Projects p ON u.user_id = p.principal_investigator_id;
二、查看项目中项目阶段最多的项目对应的类型
SELECT
p.project_name,
p.status
FROM
Projects p
WHERE
(SELECT COUNT(*)
FROM Projects p2
WHERE p2.status = p.status) =
(SELECT MAX(cnt)
FROM (SELECT status, COUNT(*) as cnt
FROM Projects
GROUP BY status) as subquery);
三、查询项目最多的用户,并且查询用户的全部信息与当前项目阶段
SET @MostProjectsUserId = (
SELECT principal_investigator_id
FROM Projects
GROUP BY principal_investigator_id
ORDER BY COUNT(*) DESC
LIMIT 1
);
SELECT
u.*,
p.project_id,
p.project_name,
p.status AS current_project_status
FROM
Users u
JOIN
Projects p ON u.user_id = p.principal_investigator_id
WHERE
u.user_id = @MostProjectsUserId;
触发器
触发器一:项目状态更新时记录日志
DELIMITER $$
CREATE TRIGGER trg_after_project_status_update
AFTER UPDATE ON Projects
FOR EACH ROW
BEGIN
IF NEW.status <> OLD.status THEN
INSERT INTO ProjectLogs (project_id, user_id, log_date, log_content)
VALUES (NEW.project_id, @CURRENT_USER_ID, NOW(), '项目状态已更新');
END IF;
END;
$$
DELIMITER ;
触发器二:用户角色变更时记录日志
DELIMITER $$
CREATE TRIGGER trg_after_fund_insert
AFTER INSERT ON Funds
FOR EACH ROW
BEGIN
INSERT INTO ProjectLogs (project_id, user_id, log_date, log_content)
VALUES (NEW.project_id, @CURRENT_USER_ID, NOW(), CONCAT('项目获得资金:', NEW.source, ',金额为:', NEW.amount));
END;
$$
DELIMITER ;
触发器三:用户角色变更时记录日志
CREATE TABLE UserRoleLogs (
log_id INT AUTO_INCREMENT PRIMARY KEY COMMENT '日志ID',
user_id INT NOT NULL COMMENT '用户ID',
old_role_id INT COMMENT '旧角色ID',
new_role_id INT COMMENT '新角色ID',
log_date DATETIME NOT NULL COMMENT '日志日期',
log_content TEXT COMMENT '日志内容',
FOREIGN KEY (user_id) REFERENCES Users(user_id),
FOREIGN KEY (old_role_id) REFERENCES Roles(role_id),
FOREIGN KEY (new_role_id) REFERENCES Roles(role_id)
);
DELIMITER $$
CREATE TRIGGER trg_after_user_role_change
AFTER INSERT ON UserRoles
FOR EACH ROW
BEGIN
DECLARE old_role_name VARCHAR(50);
DECLARE new_role_name VARCHAR(50);
SELECT role_name INTO new_role_name FROM Roles WHERE role_id = NEW.role_id;
IF new_role_name IS NOT NULL THEN
INSERT INTO UserRoleLogs (user_id, new_role_id, log_date, log_content)
VALUES (NEW.user_id, NEW.role_id, NOW(), CONCAT('用户', NEW.user_id, '被赋予了新角色:', new_role_name));
END IF;
END;
$$
DELIMITER ;
存储过程
存储过程 1: 分配用户角色
DELIMITER $$
CREATE PROCEDURE AssignUserRole(IN userId INT, IN roleName VARCHAR(50))
BEGIN
DECLARE roleId INT;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET @errorMsg = 'Role not found.';
SELECT role_id INTO roleId FROM Roles WHERE role_name = roleName;
IF roleId IS NULL THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = @errorMsg;
END IF;
IF NOT EXISTS (SELECT 1 FROM UserRoles WHERE user_id = userId AND role_id = roleId) THEN
INSERT INTO UserRoles (user_id, role_id) VALUES (userId, roleId);
END IF;
SELECT 'Role assigned successfully.' AS message;
END $$
DELIMITER ;
存储过程 2: 更新项目状态并记录日志
DELIMITER $$
CREATE PROCEDURE UpdateProjectStatus(IN projectId INT, IN newStatus ENUM('申请中', '审批中', '执行中', '结题'))
BEGIN
DECLARE OLD_STATUS ENUM('申请中', '审批中', '执行中', '结题');
SELECT status INTO OLD_STATUS FROM Projects WHERE project_id = projectId;
UPDATE Projects SET status = newStatus WHERE project_id = projectId;
INSERT INTO ProjectLogs (project_id, user_id, log_date, log_content)
VALUES (projectId, USER(), NOW(), CONCAT('Project status changed from ', OLD_STATUS, ' to ', newStatus));
SELECT 'Project status updated successfully.' AS message;
END $$
DELIMITER ;
存储过程 3: 分配项目资金并检查预算
ALTER TABLE Projects ADD total_budget DECIMAL(10, 2) NOT NULL DEFAULT 0 COMMENT '项目总预算';
DELIMITER $$
CREATE PROCEDURE AllocateProjectFunds(
IN p_project_id INT,
IN p_source VARCHAR(100),
IN p_amount DECIMAL(10, 2)
)
BEGIN
DECLARE v_total_budget DECIMAL(10, 2);
DECLARE v_allocated_funds DECIMAL(10, 2);
SELECT total_budget INTO v_total_budget FROM Projects WHERE project_id = p_project_id;
SELECT SUM(amount) INTO v_allocated_funds FROM Funds WHERE project_id = p_project_id;
IF v_total_budget >= (v_allocated_funds + p_amount) THEN
INSERT INTO Funds (project_id, source, amount) VALUES (p_project_id, p_source, p_amount);
INSERT INTO ProjectLogs (project_id, user_id, log_date, log_content)
VALUES (p_project_id, USER(), NOW(),CONCAT('资金已成功分配给项目', p_project_id, ',金额:', p_amount, ',来源:', p_source));
SELECT '资金分配成功' AS message;
ELSE
SELECT '预算不足,无法分配资金' AS message;
END IF;
END $$
DELIMITER ;