参考文档:https://dev.mysql.com/doc/refman/8.0/en/date-and-time-functions.html
数据类型
类型 | 具体类型 |
---|---|
整数类型 | BIT、BOOL、TINY INT、SMALL INT、MEDIUM INT、 INT、 BIG INT |
浮点数类型 | FLOAT、DOUBLE、DECIMAL |
字符串类型 | CHAR、VARCHAR、TINY TEXT、TEXT、MEDIUM TEXT、LONGTEXT、TINY BLOB、BLOB、MEDIUM BLOB、LONG BLOB |
日期类型 | Date、DateTime、TimeStamp、Time、Year |
其他数据类型 | BINARY、VARBINARY、ENUM、SET、Geometry、Point、MultiPoint、LineString、MultiLineString、Polygon、MultiPolygon、GeometryCollection,JSON |
1.整数类型
- tinyint(m):1个字节(-128~127)
- smallint(m):2个字节(-32768~32767)
- mediumint(m):3个字节(-8388608~8388607)
- int(m) :4个字节(-2147483648~2147483647)
- bigint(m):8个字节(-9223372036854775808~9223372036854775807)
取值范围如果加了unsigned,则最大值翻倍;m表示宽度,不足宽度的前面用0填充,需要配合ZEROFILL使用
2.浮点数类型
- float(m,d):单精度浮点型,8位精度(4字节) ,总个数m,小数点后d位
- double(m,d):双精度浮点型,16位精度(8字节),总个数m,小数点后d位
- decimal(m,d) :定点数,总个数m(0<=m<=65),小数点后d位(0<=m<=30),d<m
3.字符串类型
- char(m):固定长度,最多255个字符,m个字节
- varchar(m):可变长度,最多65535个字符,m+1个字节
- tinytext:可变长度,最多255个字符
- text:可变长度,最多65535个字符
- mediumtext:可变长度,最多2的24次方-1个字符
- longtext:可变长度,最多2的32次方-1个字符
- TINY BLOB:可变长度,最多255个字符
- BLOB:可变长度,最多65535个字符
- MEDIUM BLOB:可变长度,,最多2的24次方-1个字符
- LONG BLOB可变长度,,最多2的32次方-1个字符
- BINARY(m):固定长度,m个字节
- VARBINARY(m):可变长度,m+1个字节
1._TEXT以文本方式存储,英文存储区分大小写,而_Blob是以二进制方式存储,不分大小写
2._TEXT可以指定字符集
3.text的索引似乎不起作用
4.比指定类型支持的最大范围大的值将被自动截短
4.日期类型
- Date:YYYY-MM-DD格式
- DateTime:YYYY-MM-DD HH:MM:SS格式
- TimeStamp:YYYY-MM-DD格式,自动存储记录修改时间
- Time:HH:MM:SS格式
- Year:YYYY格式
5.其他数据类型
- ENUM:字符串枚举,enum(‘male’,‘female’,‘?’)
- SET:集合字符串,定义了集合之后,不能插入集合元素之外的字符串,set(‘string1’,‘string2’,‘string3’)
- Geometry:地理空间位置
- GeometryCollection:地理空间位置集合
- Point:坐标值
- MultiPoint:坐标集合
- LineString:线
- MultiLineString:线集合
- Polygon:多边形
- MultiPolygon:多边形集合
- JSON:JSON格式的存储
字符串
1.CONCAT(sl,s2,…)
直接拼接一个或者多个字符串
注意:若有任何一个参数为 NULL,则返回值为 NULL。
2.CONCAT_WS(separator,str1,str2,…)
分隔符拼接字符串,不会因为参数为NULL值而返回NULL ,但如果分隔符为 NULL,则结果为 NULL
3.group_concat
group_concat([DISTINCT] 要连接的字段 [Order BY ASC/DESC 排序字段] [Separator ‘分隔符’])
4.repeat()
复制字符串
5.REPLACE(str,from_str,to_str)
将所有str中所有出现的字符串from_str替换to_str,REPLACE()搜索时执行区分大小写的匹配。
SELECT REPLACE('aabbbaa', 'bb', '')
--> aabaa
column列
1.修改列
ALTER table settlement_port
CHANGE COLUMN `add_sub_item_data` `add_item_data` json DEFAULT NULL COMMENT '增项json';
alter table employee_family modify column is_main TINYINT DEFAULT 0 COMMENT '是否为紧急联系人';
2.添加列
ALTER table settlement_port
ADD COLUMN `sub_item_data` json DEFAULT NULL COMMENT '减项json' AFTER `add_item_data`;
3.列约束
-- 表中性别字段设置约束,数值为男或女。
ALTER table Swordsmen
add CONSTRAINT ck_sGender check(sGender='男' or sGender='女');
-- 为表添加外健。
ALTER TABLE MenKungfu
add CONSTRAINT fk_MenKungfu_sID_Swordsmen FOREIGN key(sID)
REFERENCES Swordsmen(sID);
-- 删除约束
ALTER table Swordsmen DROP CONSTRAINT ck_sGender;
时间
1.时间格式化
SELECT DATE_FORMAT(NOW(),'%Y-%m-%d');
--> 2022-03-15
SELECT DATE_FORMAT( '2022-09-15 09:33:45' , '%Y-%m-%d %H:%i:%S' );
-> 2022-09-15 09:33:45
2.时间差
SELECT DATEDIFF('2022-11-30 23:59:59','2022-12-31');
--> -31
3.返回星期索引,星期日:1,星期一:2 …
SELECT DAYOFWEEK('2022-03-23');
--> 4
条件控制
SELECT if(1>2,'true','false');
--> false
SELECT IFNULL(NULL,1);
--> 1
SELECT IFNULL(1,0);
-> 1
-- expr1 = expr2返回null,否则返回expr1
SELECT NULLIF(1,1);
-> NULL
SELECT NULLIF(1,2);
-> 1
SELECT
(CASE s_sex
WHEN '男' THEN 1
WHEN '女' THEN 0
ELSE '*'
END) 'sex'
FROM student
视图
作用:
1.简单,用户不需要指定条件
2.安全,视图可以授权
-- ④创建视图用于查询侠客所属门派,列出侠客姓名,门派名称以及入门派时间
CREATE VIEW view_xk as
SELECT sname,dName,dEnterDate
FROM Swordsmen s join Department d
on s.dID=d.dID;
-- 查看视图
desc view_xk;
-- 删除视图
drop view view_xk;
视图更新:
视图可更新,视图中的行与基础表中的行必须存在一对一的关系。如果视图包含下面任何一项则不可更新:
1.聚合函数或窗口函数
2.DISTINCT
3.GROUP BY
4.HAVING
5.UNION 或UNION ALL
变量
1.系统变量:是MySQL服务器提供,属于服务器层面,分为全局变量(GLOBAL)、会话变量(SESSION)
-- 查看所有系统变量
SHOW VARIABLES;
-- 模糊搜索所有系统变量
SHOW SESSION VARIABLES like '%auto%';
-- 查看所有会话系统变量
SHOW SESSION VARIABLES;
-- 查看所有全局系统变量
SHOW GLOBAL VARIABLES;
-- 查看所有全局系统变量的值
SELECT @@GLOBAL.autocommit;
-- 设置会话系统变量
SET SESSION autocommit=0
-- 设置全局系统变量,服务器重启会恢复原样,如果想永久设置,需要配置my.cnf文件
SET GLOBAL autocommit=1
2.用户变量:用户自定义的变量,用户变量不需要提前声明,只需要’@var’就可以使用,作用域为当前连接。
-- 定义用户变量两种方式,推荐':'
set @name = 'zhangsan' , @age := 10;
-- 将查询结果赋值给用户变量
SELECT COUNT(*) into @count FROM users;
-- 使用
SELECT @name,@age,@count;
3.局部变量:局部变量是在定义的局部生效,访问之前需要DECLARE声明。
delimiter //
CREATE PROCEDURE p1()
BEGIN
-- 声明局部变量
DECLARE user_count int DEFAULT 0;
-- 给局部变量赋值
set user_count =10;
-- 将查询结果给局部变量赋值
SELECT COUNT(*) into user_count FROM users;
SELECT user_count;
end //;
CALL p1();
DROP PROCEDURE p1;
将变量设为null就是删除,因为不存在的变量查询出来也是null
存储过程
作用:存储过程是事先经过编译在数据库中的一段sql语句,将多段sql封装到一个存储过程中,可以减少服务器与应用之间的传输次数。
-- ⑤创建存储过程,查询指定武功所使用的武器
delimiter //
CREATE PROCEDURE sp_kw(kn VARCHAR(15))
BEGIN
SELECT kWeapon
FROM kungfu
WHERE kName=kn;
END//
-- 调用存储过程
CALL sp_kw('打狗棍法');
-- 删除存储过程
DROP PROCEDURE sp_kw;
-- 查看jinyong2db这个数据库的存储过程
SELECT * FROM information_schema.ROUTINES WHERE ROUTINE_SCHEMA = 'jinyong2db';
-- 查看sp_kw这个存储过程的sql
SHOW CREATE PROCEDURE sp_kw;
-------------------------华丽分割线-------------------------------
-- IN 该参数作为入参
-- OUT 作为存储过程返回值
-- INOUT 既可以作为入参,也可以作为出参
-- 存储过程条件判断
delimiter //
CREATE PROCEDURE p_score(in score int ,out result VARCHAR(10))
BEGIN
IF score<60
THEN set result:='不及格';
ELSEIF score=60
THEN set result:='666';
ELSE set result:='优秀';
END IF;
end //
CALL p_score(60,@result);
SELECT @result;
DROP PROCEDURE p_score;
-------------------------华丽分割线-------------------------------
-- 换算
delimiter //
CREATE PROCEDURE p_convert(inout score DOUBLE)
BEGIN
SET score :=score/100;
end //
set @score=100;
CALL p_convert(@score);
SELECT @score;
-------------------------华丽分割线-------------------------------
-- while循环
delimiter //
CREATE PROCEDURE p_while(inout n DOUBLE)
BEGIN
WHILE n<100 DO
set n := n+1;
END WHILE;
end //
set @n=0;
CALL p_while(@n);
SELECT @n;
-------------------------华丽分割线-------------------------------
-- repeat循环,先执行一次,满足条件退出
delimiter //
CREATE PROCEDURE p_repeat(inout i DOUBLE)
BEGIN
REPEAT
set i := i+1;
UNTIL i=100
END REPEAT;
end //
set @i=0;
CALL p_repeat(@i);
SELECT @i;
-------------------------华丽分割线-------------------------------
-- loop循环,需要在sql逻辑中增加退出循环的条件,否则会死循环。
-- LEAVE :配合循环使用,退出循环
-- ITERATE :在循环体中,跳过当前循环
delimiter //
CREATE PROCEDURE p_loop(L DOUBLE)
BEGIN
DECLARE total int DEFAULT 0;
sum: LOOP
IF L=100 THEN
LEAVE sum;
END IF;
IF L%2=0 THEN
set L := L+1;
ITERATE sum;
END IF;
set L := L+1;
set total :=total+L;
END LOOP sum;
SELECT total;
end //
CALL p_loop(@L);
DROP PROCEDURE p_loop;
-------------------------华丽分割线-------------------------------
-- 条件处理程序(handler):可以定义在流程控制结构执行过程中遇到问题时相应处理步骤。
DECLARE handler_action HANDLER for [condition_value] statement;
handler_action
CONTINUE:继续执行当前程序
EXIT:终止执行当前程序
condition_value
SQLSTATE sqlstate_value:状态码,参考mysql官网
SQLWARNING:所有以01开头的SQLSTATE代码简写
NOT FOUND:所有以02开头的SQLSTATE代码简写
SQLEXCEPTION:所有没有被SQLWARNING或NOT FOUND捕捉的SQLSTATE代码简写
-------------------------华丽分割线-------------------------------
-- 游标:用来存储查询结果的数据集合
-- 声明游标:DECLARE 游标名称 CURSOR FOR 查询语句;
-- 打开游标:OPEN 游标名称;
-- 获取游标记录并赋值给变量:FETCH 游标名称 INTO [变量];
-- 关闭游标:CLOSE 游标名称;
delimiter //
CREATE PROCEDURE p_cursor(in Hot DOUBLE)
BEGIN
DECLARE c_name VARCHAR(100);
DECLARE c_addr VARCHAR(100);
DECLARE s_cursor CURSOR for SELECT sName,sAdd FROM songs WHERE sHot >= Hot;
DECLARE exit handler for SQLSTATE '02000' CLOSE s_cursor;
DROP table if EXISTS tb_songs;
CREATE TABLE if not EXISTS tb_songs(
`id` int PRIMARY key auto_increment,
`tb_name` VARCHAR(100),
`tb_addr` VARCHAR(100)
);
OPEN s_cursor;
WHILE true DO
FETCH s_cursor into c_name,c_addr;
INSERT into tb_songs(tb_name,tb_addr)VALUES(c_name,c_addr);
END WHILE;
CLOSE s_cursor;
end //
CALL p_cursor(10);
DROP PROCEDURE p_cursor;
存储函数
-- 存储函数,必须要有返回值
delimiter //
CREATE FUNCTION fsum(n int)
RETURNS int DETERMINISTIC
BEGIN
DECLARE total int DEFAULT 0;
WHILE n>0 DO
set total := total+n;
set n := n-1;
END WHILE;
RETURN total;
end //
SELECT fsum(100);
DROP FUNCTION if EXISTS fsum;
触发器
定义:触发器是在DML语句之前或之后,触发执行触发器中定义的SQL语句集合。
- insert型触发器:NEW表示将要或者已经新增的数据
- update型触发器:OLD表示修改之前的数据,NEW表示将要或者已经修改的数据
- delete型触发器:OLD表示将要或者已经删除的数据
创建:
delimiter //
CREATE TRIGGER trigger_name
BEFORE/AFTER INSERT/UPDATE/DELETE
ON tab_name FOR EACH ROW -- 行级触发器
BEGIN
trigger statement;
END; //
-------------------------华丽分割线-------------------------------
-- insert型触发器:users表中插入数据,通过触发器记录到user_logs表中
delimiter //
CREATE TRIGGER trigger_insert
AFTER INSERT on users FOR EACH ROW
BEGIN
INSERT into user_logs(operation,user_data,create_time)
VALUES ('insert',CONCAT('插入:',new.uid,new.uName),NOW());
END; //
-- 插入测试
INSERT into users(uName,uPwd,uGender,uBirthDate) VALUES ('大蛇','156323','男',NOW());
-- 查看所有触发器
SHOW TRIGGERS;
-- 删除触发器
DROP TRIGGER trigger_insert;
-------------------------华丽分割线-------------------------------
-- update型触发器:users表中更新数据,通过触发器记录到user_logs表中
delimiter //
CREATE TRIGGER trigger_update
AFTER UPDATE on users FOR EACH ROW
BEGIN
INSERT into user_logs(operation,user_data,create_time)
VALUES ('update',CONCAT('更新前:',old.uid,old.uName,'-更新后:',new.uid,new.uName) ,NOW());
END; //
-- 更新测试
update users set uName='火麟飞' WHERE uid=7;
-------------------------华丽分割线-------------------------------
-- delete型触发器:users表中删除数据,通过触发器记录到user_logs表中
delimiter //
CREATE TRIGGER trigger_delete
AFTER DELETE on users FOR EACH ROW
BEGIN
INSERT into user_logs(operation,user_data,create_time)
VALUES ('delete',CONCAT('删除数据:',old.uid,old.uName) ,NOW());
END; //
-- 删除测试
DELETE FROM users WHERE uid=5;
事务
-- 查看事务提交,on:自动 off:手动
SHOW VARIABLES LIKE 'autocommit';
--设置事务提交方式,1:自动 0:手动
set @@autocommit=0
-- 开启一个事务START transaction;或 BEGIN;
BEGIN;
UPDATE users SET uName='陆小果' WHERE uID=1
-- 事务提交commit; 事务回滚rollback;
commit;
JSON
1.查找指定键的所有值
{
"clientId": "31",
"agreementId": "12",
"settlementName": "大时代",
"taxRate": 0.25,
"serviceFeeType": "1",
"serviceFeeData": null,
"addItemData": [{
"name":"绩效",
"value":"10"
},{
"name":"哈哈哈",
"value":"100"
}],
"subItemData":[{
"name":"迟到",
"value":"12"
},
{
"name":"狡猾",
"value":"100"
}]
}
SELECT
sp.add_item_data->'$[*].name' as 'addItemData',
sp.sub_item_data->'$[*].name' as 'subItemData'
FROM settlement_port sp
笛卡尔积
笛卡尔积是多个集合的组合,会产生很多数据,但可以利用笛卡尔积巧妙解决很多问题
UPDATE
如果更新影响行数为0,要么没有查出数据,要么查出的数据和更新的数据是一样的。
mysql自带的四个数据库
information_schema
information_schema数据库记录了mysql的元数据。其他数据库的信息,如数据库名,数据库的表,表栏的数据类型与访问权限等。
TABLES表记录了mysql其他所有数据库的表
SELECT
TABLE_SCHEMA '库名',
TABLE_NAME '表名',
TABLE_COMMENT '表注释'
FROM
information_schema.`TABLES`
WHERE
TABLE_SCHEMA = 'nacos' AND TABLE_NAME = 'users';
查询该表的所有字段
SELECT
TABLE_SCHEMA '库名',
TABLE_NAME '表名',
COLUMN_NAME '列名',
COLUMN_KEY 'KEY',
DATA_TYPE '数据类型',
COLUMN_COMMENT '注释'
FROM
information_schema.`COLUMNS`
WHERE TABLE_SCHEMA = 'nacos' AND TABLE_NAME = 'users';
information_schema
主要用于收集数据库服务器性能参数。
mysql
主要负责存储数据库的用户、权限设置、关键字等。
sys
这个数据库有很多个函数和视图,存储了很多mysql的一些信息,如某个数据库用的的索引使用情况,耗时,用的什么引擎等等。
实战
--学生表
CREATE TABLE `Student`(
`s_id` VARCHAR(20),
`s_name` VARCHAR(20) NOT NULL DEFAULT '',
`s_birth` VARCHAR(20) NOT NULL DEFAULT '',
`s_sex` VARCHAR(10) NOT NULL DEFAULT '',
PRIMARY KEY(`s_id`)
);
--课程表
CREATE TABLE `Course`(
`c_id` VARCHAR(20),
`c_name` VARCHAR(20) NOT NULL DEFAULT '',
`t_id` VARCHAR(20) NOT NULL,
PRIMARY KEY(`c_id`)
);
--教师表
CREATE TABLE `Teacher`(
`t_id` VARCHAR(20),
`t_name` VARCHAR(20) NOT NULL DEFAULT '',
PRIMARY KEY(`t_id`)
);
--成绩表
CREATE TABLE `Score`(
`s_id` VARCHAR(20),
`c_id` VARCHAR(20),
`s_score` INT(3),
PRIMARY KEY(`s_id`,`c_id`)
);
--插入学生表测试数据
insert into Student values('01' , '赵雷' , '1990-01-01' , '男');
insert into Student values('02' , '钱电' , '1990-12-21' , '男');
insert into Student values('03' , '孙风' , '1990-05-20' , '男');
insert into Student values('04' , '李云' , '1990-08-06' , '男');
insert into Student values('05' , '周梅' , '1991-12-01' , '女');
insert into Student values('06' , '吴兰' , '1992-03-01' , '女');
insert into Student values('07' , '郑竹' , '1989-07-01' , '女');
insert into Student values('08' , '王菊' , '1990-01-20' , '女');
--课程表测试数据
insert into Course values('01' , '语文' , '02');
insert into Course values('02' , '数学' , '01');
insert into Course values('03' , '英语' , '03');
--教师表测试数据
insert into Teacher values('01' , '张三');
insert into Teacher values('02' , '李四');
insert into Teacher values('03' , '王五');
--成绩表测试数据
insert into Score values('01' , '01' , 80);
insert into Score values('01' , '02' , 90);
insert into Score values('01' , '03' , 99);
insert into Score values('02' , '01' , 70);
insert into Score values('02' , '02' , 60);
insert into Score values('02' , '03' , 80);
insert into Score values('03' , '01' , 80);
insert into Score values('03' , '02' , 80);
insert into Score values('03' , '03' , 80);
insert into Score values('04' , '01' , 50);
insert into Score values('04' , '02' , 30);
insert into Score values('04' , '03' , 20);
insert into Score values('05' , '01' , 76);
insert into Score values('05' , '02' , 87);
insert into Score values('06' , '01' , 31);
insert into Score values('06' , '03' , 34);
insert into Score values('07' , '02' , 89);
insert into Score values('07' , '03' , 98);
-- where在查询结果返回前对数据库字段进行约束,不能使用聚合函数;而having是在查询结果返回后对结果字段进行约束,自然可以使用聚合函数
-- where后面的and是对前面笛卡尔积表的条件限制,on后面的and只能是对当前表的条件限制
-- 聚合函数一定要配合group by使用
-- union 合并行会去重,union all合并不会去重。
-- 合并的数据必须具有相同列。
-- union 效率比 in 高
-- 创建临时表
CREATE TEMPORARY TABLE temp_t AS
(
SELECT * FROM Student
);
SELECT *
FROM temp_t;
-- 删除临时表
DROP TEMPORARY TABLE temp_t;
-- 查看名字包含某字符的同学
SELECT *
FROM student stu
WHERE stu.s_name like '%赵%';
-- 多字段去重
SELECT
sp.receiving_company,
sp.receiving_account,
sp.receiving_bank,
FROM settlement_port sp
GROUP BY CONCAT(sp.receiving_company,sp.receiving_account,sp.receiving_bank)
-- 查询每个同学的最高学历
SELECT
e.id,
e.employee_id,
e.major_name,
e.school_name,
e.academic_degree
FROM employee_education e
WHERE
(select COUNT(*) from employee_education b
where b.employee_id=e.employee_id and
e.academic_degree<=b.academic_degree)<=1
-- 找出老6及她的兄弟
SELECT *
FROM student stu
WHERE stu.s_name Regexp '老[1-9]';
-- 查看王姓的同学
SELECT *
FROM student stu
WHERE stu.s_name like '王%';
或
SELECT *
FROM student stu
WHERE stu.s_name like '王_';
SELECT *
FROM student stu
WHERE (stu.s_name,stu.s_sex)=('赵雷','男');
-- 先按性别分组,再按生日分组,最后汇总
SELECT
s_sex,s_birth,count(s_sex)
FROM student stu
GROUP BY s_sex,s_birth WITH ROLLUP;
-- 统计有多少种姓氏
SELECT COUNT(DISTINCT LEFT(s_name,1))
FROM student;
-- 查看生日在范围内的同学
SELECT *
FROM student
WHERE s_birth BETWEEN '1990-01-01' and '1991-12-01';
-- 查询字符串中某个字符的重复次数
SELECT (LENGTH('aabaa') - LENGTH(REPLACE('aabaa', 'b', ''))) / LENGTH('b')
-- 行转列
SELECT
name,
MAX(CASE Subject WHEN '语文' THEN Score ELSE 0 END) AS '语文',
MAX(CASE Subject WHEN '数学' THEN Score ELSE 0 END) AS '数学',
MAX(CASE Subject WHEN '英语' THEN Score ELSE 0 END) AS '英语',
MAX(CASE Subject WHEN '生物' THEN Score ELSE 0 END) AS '生物'
FROM
(
SELECT
st.s_name 'name',
co.c_name 'Subject',
sc.s_score 'Score'
FROM student st
LEFT JOIN score sc on st.s_id=sc.s_id
LEFT JOIN course co on co.c_id=sc.c_id
) list
GROUP BY name
-- 使用WITH创建临时表代替student、score、course表,查询学生学科对应的分数
WITH
t1 AS (SELECT * FROM student),
t2 AS (SELECT * FROM score),
t3 AS (SELECT * FROM course)
SELECT t1.s_name,t3.c_name,t2.s_score
FROM t1
LEFT JOIN t2 on t1.s_id=t2.s_id
LEFT JOIN t3 on t2.c_id=t3.c_id;
-- 1、查询"01"课程比"02"课程成绩高的学生的信息及课程分数
SELECT st.s_name,sc1.s_score as '语文',sc2.s_score as '数学'
FROM student st
LEFT JOIN score sc1 on sc1.s_id=st.s_id and sc1.c_id='01'
LEFT JOIN score sc2 on sc2.s_id=st.s_id and sc2.c_id='02'
WHERE sc1.s_score>sc2.s_score;
-- 3、查询平均成绩大于等于60分的同学的学生编号和学生姓名和平均成绩
SELECT st.s_id,st.s_name,AVG(sc.s_score) as '平均成绩'
FROM student st
LEFT JOIN score sc on st.s_id=sc.s_id
group by st.s_id HAVING AVG(sc.s_score)>=60;
-- 5、查询所有同学的学生编号、学生姓名、选课总数、所有课程的总成绩
SELECT st.s_id,st.s_name,COUNT(sc.c_id) as '选课总数',SUM(case when sc.s_score is null then 0 else sc.s_score end) as '总成绩'
FROM student st
LEFT JOIN score sc on st.s_id=sc.s_id
GROUP BY st.s_id
-- 6、查询"李"姓老师的数量
SELECT COUNT(t.t_name) as '李姓老师'
FROM teacher t
WHERE t.t_name like '李_%'
-- 7、查询学过"张三"老师授课的同学的信息
SELECT DISTINCT st.*
FROM student st
LEFT JOIN score sc on sc.s_id=st.s_id
LEFT JOIN course co on co.c_id=sc.c_id
LEFT JOIN teacher te on te.t_id=co.t_id
WHERE te.t_name='张三';
-- 求差集 8、查询没学过"张三"老师授课的同学的信息
SELECT st2.*
FROM student st2
WHERE st2.s_id not in
(SELECT DISTINCT st.s_id
FROM student st
LEFT JOIN score sc on sc.s_id=st.s_id
LEFT JOIN course co on co.c_id=sc.c_id
LEFT JOIN teacher te on te.t_id=co.t_id
WHERE te.t_name='张三');
-- 求交集 9、查询学过编号为"01"并且也学过编号为"02"的课程的同学的信息
SELECT st1.*
FROM student st1
LEFT JOIN score sc1 on sc1.s_id=st1.s_id and sc1.c_id='01'
WHERE st1.s_id in
(SELECT st2.s_id
FROM student st2
LEFT JOIN score sc2 on sc2.s_id=st2.s_id and sc2.c_id='02')
-- 10、查询学过编号为"01"但是没有学过编号为"02"的课程的同学的信息
SELECT st1.*
FROM student st1
LEFT JOIN score sc1 on sc1.s_id=st1.s_id and sc1.c_id='01'
WHERE st1.s_id not in
(SELECT st2.s_id
FROM student st2
LEFT JOIN score sc2 on sc2.s_id=st2.s_id and sc2.c_id='02')
-- 11、查询没有学全所有课程的同学的信息
SELECT st1.*
FROM student st1
LEFT JOIN score sc1 on sc1.s_id=st1.s_id
GROUP BY st1.s_id
HAVING COUNT(*)<(
SELECT DISTINCT COUNT(course.c_name) FROM course
)
-- 12、查询至少有一门课与学号为"01"的同学所学相同的同学的信息
SELECT st1.*
FROM student st1
LEFT JOIN score sc2 on sc2.s_id=st1.s_id
WHERE st1.s_id !='01' AND sc2.c_id in
(SELECT sc1.c_id
FROM student st2
LEFT JOIN score sc1 on sc1.s_id=st2.s_id
WHERE st2.s_id='01')
-- 集合对比 13、查询和"01"号的同学学习的课程完全相同的其他同学的信息
select st.* from student st
left join score sc on sc.s_id=st.s_id
group by st.s_id
having group_concat(sc.c_id) =
(
select group_concat(sc2.c_id) from student st2
left join score sc2 on sc2.s_id=st2.s_id
where st2.s_id ='01'
)
-- 14、查询没学过"张三"老师讲授的任一门课程的学生姓名
-- 3.排除
SELECT *
FROM student st
WHERE st.s_id not in(
-- 2.查询上过张三老师的课的学生id
SELECT sc.s_id
FROM score sc
LEFT JOIN course co on co.c_id=sc.c_id
LEFT JOIN teacher t on t.t_id=co.t_id
WHERE t.t_name='张三'
)
-- 15、查询两门及其以上不及格课程的同学的学号,姓名及其平均成绩
SELECT st.s_id,st.s_name,avg (case when sc.s_score is null then 0 else sc.s_score end) as '平均分数'
FROM student st
LEFT JOIN score sc on sc.s_id=st.s_id
WHERE sc.s_score<60
GROUP BY st.s_id
HAVING COUNT(*)>=2
-- 16、检索"01"课程分数小于60,按分数降序排列的学生信息
SELECT stu.*
FROM student stu
INNER JOIN score sc on sc.s_id=stu.s_id and sc.c_id='01' and sc.s_score<60
GROUP BY stu.s_id
-- 17、按平均成绩从高到低显示所有学生的所有课程的成绩以及平均成绩
select st.s_id,st.s_name,avg(sc4.s_score) "平均分",sc.s_score "语文",sc2.s_score "数学",sc3.s_score "英语" from student st
left join score sc on sc.s_id=st.s_id and sc.c_id="01"
left join score sc2 on sc2.s_id=st.s_id and sc2.c_id="02"
left join score sc3 on sc3.s_id=st.s_id and sc3.c_id="03"
left join score sc4 on sc4.s_id=st.s_id
group by st.s_id
order by avg(sc4.s_score) desc
-- 18.查询各科成绩最高分、最低分和平均分:以如下形式显示:课程ID,课程name,最高分,最低分,平均分,及格率,中等率,优良率,优秀率
-- 及格为>=60,中等为:70-80,优良为:80-90,优秀为:>=90
SELECT co.c_id as '课程ID',
co.c_name as '课程name',
MAX(sc.s_score) as '最高分',
MIN(sc.s_score) as '最低分',
AVG(sc.s_score) as '平均分',
((SELECT COUNT(s_id) FROM score WHERE s_score>=60 AND c_id=co.c_id)/(SELECT COUNT(s_id) FROM score WHERE c_id=co.c_id)) as '及格率'
FROM course co
LEFT JOIN score sc on sc.c_id=co.c_id
GROUP BY co.c_id
-- 19、按各科成绩进行排序,并显示排名(实现不完全)
-- mysql没有rank函数
-- 加@score是为了防止用union all 后打乱了顺序
select c1.s_id,c1.c_id,c1.c_name,@score:=c1.s_score,@i:=@i+1
from (select c.c_name,sc.* from course c
left join score sc on sc.c_id=c.c_id
where c.c_id="01" order by sc.s_score desc) c1 ,
(select @i:=0) a
union all
select c2.s_id,c2.c_id,c2.c_name,c2.s_score,@ii:=@ii+1
from (select c.c_name,sc.* from course c
left join score sc on sc.c_id=c.c_id
where c.c_id="02" order by sc.s_score desc) c2 ,
(select @ii:=0) aa
union all
select c3.s_id,c3.c_id,c3.c_name,c3.s_score,@iii:=@iii+1
from (select c.c_name,sc.* from course c
left join score sc on sc.c_id=c.c_id
where c.c_id="03" order by sc.s_score desc) c3;
set @iii=0;
-- 20、查询学生的总成绩并进行排名
SELECT stu.s_name,SUM(sc.s_score) '总分'
FROM student stu
LEFT JOIN score sc on sc.s_id=stu.s_id
GROUP BY stu.s_id
ORDER BY SUM(sc.s_score) DESC
-- 21、查询不同老师所教不同课程平均分从高到低显示
SELECT t.t_name,co.c_name,AVG(sc.s_score)
FROM teacher t
LEFT JOIN course co on co.t_id=t.t_id
LEFT JOIN score sc on sc.c_id=co.c_id
GROUP BY t.t_id
ORDER BY AVG(sc.s_score) DESC
-- 22、查询所有课程的成绩第2名到第3名的学生信息及该课程成绩
select a.* from (
select st.*,c.c_id,c.c_name,sc.s_score from student st
left join score sc on sc.s_id=st.s_id
inner join course c on c.c_id =sc.c_id and c.c_id="01"
order by sc.s_score desc LIMIT 1,2 ) a
union all
select b.* from (
select st.*,c.c_id,c.c_name,sc.s_score from student st
left join score sc on sc.s_id=st.s_id
inner join course c on c.c_id =sc.c_id and c.c_id="02"
order by sc.s_score desc LIMIT 1,2) b
union all
select c.* from (
select st.*,c.c_id,c.c_name,sc.s_score from student st
left join score sc on sc.s_id=st.s_id
inner join course c on c.c_id =sc.c_id and c.c_id="03"
order by sc.s_score desc LIMIT 1,2) c
-- 23、统计各科成绩各分数段人数:课程编号,课程名称,[100-85],[85-70],[70-60],[0-60]及所占百分比
SELECT
c.c_id,c.c_name,
((SELECT COUNT(0) FROM score sc WHERE c.c_id=sc.c_id and sc.s_score<=100 and sc.s_score>85)/
(SELECT COUNT(0) FROM score sc WHERE c.c_id=sc.c_id)) '100-85',
((SELECT COUNT(0) FROM score sc WHERE c.c_id=sc.c_id and sc.s_score<=85 and sc.s_score>70)/
(SELECT COUNT(0) FROM score sc WHERE c.c_id=sc.c_id)) '85-70',
((SELECT COUNT(0) FROM score sc WHERE c.c_id=sc.c_id and sc.s_score<=70 and sc.s_score>60)/
(SELECT COUNT(0) FROM score sc WHERE c.c_id=sc.c_id)) '70-60',
((SELECT COUNT(0) FROM score sc WHERE c.c_id=sc.c_id and sc.s_score<=60 and sc.s_score>0)/
(SELECT COUNT(0) FROM score sc WHERE c.c_id=sc.c_id)) '60-0'
FROM course c
-- 24、查询学生平均成绩及其名次
set @i=0;
SELECT
a.*,
@i:=@i+1 '排名'
FROM
(SELECT
st.s_id,
st.s_name,
ROUND((case when avg(sc.s_score) is NULL THEN 0 else AVG(sc.s_score) END),2)'平均成绩'
FROM student st
LEFT JOIN score sc on sc.s_id=st.s_id
GROUP BY st.s_id ORDER BY sc.s_score DESC) a
-- 25、查询各科成绩前三名的记录,并集
select a.* from (
select st.s_id,st.s_name,c.c_id,c.c_name,sc.s_score from student st
left join score sc on sc.s_id=st.s_id
inner join course c on c.c_id=sc.c_id and c.c_id='01'
order by sc.s_score desc LIMIT 0,3) a
union all
select b.* from (
select st.s_id,st.s_name,c.c_id,c.c_name,sc.s_score from student st
left join score sc on sc.s_id=st.s_id
inner join course c on c.c_id=sc.c_id and c.c_id='02'
order by sc.s_score desc LIMIT 0,3) b
union all
select c.* from (
select st.s_id,st.s_name,c.c_id,c.c_name,sc.s_score from student st
left join score sc on sc.s_id=st.s_id
inner join course c on c.c_id=sc.c_id and c.c_id='03'
order by sc.s_score desc LIMIT 0,3) c
-- 26、查询每门课程被选修的学生数
select c.c_id,c.c_name,count(1) from course c
left join score sc on sc.c_id=c.c_id
inner join student st on st.s_id=c.c_id
group by st.s_id
-- 27、查询出只有两门课程的全部学生的学号和姓名,求交集
select st.s_id,st.s_name from student st
left join score sc on sc.s_id=st.s_id
inner join course c on c.c_id=sc.c_id
group by st.s_id having count(1)=2
-- 28、查询每门课程的平均成绩,结果按平均成绩降序排列,平均成绩相同时,按课程编号升序排列
select c.c_id,c.c_name,avg(sc.s_score) '平均成绩' from course c
inner join score sc on sc.c_id=c.c_id
group by c.c_id order by avg(sc.s_score) desc,c.c_id asc
-- 29、查询任何一门课程成绩在70分以上的姓名、课程名称和分数
select st2.s_id,st2.s_name,c2.c_name,sc2.s_score from student st2
left join score sc2 on sc2.s_id=st2.s_id
left join course c2 on c2.c_id=sc2.c_id
where st2.s_id in(
select st.s_id from student st
left join score sc on sc.s_id=st.s_id
group by st.s_id having min(sc.s_score)>=70)
order by s_id
-- 30、查询不同课程成绩相同的学生的学生编号、课程编号、学生成绩
select st.s_id,st.s_name,sc.c_id,sc.s_score from student st
left join score sc on sc.s_id=st.s_id
left join course c on c.c_id=sc.c_id
where (
select count(1) from student st2
left join score sc2 on sc2.s_id=st2.s_id
left join course c2 on c2.c_id=sc2.c_id
where sc.s_score=sc2.s_score and c.c_id!=c2.c_id
)>1
-- 31、查询每门功成绩最好的前两名
select st.s_name,co.c_name,a.s_score from score a
LEFT JOIN student st on st.s_id=a.s_id
LEFT JOIN course co on co.c_id=a.c_id
where (select COUNT(1) from score b where b.c_id=a.c_id and b.s_score>=a.s_score)<=2 order by a.c_id
-- 32、统计每门课程的学生选修人数(超过5人的课程才统计)。要求输出课程号和选修人数,查询结果按人数降序排列,若人数相同,按课程号升序排列
select sc.c_id,count(1) from score sc
left join course c on c.c_id=sc.c_id
group by c.c_id having count(1)>5
order by count(1) desc,sc.c_id asc