说明:本章主要使用baidu comate 的AI软件来完成
1.创建表
问题1:帮我创建2个表student与score表,要求student表有id,createDate,userName,phone,age,sex,introduce,
要求score表有id,scoreName,result,studentId(student表的id外键)。
要求student表中插入5条学生信息,都要是中文的。
要求score表中对应studentId插入10条信息,每个学生ID要有2个科目的成绩。
给出DDL与DML语句。
AI:下面是DDL(数据定义语言)用于创建student
和score
表,以及DML(数据操作语言)用于插入数据的SQL语句。
DDL语句:
sql
-- 创建student表
CREATE TABLE student (
id INT PRIMARY KEY AUTO_INCREMENT,
createDate DATE NOT NULL,
userName VARCHAR(50) NOT NULL,
phone VARCHAR(20) NOT NULL,
age INT NOT NULL,
sex VARCHAR(10) NOT NULL,
introduce TEXT
);
-- 创建score表,其中studentId是student表的外键
CREATE TABLE score (
id INT PRIMARY KEY AUTO_INCREMENT,
scoreName VARCHAR(50) NOT NULL,
result DECIMAL(5,2) NOT NULL,
studentId INT,
FOREIGN KEY (studentId) REFERENCES student(id) ON DELETE CASCADE ON UPDATE CASCADE
);
DML语句:
首先,插入5条学生信息到student
表中:
sql
-- 插入5条学生信息
INSERT INTO student (createDate, userName, phone, age, sex, introduce) VALUES
('2023-01-01', '张三', '13800138000', 20, '男', '来自北京,喜欢数学。'),
('2023-02-02', '李四', '13900139000', 21, '女', '来自上海,擅长英语。'),
('2023-03-03', '王五', '13700137000', 22, '男', '来自深圳,喜欢编程。'),
('2023-04-04', '赵六', '13600136000', 19, '女', '来自成都,爱好音乐。'),
('2023-05-05', '孙七', '13500135000', 20, '男', '来自武汉,擅长物理。');
然后,根据student
表中的id
,向score
表中插入对应的成绩信息,每个学生两个科目:
sql
-- 假设已经插入的学生信息中id分别为1, 2, 3, 4, 5
-- 插入成绩信息,每个学生两条记录
INSERT INTO score (scoreName, result, studentId) VALUES
('数学', 90.50, 1),
('英语', 85.25, 1),
('语文', 88.75, 2),
('物理', 92.00, 2),
('化学', 78.50, 3),
('生物', 82.25, 3),
('历史', 95.00, 4),
('地理', 89.75, 4),
('政治', 76.50, 5),
('体育', 87.00, 5);
注意:
-
上述DML语句中插入的
id
值是根据假设的,实际操作中你需要根据student
表实际插入数据后自增生成的id
来填写对应的studentId
。 -
result
字段是成绩,这里使用了DECIMAL(5,2)
类型来存储,确保可以保存小数且保留两位小数。 -
createDate
字段使用的是DATE
类型,实际插入时需要按照YYYY-MM-DD
的格式提供日期值。 -
introduce
字段是文本类型,可以存储较长的介绍信息。 -
外键约束使用了
ON DELETE CASCADE ON UPDATE CASCADE
,这表示当student
表中的id
被删除或更新时,score
表中对应的记录也会被级联删除或更新。这有助于保持数据的一致性。
请根据你的数据库环境和实际情况调整上述SQL语句。
2.插入数据
问题2:帮我根据两个DDL创建一个插入信息的存储过程,使用循环先插入10条学生表信息,再根据插入的学生表信息插入100条对应studentId的score成绩, 所有信息随机生成,学生表的自增序号从6开始。不允许使用DECLARE,使用set类声明变量。
AI:根据您的要求,以下是使用SET
来声明变量,并使用循环插入学生信息和成绩的存储过程。请注意,MySQL的存储过程不支持直接使用SET
来声明循环变量,但可以使用SET
来更新变量的值。对于循环,我们将使用REPEAT ... UNTIL
结构。
sql
DELIMITER //
CREATE PROCEDURE InsertStudentsAndScores()
BEGIN
-- 设置student表的自增起始值为6
ALTER TABLE student AUTO_INCREMENT = 6;
-- 初始化变量
SET @counter = 0;
SET @lastStudentId = 0;
-- 插入10条随机学生信息
REPEAT
SET @counter = @counter + 1;
INSERT INTO student (createDate, userName, phone, age, sex, introduce)
VALUES (
CURDATE() - INTERVAL FLOOR(RAND() * 365) DAY, -- 随机日期
CONCAT('Student', FLOOR(RAND() * 1000000)), -- 随机用户名
CONCAT('1', LPAD(FLOOR(RAND() * 900000000), 9, '0')), -- 随机电话号码
FLOOR(RAND() * 100) + 1, -- 随机年龄(1-100)
CASE FLOOR(RAND() * 2) WHEN 0 THEN 'Male' ELSE 'Female' END, -- 随机性别
CONCAT('This is a random introduction for student ', CONCAT('Student', FLOOR(RAND() * 1000000)), '.') -- 随机介绍
);
-- 获取最后插入的学生ID
SELECT LAST_INSERT_ID() INTO @lastStudentId;
UNTIL @counter >= 10 END REPEAT;
-- 初始化变量,准备插入成绩
SET @counter = 0;
-- 插入100条随机成绩信息
REPEAT
SET @counter = @counter + 1;
-- 随机选择一个已存在的学生ID
SET @studentId = FLOOR(@lastStudentId * RAND()) + 6;
IF @studentId > @lastStudentId THEN
SET @studentId = @lastStudentId; -- 如果随机生成的ID超出了范围,则取最大值
END IF;
INSERT INTO score (scoreName, result, studentId)
VALUES (
CONCAT('Score', FLOOR(RAND() * 1000)), -- 随机成绩名称
ROUND(RAND() * 100, 2), -- 随机成绩,范围0-100
@studentId -- 随机选择的学生ID
);
UNTIL @counter >= 100 END REPEAT;
END //
DELIMITER ;
-- 调用存储过程
CALL InsertStudentsAndScores();
在这个存储过程中,我们首先使用ALTER TABLE
语句设置student
表的自增起始值为6。
接着,使用REPEAT ... UNTIL
循环结构来插入10条随机学生信息。在每次循环中,我们更新@counter
变量来追踪循环的次数,并使用INSERT INTO
语句插入一条随机的学生记录。使用LAST_INSERT_ID()
函数获取最后插入的学生ID,并将其保存在@lastStudentId
变量中。
然后,我们再次使用REPEAT ... UNTIL
循环来插入100条随机成绩信息。在每次循环中,我们随机选择一个已存在的学生ID,并插入一条随机的成绩记录。
最后,通过调用CALL InsertStudentsAndScores();
来执行这个存储过程。
请注意,这里的随机电话号码生成逻辑可能不符合实际的电话号码格式要求,您可能需要根据实际情况调整生成电话号码的逻辑。此外,由于随机性,有可能出现同一个学生被关联多条成绩记录的情况,这符合您的要求,但可能不符合某些实际场景。如果需要每个学生恰好有10条成绩记录,那么您需要设计更复杂的逻辑来确保这一点。
3.实现多表联合查询
问题3:帮我创建一个多表联合查询以student为主表,查看学生的所有科目成绩总分。
AI:要创建一个多表联合查询,以student
表为主表,查看学生的所有科目成绩总分,你可以使用SQL的JOIN
语句配合GROUP BY
和SUM
函数来实现。以下是一个示例查询:
sql
SELECT
s.id AS student_id,
s.userName AS student_name,
SUM(sc.result) AS total_score
FROM
student s
JOIN
score sc ON s.id = sc.studentId
GROUP BY
s.id, s.userName;
这个查询做了以下几件事情:
-
使用
JOIN
语句将student
表和score
表连接起来,通过studentId
字段进行匹配。 -
使用
SELECT
语句选择需要显示的字段,包括学生的ID、姓名和总分。这里使用别名(如student_id
和student_name
)使结果更清晰。 -
使用
SUM(sc.result)
计算每个学生的所有科目成绩总分。 -
使用
GROUP BY
语句按学生的ID和姓名对结果进行分组,这样每个学生的总分只会出现一次。
请注意,这个查询假设每个学生可能有多个成绩记录(即score
表中可能有多行与同一个studentId
相关联)。如果score
表中每个学生只有一个成绩记录,那么这个查询仍然有效,但SUM
函数在这种情况下其实是多余的,因为它只是对单个值进行求和。
另外,这个查询没有处理没有成绩记录的学生的情况。如果你想要包括那些没有成绩记录的学生,并显示他们的总分为0,你需要使用LEFT JOIN
而不是JOIN
。这样,即使score
表中没有与某个学生ID匹配的记录,该学生仍然会出现在结果集中,但总分将为0。
4.触发器的使用
问题4:帮我创建一个修改score表scoreName的触发器,当修改scoreName的时候触发,判断修改的scoreName是否是数学,如果是数学就改成(天书)。
并且给出测试示例。
AI:要创建一个触发器,当score
表中的scoreName
字段被修改时,检查新值是否为"数学",如果是,则将其改为"天书",你可以按照以下步骤进行:
首先,创建触发器:
sql
DELIMITER //
CREATE TRIGGER trg_update_scoreName_to_tianshu
BEFORE UPDATE ON score
FOR EACH ROW
BEGIN
IF NEW.scoreName = '数学' THEN
SET NEW.scoreName = '天书';
END IF;
END;
//
DELIMITER ;
这个触发器使用了BEFORE UPDATE
事件,意味着在score
表的行被更新之前,触发器会执行其内部的逻辑。如果NEW.scoreName
(代表将要被设置的新值)等于"数学",则将其更改为"天书"。
接下来,测试触发器:
首先,插入一些示例数据到score
表中:
sql
INSERT INTO score (scoreName, result, studentId) VALUES ('数学', 90.50, 1);
INSERT INTO score (scoreName, result, studentId) VALUES ('英语', 85.25, 1);
INSERT INTO score (scoreName, result, studentId) VALUES ('物理', 78.75, 2);
现在,尝试更新scoreName
为"数学"的记录,并查看是否触发器正常工作:
sql
UPDATE score SET scoreName = '数学' WHERE id = 1; -- 假设id为1的记录原本scoreName就是'数学'
执行上述UPDATE
语句后,由于触发器的作用,scoreName
字段的值不会变成"数学",而是会变成"天书"。
为了验证结果,可以查询score
表:
sql
SELECT * FROM score;
你应该能看到id为1的记录的scoreName
字段现在是"天书",而不是"数学"。
请注意,如果scoreName
字段的值原本就不是"数学",则触发器不会有任何效果,scoreName
字段的值将按照UPDATE
语句中指定的新值进行更新。
还要确保在创建触发器之前,score
表中没有名为trg_update_scoreName_to_tianshu
的触发器存在,否则你会得到一个错误,因为MySQL不允许重名的触发器。如果之前已经创建了同名的触发器,你需要先删除它,可以使用以下命令:
sql
DROP TRIGGER IF EXISTS trg_update_scoreName_to_tianshu;
然后再创建新的触发器。
5.游标的使用
问题5:创建一个两个表的综合【游标查询】,要求根据学生姓名进行查询,查询的结果返回两个表的综合信息。
AI:为了创建一个综合两个表的游标查询,并根据学生姓名来检索信息,我们可以使用存储过程结合游标来实现。在这个例子中,我们假设你希望查询学生的信息以及他们所有的成绩(不包含成绩表的id)。
首先,我们需要编写一个存储过程,该过程将接收学生姓名作为参数,并使用游标来遍历查询结果。以下是一个可能的实现:
sql
DELIMITER //
CREATE PROCEDURE GetStudentInfoAndScores(IN p_userName VARCHAR(50))
BEGIN
-- 声明变量来存储查询结果
DECLARE done INT DEFAULT FALSE;
DECLARE v_id INT;
DECLARE v_createDate DATE;
DECLARE v_userName VARCHAR(50);
DECLARE v_phone VARCHAR(20);
DECLARE v_age INT;
DECLARE v_sex VARCHAR(10);
DECLARE v_introduce TEXT;
DECLARE v_scoreName VARCHAR(50);
DECLARE v_result DECIMAL(5,2);
-- 声明游标
DECLARE cur CURSOR FOR
SELECT
s.id, s.createDate, s.userName, s.phone, s.age, s.sex, s.introduce,
sc.scoreName, sc.result
FROM student s
JOIN score sc ON s.id = sc.studentId
WHERE s.userName = p_userName;
-- 声明NOT FOUND处理程序
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
-- 打开游标
OPEN cur;
-- 读取游标中的数据
read_loop: LOOP
FETCH cur INTO v_id, v_createDate, v_userName, v_phone, v_age, v_sex, v_introduce, v_scoreName, v_result;
IF done THEN
LEAVE read_loop;
END IF;
-- 这里你可以对变量进行进一步的处理,比如打印或返回给调用者
SELECT
v_id AS student_id,
v_createDate AS create_date,
v_userName AS student_name,
v_phone AS phone,
v_age AS age,
v_sex AS sex,
v_introduce AS introduction,
v_scoreName AS score_name,
v_result AS result;
END LOOP;
-- 关闭游标
CLOSE cur;
END //
DELIMITER ;
现在,我们有了这个存储过程GetStudentInfoAndScores
,它接受一个学生姓名作为参数,并返回该学生的所有信息以及他们的成绩。请注意,由于一个学生可能有多个成绩,因此每个学生的信息将会被重复打印,每次打印都附带一个不同的成绩。
要调用这个存储过程并获取结果,你可以这样做:
sql
CALL GetStudentInfoAndScores('目标学生姓名');
请替换'目标学生姓名'
为你想要查询的学生的实际姓名。调用存储过程后,你将看到该学生的所有信息以及他们所有的成绩。
注意:这个实现假设每个学生至少有一个成绩记录。如果没有成绩记录,这个学生将不会出现在结果中。如果你希望即使学生没有成绩也显示他们的信息(例如,显示成绩为NULL或空字符串),你应该使用LEFT JOIN
而不是JOIN
。