# 前言
- 过于草率地相信直觉的判断了,作为一个猜想是需要验证的,想当然才是根源
- 执行力不够,脑袋里产生想法之后一定要立即马上去验证,时间长了就忘了!!(最次也得上备忘录)
- 对于连表的理解有欠缺
- sql语句多学多看,多查,终身学习,不要被其他的边边角角占据了头脑,保持敏锐!
- 对于where in和inner join,not in 和left join之间的转化关系有进一步了解
- 前几名的问题,使用group_concat 和 find_in_set的形式可以方便地解决问题
- 周的生日的问题,年份必须转化,不然只会是错误的结果
- case when 的用法,常见于行和列的转化
- MySQL里没有排名函数,所以使用定义的方式就尤为重要,尤其是不保留排名的方式,必须要3个变量
# Update Join
update table_name_1
inner join table_name_2 on table_name_1.id = table_name_2.uid
inner join table_name_3 on table_name_3.id = table_name_1.tid
set *** = ***
where ***
# Delete Join
DELETE a FROM t1 a LEFT JOIN (SELECT min(info_id) AS infoId
FROM t1
GROUP BY form_id) b ON a.info_id = b.infoId WHERE b.infoId is NULL
# in 和 exists
in是把外表和内表作hash连接,而exists是对外表作loop循环,每次loop循环再对内表进行查询,一直以来认为exists比in效率高的说法是不准确的。如果查询的两个表大小相当,那么用in和exists差别不大;如果两个表中一个较小一个较大,则子查询表大的用exists,子查询表小的用in;
例如:表A(小表),表B(大表)
select * from A where cc in(select cc from B) -->效率低,用到了A表上cc列的索引;
select * from A where exists(select cc from B where cc=A.cc) -->效率高,用到了B表上cc列的索引。
相反的:
select * from B where cc in(select cc from A) -->效率高,用到了B表上cc列的索引
select * from B where exists(select cc from A where cc=B.cc) -->效率低,用到了A表上cc列的索引。
# not in 和not exists
not in 逻辑上不完全等同于not exists,如果你误用了not in,小心你的程序存在致命的BUG,请看下面的例子:
create table ##t1(c1 int,c2 int);
create table ##t2(c1 int,c2 int);
insert into ##t1 values(1,2);
insert into ##t1 values(1,3);
insert into ##t2 values(1,2);
insert into ##t2 values(1,null);
select * from ##t1 where c2 not in(select c2 from ##t2); -->执行结果:无
select * from ##t1 where not exists(select 1 from ##t2 where ##t2.c2=##t1.c2) -->执行结果:1 3
正如所看到的,not in出现了不期望的结果集,存在逻辑错误。如果看一下上述两个select 语句的执行计划,也会不同,后者使用了hash_aj,所以,请尽量不要使用not in(它会调用子查询),而尽量使用not exists(它会调用关联子查询)。如果子查询中返回的任意一条记录含有空值,则查询将不返回任何记录。如果子查询字段有非空限制,这时可以使用not in,并且可以通过提示让它用hasg_aj或merge_aj连接。
如果查询语句使用了not in,那么对内外表都进行全表扫描,没有用到索引;而not exists的子查询依然能用到表上的索引。所以无论哪个表大,用not exists都比not in 要快。
- 说多了都是泪啊
# 获取表中某字段包含某字符串的数据
SELECT * FROM `表名` WHERE LOCATE('关键字', 字段名)
- locate函数的用法
# 连续范围的问题
## 创建测试表
CREATE TABLE `test_number` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`number` int(11) unsigned NOT NULL DEFAULT '0' COMMENT '数字',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
## 创建测试数据
insert into test_number values(1,1);
insert into test_number values(2,2);
insert into test_number values(3,3);
insert into test_number values(4,5);
insert into test_number values(5,7);
insert into test_number values(6,8);
insert into test_number values(7,10);
insert into test_number values(8,11);
SELECT min(number) start_range, max(number) end_range
FROM (SELECT number, rn, number - rn diff
FROM (SELECT number, @number := @number + 1 rn
FROM test_number,
(SELECT @number := 0) AS number) b) c
GROUP BY diff;
# 签到问题
## 创建参考表(模拟数据需要用到)
CREATE TABLE `test_nums` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='参考表';
## 模拟数据,插入 1-1000 连续数据.
create PROCEDURE test()
BEGIN
DECLARE i int DEFAULT 1;
WHILE (i < 1000) DO INSERT INTO test_nums VALUES (i);
SET i = i + 1;
END WHILE;
END;
CALL test();
DROP PROCEDURE test;
## 创建测试表
CREATE TABLE `test_sign_history` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`uid` int(11) unsigned NOT NULL DEFAULT '0' COMMENT '用户ID',
`create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '签到时间',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='签到历史表';
## 创建测试数据
insert into test_sign_history(uid,create_time)
select ceil(rand()*10000),str_to_date('2016-12-11','%Y-%m-%d')+interval ceil(rand()*10000) minute
from test_nums where id<500;
## 统计每天的每小时用户签到情况
SELECT
tmp.h,
sum(CASE WHEN tmp.d = '20161211' THEN tmp.c ELSE 0 END ) as 11sign,
sum(CASE WHEN tmp.d = '20161212' THEN tmp.c ELSE 0 END ) as 12sign,
sum(CASE WHEN tmp.d = '20161213' THEN tmp.c ELSE 0 END ) as 13sign,
sum(CASE WHEN tmp.d = '20161214' THEN tmp.c ELSE 0 END ) as 14sign,
sum(CASE WHEN tmp.d = '20161215' THEN tmp.c ELSE 0 END ) as 15sign,
sum(CASE WHEN tmp.d = '20161216' THEN tmp.c ELSE 0 END ) as 16sign,
sum(CASE WHEN tmp.d = '20161217' THEN tmp.c ELSE 0 END ) as 17sign
FROM
(select hour(create_time) h,date_format(create_time,'%Y%m%d') as d,count(*) c
FROM test_sign_history group BY h,d) tmp
GROUP BY tmp.h ORDER BY tmp.h;
## 统计每天的每小时用户签到情况(当某个小时没有数据时,显示0)
## 主要在于使用了辅助表,使用它用来作为left join 的主表
SELECT
tmp.h,
sum(CASE WHEN tmp.d = '20161211' THEN tmp.c ELSE 0 END ) as 11sign,
sum(CASE WHEN tmp.d = '20161212' THEN tmp.c ELSE 0 END ) as 12sign,
sum(CASE WHEN tmp.d = '20161213' THEN tmp.c ELSE 0 END ) as 13sign,
sum(CASE WHEN tmp.d = '20161214' THEN tmp.c ELSE 0 END ) as 14sign,
sum(CASE WHEN tmp.d = '20161215' THEN tmp.c ELSE 0 END ) as 15sign,
sum(CASE WHEN tmp.d = '20161216' THEN tmp.c ELSE 0 END ) as 16sign,
sum(CASE WHEN tmp.d = '20161217' THEN tmp.c ELSE 0 END ) as 17sign
FROM
(SELECT b.h,tsh.d,tsh.c
FROM (SELECT id as h FROM test_nums WHERE id <= 24) b
LEFT JOIN
(select hour(create_time) h,date_format(create_time,'%Y%m%d') as d,count(*) c
FROM test_sign_history group BY h,d) tsh ON b.h = tsh.h
) tmp
GROUP BY tmp.h ORDER BY tmp.h;
## 统计每天的用户签到数据和每天的增量数据
## 自己想的写法
SELECT t.d, t.cnt, t.cnt - @rown AS increase, @rown := t.cnt
FROM (SELECT date_format(create_time, '%Y%m%d') AS d, count(*) AS cnt
FROM test_sign_history
GROUP BY d
ORDER BY d) t,
(SELECT @rown := 0) r;
## 参考写法
## 两种写法,思想不同而已
SELECT type,
sum(CASE WHEN create_time = '2016-12-11' THEN c ELSE 0 END) 11Sign,
sum(CASE WHEN create_time = '2016-12-12' THEN c ELSE 0 END) 12Sign,
sum(CASE WHEN create_time = '2016-12-13' THEN c ELSE 0 END) 13Sign,
sum(CASE WHEN create_time = '2016-12-14' THEN c ELSE 0 END) 14Sign,
sum(CASE WHEN create_time = '2016-12-15' THEN c ELSE 0 END) 15Sign,
sum(CASE WHEN create_time = '2016-12-16' THEN c ELSE 0 END) 16Sign,
sum(CASE WHEN create_time = '2016-12-17' THEN c ELSE 0 END) 17Sign
FROM (SELECT b.create_time, ifnull(b.c - c.c, 0) c, 'Increment' type
FROM (SELECT date_format(create_time, '%Y-%m-%d') create_time, count(*) c
FROM test_sign_history
GROUP BY date_format(create_time, '%Y-%m-%d')) b
LEFT JOIN (SELECT date_format(create_time, '%Y-%m-%d') create_time, count(*) c
FROM test_sign_history
GROUP BY date_format(create_time, '%Y-%m-%d')) c
ON (b.create_time = c.create_time + INTERVAL 1 DAY)
UNION ALL
SELECT date_format(create_time, '%Y-%m-%d') create_time, count(*) c, 'Current'
FROM test_sign_history
GROUP BY date_format(create_time, '%Y-%m-%d')) a
GROUP BY type
ORDER BY CASE WHEN type = 'Current' THEN 1 ELSE 0 END DESC;
##模拟不同的用户签到了不同的天数
insert into test_sign_history(uid,create_time)
select uid,create_time + interval ceil(rand()*10) day from test_sign_history,test_nums
where test_nums.id <10 order by rand() limit 150;
## 统计签到天数相同的用户数量
SELECT date_format(create_time,'%Y%m%d') as d,count(DISTINCT uid) AS user_cnt
FROM test_sign_history GROUP BY d ORDER BY d;
## 统计每个用户的连续签到时间
## 属于连续问题的解决办法
SELECT tmp2.uid,max(tmp2.sign_last) FROM
(
SELECT tmp.uid, min(d) AS begin_date, max(d) AS end_date, datediff(max(d), min(d)) + 1 AS sign_last
FROM (SELECT ud.uid, ud.d, datediff(ud.d, @time) AS diff, @time := @time + INTERVAL 1 DAY
FROM (SELECT uid, date_format(create_time, '%Y-%m-%d') AS d
FROM test_sign_history
GROUP BY uid, d
ORDER BY uid, d) ud,
(SELECT @time := '2016-01-01') t) tmp
GROUP BY tmp.uid, tmp.diff
) tmp2 GROUP BY tmp2.uid;
## 参考写法
SELECT *
FROM (SELECT d.*, @ggid := @cggid, @cggid := d.uid, if(@ggid = @cggid, @grank := @grank + 1, @grank := 1) grank
FROM (SELECT uid, min(c.create_time) begin_date, max(c.create_time) end_date, count(*) count
FROM (SELECT b.*,
@gid := @cgid,
@cgid := b.uid,
if(@gid = @cgid, @rank := @rank + 1, @rank := 1),
b.diff - @rank as flag
FROM (SELECT DISTINCT uid,
date_format(create_time, '%Y-%m-%d') create_time,
datediff(create_time, now()) diff
FROM test_sign_history
ORDER BY uid, create_time) b,
(SELECT @gid := 1, @cgid := 1, @rank := 1) AS a) c
GROUP BY uid, flag
ORDER BY uid, count(*) DESC) d,
(SELECT @ggid := 1, @cggid := 1, @grank := 1) AS e)f
WHERE grank = 1;
# MySQL的测试表
create table if not exists 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 default '',
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);
# 查询"01"课程比"02"课程成绩高的学生的信息及课程分数
- 考虑02课程没选的的情况
SELECT
s.*,sc.s_score AS 01score,sc2.s_score AS 02score
FROM student s INNER JOIN score sc ON s.s_id = sc.s_id AND sc.c_id = '01'
LEFT JOIN score sc2 ON s.s_id = sc2.s_id AND sc2.c_id = '02'
WHERE sc.s_score < sc2.s_score OR sc.s_score is NULL ;
SELECT student.*, a.s_score AS 01_score, b.s_score AS 02_score
FROM student
JOIN score a ON student.s_id = a.s_id AND a.c_id = '01'
LEFT JOIN score b ON student.s_id = b.s_id AND b.c_id = '02' OR b.c_id = NULL
WHERE a.s_score > b.s_score;
# 查询"01"课程比"02"课程成绩低的学生的信息及课程分数
SELECT student.*, a.s_score AS 01_score, b.s_score AS 02_score
FROM student
JOIN score a ON student.s_id = a.s_id AND a.c_id = '01' OR a.c_id = NULL
LEFT JOIN score b ON student.s_id = b.s_id AND b.c_id = '02'
WHERE a.s_score < b.s_score;
# 查询平均成绩大于等于60分的同学的学生编号和学生姓名和平均成绩
- group by 之后,如果已经group by 了用以区分的id,那么其他所有的属性都是可以直接得出来的
SELECT
s.s_id,s.s_name,round(avg(sc.s_score),1) as avg_score
FROM student s LEFT JOIN score sc on s.s_id = sc.s_id
GROUP BY s.s_id,s.s_name HAVING avg(sc.s_score) >= 60;
SELECT student.s_id, student.s_name, tmp.avg_score
FROM student
JOIN (SELECT score.s_id, round(avg(score.s_score), 1)AS avg_score FROM score GROUP BY s_id)AS tmp
ON tmp.avg_score >= 60
WHERE student.s_id = tmp.s_id;
–答案2
SELECT student.s_id, student.s_name, round(avg(score.s_score), 1) AS avg_score
FROM student
JOIN score ON student.s_id = score.s_id
GROUP BY score.s_id
HAVING avg(score.s_score) >= 60;
# 查询平均成绩小于60分的同学的学生编号和学生姓名和平均成绩
– (包括有成绩的和无成绩的)
SELECT
s.s_id,s.s_name,ifnull(round(avg(sc.s_score),1),0) as avg_score
FROM student s LEFT JOIN score sc on s.s_id = sc.s_id
GROUP BY s.s_id,s.s_name HAVING avg(sc.s_score) < 60
or count(sc.s_score) = 0;
SELECT student.s_id, student.s_name, tmp.avg_score
FROM student
JOIN (SELECT score.s_id, round(avg(score.s_score), 1)AS avg_score FROM score GROUP BY s_id)AS tmp
ON tmp.avg_score < 60
WHERE student.s_id = tmp.s_id
UNION
SELECT s_id, s_name, 0 AS avg_score
FROM student
WHERE s_id NOT IN
(SELECT DISTINCT s_id FROM score);
–答案2
SELECT student.s_id, student.s_name, round(avg(score.s_score), 1) AS avg_score
FROM student
JOIN score ON student.s_id = score.s_id
GROUP BY score.s_id
HAVING avg(score.s_score) < 60
UNION
SELECT s_id, s_name, 0 AS avg_score
FROM student
WHERE s_id NOT IN
(SELECT DISTINCT s_id FROM score);
# 查询所有同学的学生编号、学生姓名、选课总数、所有课程的总成绩
SELECT s.s_id,s.s_name,count(DISTINCT sc.c_id) as num,sum(sc.s_score) as total
FROM student s LEFT JOIN score sc ON s.s_id = sc.s_id
GROUP BY s.s_id ORDER BY total DESC ;
SELECT student.s_id, student.s_name, count(score.c_id) AS total_count, sum(score.s_score)AS total_score
FROM student
LEFT JOIN score ON student.s_id = score.s_id
GROUP BY student.s_id ORDER BY total_score DESC ;
# 查询"李"姓老师的数量
SELECT count(1)
FROM teacher
WHERE t_name LIKE '李%';
# 查询学过"张三"老师授课的同学的信息
-- 这就是因为对于连表的概念还不够融汇贯通的表现
SELECT student.*
FROM student INNER JOIN
(SELECT sc.s_id
FROM score sc INNER JOIN course c ON sc.c_id = c.c_id
INNER JOIN teacher t ON c.t_id = t.t_id WHERE t.t_name= '张三') tmp
ON student.s_id = tmp.s_id;
SELECT student.*
FROM student INNER JOIN
score sc ON student.s_id = sc.s_id INNER JOIN course c ON sc.c_id = c.c_id
INNER JOIN teacher t ON c.t_id = t.t_id WHERE t.t_name= '张三';
SELECT *
FROM student
JOIN score ON student.s_id = score.s_id
WHERE score.c_id IN (SELECT course.c_id
FROM course
WHERE course.t_id IN (SELECT teacher.t_id FROM teacher WHERE teacher.t_name = '张三'));
–答案2
SELECT student.*
FROM student
JOIN score ON student.s_id = score.s_id
JOIN course ON course.c_id = score.c_id
JOIN teacher ON course.t_id = teacher.t_id AND t_name = '张三';
# 查询没学过"张三"老师授课的同学的信息
SELECT *
FROM student
WHERE s_id NOT IN (SELECT score.s_id
FROM score
WHERE score.c_id IN (SELECT course.c_id
FROM course
WHERE course.t_id =
(SELECT teacher.t_id FROM teacher WHERE teacher.t_name = '张三')));
SELECT student.*
FROM student LEFT JOIN
(SELECT sc.s_id
FROM score sc INNER JOIN course c ON sc.c_id = c.c_id
INNER JOIN teacher t ON c.t_id = t.t_id WHERE t.t_name= '张三') tmp
ON student.s_id = tmp.s_id WHERE tmp.s_id is NULL ;
–答案2
SELECT student.*
FROM student
LEFT JOIN (SELECT s_id
FROM score
JOIN course ON course.c_id = score.c_id
JOIN teacher ON course.t_id = teacher.t_id AND t_name = '张三')tmp ON student.s_id = tmp.s_id
WHERE tmp.s_id IS NULL;
# 查询学过编号为"01"并且也学过编号为"02"的课程的同学的信息
SELECT *
FROM student
WHERE s_id IN (SELECT s_id FROM score WHERE c_id = 1)
AND s_id IN (SELECT s_id FROM score WHERE c_id = 2);
# 查询学过编号为"01"但是没有学过编号为"02"的课程的同学的信息
SELECT *
FROM student
WHERE s_id IN (SELECT s_id FROM score WHERE c_id = 1)
AND s_id NOT IN (SELECT s_id FROM score WHERE c_id = 2);
–答案2
SELECT student.*
FROM student
JOIN (SELECT s_id FROM score WHERE c_id = 1)tmp1 ON student.s_id = tmp1.s_id
LEFT JOIN (SELECT s_id FROM score WHERE c_id = 2)tmp2 ON student.s_id = tmp2.s_id
WHERE tmp2.s_id IS NULL;
# 查询没有学全所有课程的同学的信息
SELECT *
FROM student
WHERE s_id NOT IN (SELECT s_id FROM score GROUP BY s_id HAVING count(c_id) = (SELECT count(1) FROM course));
# 查询至少有一门课与学号为"01"的同学所学相同的同学的信息
-- 对于这种单个的条件的情况下,使用where in的方式,明显更加直接,如果有多个条件的情况下,使用join才是优势
SELECT DISTINCT student.* FROM student INNER JOIN score ON student.s_id = score.s_id WHERE score.c_id IN
(SELECT c_id FROM score WHERE s_id = '01') AND student.s_id <> '01';
SELECT *
FROM student
WHERE s_id <> 01
AND s_id IN (SELECT s_id FROM score WHERE c_id IN (SELECT c_id FROM score WHERE score.s_id = 01) GROUP BY s_id);
# 查询和"01"号的同学学习的课程完全相同的其他同学的信息
-- 使用了group_concat的知识,还以为能有什么新鲜的
SELECT s.*,tmp1.cids FROM student s INNER JOIN
(SELECT s_id,group_concat(c_id ORDER by c_id) as cids FROM score GROUP BY s_id ) tmp1
ON s.s_id = tmp1.s_id AND s.s_id <> '01'
WHERE tmp1.cids =
(SELECT group_concat(c_id ORDER by c_id) as cids FROM score WHERE s_id = '01' GROUP BY s_id );
SELECT student.*, tmp.course_id
FROM (SELECT s_id, group_concat(c_id) course_id
FROM score
GROUP BY s_id
HAVING s_id <> 1
AND course_id = (SELECT group_concat(c_id) course_id2 FROM score WHERE s_id = 1))tmp
JOIN student ON student.s_id = tmp.s_id;
# 查询没学过"张三"老师讲授的任一门课程的学生姓名
SELECT *
FROM student
WHERE s_id NOT IN (SELECT s_id
FROM score
JOIN (SELECT c_id FROM course WHERE t_id IN (SELECT t_id FROM teacher WHERE t_name = '张三'))tmp
ON score.c_id = tmp.c_id);
–答案2
SELECT student.*
FROM student
LEFT JOIN (SELECT s_id
FROM score
JOIN (SELECT c_id FROM course
JOIN teacher ON course.t_id = teacher.t_id AND t_name = '张三')tmp2
ON score.c_id = tmp2.c_id)tmp ON student.s_id = tmp.s_id
WHERE tmp.s_id IS NULL;
# 查询两门及其以上不及格课程的同学的学号,姓名及其平均成绩
-- 关于sum里面可以使用计算条件的方式,很多人都不知道
SELECT s.*,round(tmp.avg_score,1) as avg_score FROM student s INNER JOIN
(SELECT s_id,avg(s_score) as avg_score FROM score GROUP BY s_id HAVING sum(s_score < 60) >=2) tmp
ON s.s_id = tmp.s_id;
SELECT student.s_id, student.s_name, tmp.avg_score
FROM student
LEFT JOIN (SELECT s_id, round(AVG(score.s_score)) avg_score FROM score GROUP BY s_id)tmp
ON tmp.s_id = student.s_id
WHERE student.s_id IN (SELECT s_id FROM score WHERE s_score < 60 GROUP BY score.s_id HAVING count(s_id) > 1);
# 检索"01"课程分数小于60,按分数降序排列的学生信息
SELECT student.*, s_score
FROM student,
score
WHERE student.s_id = score.s_id
AND s_score < 60
AND c_id = '01'
ORDER BY s_score DESC;
# 按平均成绩从高到低显示所有学生的所有课程的成绩以及平均成绩
-- 在查找的选项里还是可以有这种花式的写法的
SELECT s_id,
(SELECT s_score
FROM score
WHERE s_id = a.s_id
AND c_id = '01')AS 语文,
(SELECT s_score
FROM score
WHERE s_id = a.s_id
AND c_id = '02')AS 数学,
(SELECT s_score
FROM score
WHERE s_id = a.s_id
AND c_id = '03')AS 英语,
round(avg(s_score), 2) AS 平均分
FROM score a
GROUP BY s_id
ORDER BY 平均分 DESC;
–答案2
-- 尝试使用group_concat 的方式处理,外连接的一点模糊领域,要知道一个都连不到的情况下才会出现null
SELECT sc.s_id,avg(sc.s_score) as avg_score,group_concat(sc.s_score) FROM score sc
RIGHT JOIN course c ON c.c_id = sc.c_id
GROUP BY sc.s_id ORDER BY avg_score DESC ;
-- 由于如果一旦使用了group by sid的方式,那么各科的成绩将无法获取,所以使用left join 多个表的形式处理
SELECT a.s_id,
tmp1.s_score AS chinese,
tmp2.s_score AS math,
tmp3.s_score AS english,
round(avg(a.s_score), 2) AS avgScore
FROM score a
LEFT JOIN (SELECT s_id, s_score FROM score s1 WHERE c_id = '01')tmp1 ON tmp1.s_id = a.s_id
LEFT JOIN (SELECT s_id, s_score FROM score s2 WHERE c_id = '02')tmp2 ON tmp2.s_id = a.s_id
LEFT JOIN (SELECT s_id, s_score FROM score s3 WHERE c_id = '03')tmp3 ON tmp3.s_id = a.s_id
GROUP BY a.s_id, tmp1.s_score, tmp2.s_score, tmp3.s_score
ORDER BY avgScore DESC;
# 查询各科成绩最高分、最低分和平均分:以如下形式显示:课程ID,课程name,最高分,最低分,平均分,及格率,中等率,优良率,优秀率 –及格为>=60,中等为:70-80,优良为:80-90,优秀为:>=90
-- 再次验证了sum里面的条件其实是可以直接等效为case when的,这样就非常方便了
SELECT sc.c_id,c.c_name,avg(sc.s_score) avg_score,max(sc.s_score) max_score,
min(sc.s_score) min_score,sum(s_score>=60)/count() AS pass_rate,
sum(s_score>=80 AND s_score<90)/count() AS good_rate
FROM score sc INNER JOIN course c on sc.c_id =c.c_id GROUP BY sc.c_id;
SELECT score.c_id AS '课程ID',
course.c_name AS '课程name',
max(s_score) AS '最高分',
min(s_score)AS '最低分',
round(avg(s_score), 2) '平均分',
round(sum(CASE WHEN s_score >= 60 THEN 1 ELSE 0 END) / sum(CASE WHEN s_score THEN 1 ELSE 0 END), 2)'及格率',
round(sum(CASE WHEN s_score >= 70 AND s_score < 80 THEN 1 ELSE 0 END) / sum(CASE WHEN s_score THEN 1 ELSE 0 END),
2)'中等率',
round(sum(CASE WHEN s_score >= 80 AND s_score < 90 THEN 1 ELSE 0 END) / sum(CASE WHEN s_score THEN 1 ELSE 0 END),
2)'优良率',
round(sum(CASE WHEN s_score >= 90 THEN 1 ELSE 0 END) / (SUM(CASE WHEN s_score THEN 1 ELSE 0 END)), 2)'优秀率'
FROM score
LEFT JOIN course ON score.c_id = course.c_id
GROUP BY score.c_id;
–答案2
SELECT course.c_id,
course.c_name,
tmp.maxScore,
tmp.minScore,
tmp.avgScore,
tmp.passRate,
tmp.moderate,
tmp.goodRate,
tmp.excellentRates
FROM course
JOIN (SELECT c_id,
max(s_score) AS maxScore,
min(s_score)AS minScore,
round(avg(s_score), 2) avgScore,
round(sum(CASE WHEN s_score >= 60 THEN 1 ELSE 0 END) / count(c_id), 2)passRate,
round(sum(CASE WHEN s_score >= 60 AND s_score < 70 THEN 1 ELSE 0 END) / count(c_id), 2) moderate,
round(sum(CASE WHEN s_score >= 70 AND s_score < 80 THEN 1 ELSE 0 END) / count(c_id), 2) goodRate,
round(sum(CASE WHEN s_score >= 80 AND s_score < 90 THEN 1 ELSE 0 END) / count(c_id),
2) excellentRates
FROM score
GROUP BY c_id)tmp ON tmp.c_id = course.c_id;
# 按各科成绩进行排序,并显示排名(实现不完全)
– mysql没有rank函数
–方法1
-- 关于排名的sql,很蛋疼的是可能会涉及到不同的同分情况下,是否占用排名的形式
-- 在select的项里面,可以使用查找语句,查找出的是一个值就是了
(SELECT * FROM
(SELECT s1.s_id, s1.c_id, s1.s_score,
(SELECT COUNT(distinct sc.s_score) FROM score sc
WHERE sc.s_score>=s1.s_score AND sc.c_id = '01') as 'rank不保留排名'
FROM score s1 WHERE s1.c_id = '01' ORDER BY s1.s_score DESC) t1)
UNION (SELECT * FROM
(SELECT s1.s_id, s1.c_id, s1.s_score,
(SELECT COUNT(DISTINCT sc.s_score) FROM score sc
WHERE sc.s_score>=s1.s_score AND sc.c_id = '02') 'rank不保留排名'
FROM score s1 WHERE s1.c_id = '02' ORDER BY s1.s_score DESC) t2)
UNION (SELECT * FROM
(SELECT s1.s_id, s1.c_id, s1.s_score,
(SELECT COUNT(DISTINCT sc.s_score) FROM score sc
WHERE sc.s_score>=s1.s_score AND sc.c_id = '03') 'rank不保留排名'
FROM score s1 WHERE s1.c_id = '03' ORDER BY s1.s_score DESC) t3)
–方法2
(SELECT a.s_id, a.c_id, @i:=@i+1 AS i保留排名,
@k:=(CASE WHEN @score = a.s_score THEN @k ELSE @i END) AS rank不保留排名,
@score:=a.s_score AS score
FROM (SELECT * FROM score WHERE c_id = '01' GROUP BY s_id, c_id, s_score ORDER BY s_score DESC)a,
(SELECT @i:=0, @k:=0, @score:=0)b)
UNION
(SELECT a.s_id, a.c_id, @m:=@m+1 AS i保留排名,
@k:=(CASE WHEN @score = a.s_score THEN @k ELSE @m END) AS rank不保留排名,
@score:=a.s_score AS score
FROM (SELECT * FROM score WHERE c_id = '02' GROUP BY s_id, c_id, s_score ORDER BY s_score DESC)a,
(SELECT @m:=0, @k:=0, @score:=0)b)
UNION
(SELECT a.s_id, a.c_id, @x:=@x+1 AS i保留排名,
@k:=(CASE WHEN @score = a.s_score THEN @k ELSE @x END) AS rank不保留排名,
@score:=a.s_score AS score
FROM (SELECT * FROM score WHERE c_id = '03' GROUP BY s_id, c_id, s_score ORDER BY s_score DESC)a,
(SELECT @x:=0, @k:=0, @score:=0)b);
# 查询学生的总成绩并进行排名
SELECT score.s_id, s_name, sum(s_score) sumscore
FROM score,
student
WHERE score.s_id = student.s_id
GROUP BY score.s_id
ORDER BY sumscore DESC;
# 查询不同老师所教不同课程平均分从高到低显示
–方法1
-- 自行写法,参考写法实在是多此一举啊
SELECT t.t_id,sc.c_id,t.t_name,avg(sc.s_score) avgScore
FROM teacher t INNER JOIN course c ON t.t_id = c.t_id
INNER JOIN score sc ON sc.c_id = c.c_id
GROUP BY t.t_id,sc.c_id ORDER BY avgScore DESC ;
SELECT tmp.c_id, t_id, avgscore AS '平均分'
FROM ((SELECT DISTINCT c_id, (round((SELECT avg(s_score) FROM score WHERE c_id = '01' GROUP BY c_id), 2))avgscore
FROM score s1
WHERE c_id = '01')
UNION
(SELECT DISTINCT c_id, (round((SELECT avg(s_score) FROM score WHERE c_id = '02' GROUP BY c_id), 2))avgscore
FROM score s1
WHERE c_id = '02')
UNION
(SELECT DISTINCT c_id, (round((SELECT avg(s_score) FROM score WHERE c_id = '03' GROUP BY c_id), 2))avgscore
FROM score s1
WHERE c_id = '03'))tmp,
course
WHERE tmp.c_id = course.c_id
ORDER BY tmp.avgscore DESC;
–方法2
SELECT course.c_id, course.t_id, t_name, round(avg(s_score), 2)AS avgscore
FROM course
JOIN teacher ON teacher.t_id = course.t_id
JOIN score ON course.c_id = score.c_id
GROUP BY score.c_id
ORDER BY avgscore DESC;
–方法3
-- 使用cross join 的方式反而是对查询效率的降级
SELECT course.c_id, course.t_id, t_name, round(avg(s_score), 2)AS avgscore
FROM course,
teacher,
score
WHERE teacher.t_id = course.t_id
AND course.c_id = score.c_id
GROUP BY score.c_id
ORDER BY avgscore DESC;
# 查询所有课程的成绩第2名到第3名的学生信息及该课程成绩
–方法1
-- 由于这种情况下,group by 之后没有办法使用limit,而这种特定的名词就是使用Limit的处理合适,所以就使用union进行连接
(SELECT student., tmp1.c_id, tmp1.s_score FROM student,
(SELECT s_id, c_id, s_score FROM score WHERE c_id = '01' ORDER BY s_score DESC LIMIT 1, 2)tmp1
WHERE student.s_id = tmp1.s_id)
UNION (SELECT student., tmp2.c_id, tmp2.s_score FROM student,
(SELECT s_id, c_id, s_score FROM score WHERE c_id = '02' ORDER BY s_score DESC LIMIT 1, 2)tmp2
WHERE student.s_id = tmp2.s_id)
UNION (SELECT student.*, tmp3.c_id, tmp3.s_score FROM student,
(SELECT s_id, c_id, s_score FROM score WHERE c_id = '03' ORDER BY s_score DESC LIMIT 1, 2)tmp3
WHERE student.s_id = tmp3.s_id);
–方法2
-- 直接找出排名,然后对排名进行筛选,当然是一种方法,但是并不推荐
(SELECT student., tmp.c_id, tmp.s_score, tmp.排名 FROM (
SELECT a.s_id, a.c_id, a.s_score, @i:=@i+1 AS 排名 FROM score a, (SELECT @i:=0)b
WHERE a.c_id = '01' ORDER BY a.s_score DESC
)tmp JOIN student ON tmp.s_id = student.s_id WHERE 排名 BETWEEN 2 AND 3)
UNION (
SELECT student., tmp.c_id, tmp.s_score, tmp.排名 FROM (
SELECT a.s_id, a.c_id, a.s_score, @j:=@j+1 AS 排名 FROM score a, (SELECT @j:=0)b
WHERE a.c_id = '02' ORDER BY a.s_score DESC
)tmp JOIN student ON tmp.s_id = student.s_id WHERE 排名 BETWEEN 2 AND 3
) UNION (
SELECT student.*, tmp.c_id, tmp.s_score, tmp.排名 FROM (
SELECT a.s_id, a.c_id, a.s_score, @k:=@k+1 AS 排名 FROM score a, (SELECT @k:=0)b
WHERE a.c_id = '03' ORDER BY a.s_score DESC
)tmp JOIN student ON tmp.s_id = student.s_id WHERE 排名 BETWEEN 2 AND 3);
# 统计各科成绩各分数段人数:课程编号,课程名称,100-85,85-70,70-60,0-60及所占百分比
-- 很简单可以搞定的东西,为何需要那么复杂啊。。
select c.c_id,c.c_name,
sum(sc.s_score<=100 AND sc.s_score>=85) AS a,
sum(sc.s_score<85 AND sc.s_score>=70) AS b,
sum(sc.s_score<70 AND sc.s_score>=60) AS c
FROM course c INNER JOIN score sc ON c.c_id = sc.c_id
GROUP BY c.c_id ;
# 查询学生平均成绩及其名次
- 因为MySQL没有rowcount的函数,所以需要使用此种形式
SELECT a.s_id, a.s_name, a.平均分, @i := @i + 1 AS 排名
FROM (SELECT student.s_id, student.s_name, avg(score.s_score) AS "平均分"
FROM student,
score
WHERE student.s_id = score.s_id
GROUP BY score.s_id
ORDER BY 平均分
DESC)a,
(SELECT @i := 0)b;
# 查询各科成绩前三名的记录
– 1.选出b表比a表成绩大的所有组
– 2.选出比当前id成绩大的 小于三个的
–没有查学生姓名
- 查找前几名的方法,使用find_in_set真的是可以事半功倍啊!!
SELECT s1.*,s2.c_name FROM score s1 INNER JOIN
(SELECT sc.c_id,c.c_name,group_concat(sc.s_id ORDER BY sc.s_score DESC) as sids
FROM score sc INNER JOIN course c on c.c_id = sc.c_id GROUP BY sc.c_id) s2 ON s1.c_id = s2.c_id WHERE
find_in_set(s1.s_id,s2.sids) BETWEEN 1 AND 3 ORDER BY s1.c_id,s1.s_score DESC ;
(SELECT score.c_id, course.c_name, s_score FROM score, course
WHERE score.c_id = '01' AND course.c_id = score.c_id ORDER BY s_score DESC LIMIT 3)
UNION
(SELECT score.c_id, course.c_name, s_score FROM score, course
WHERE score.c_id = '02' AND course.c_id = score.c_id ORDER BY s_score DESC LIMIT 3)
UNION
(SELECT score.c_id, course.c_name, s_score FROM score, course
WHERE score.c_id = '03' AND course.c_id = score.c_id ORDER BY s_score DESC LIMIT 3);
–查了学生姓名
(SELECT score.c_id, course.c_name, student.s_name, s_score FROM score
JOIN student ON student.s_id = score.s_id
JOIN course ON score.c_id = '01' AND course.c_id = score.c_id ORDER BY s_score DESC LIMIT 3)
UNION (
SELECT score.c_id, course.c_name, student.s_name, s_score FROM score
JOIN student ON student.s_id = score.s_id
JOIN course ON score.c_id = '02' AND course.c_id = score.c_id ORDER BY s_score DESC LIMIT 3
) UNION (
SELECT score.c_id, course.c_name, student.s_name, s_score FROM score
JOIN student ON student.s_id = score.s_id
JOIN course ON score.c_id = '03' AND course.c_id = score.c_id ORDER BY s_score DESC LIMIT 3);
# 查询每门课程被重修的学生数
- 能直接连接就不要使用子查询,使用count(1)的形式其实是不严谨的
SELECT c.c_id,c.c_name,count(DISTINCT sc.s_id) AS cnt FROM course c LEFT JOIN score sc ON c.c_id = sc.c_id
WHERE sc.s_score < 60
GROUP BY c.c_id;
SELECT c.c_id, c.c_name, a.被选修人数
FROM course c
JOIN (SELECT c_id, count(1) AS 被选修人数
FROM score WHERE score.s_score < 60 GROUP BY score.c_id)a
ON a.c_id = c.c_id;
# 查询出只有两门课程的全部学生的学号和姓名
- 还是那句话,如果已经group by了完全的s_id了,那么其他的项都是可以获取到的
SELECT s.s_id,s.s_name
FROM student s INNER JOIN score sc ON s.s_id = sc.s_id GROUP BY s.s_id HAVING count(DISTINCT c_id) = 2;
SELECT st.s_id, st.s_name
FROM student st
JOIN (SELECT s_id FROM score GROUP BY s_id HAVING count(c_id) = 2)a ON st.s_id = a.s_id;
# 查询男生、女生人数
SELECT
sum(s_sex = '男') as male,
sum(s_sex = '女') as female
FROM student;
SELECT a.男生人数, b.女生人数
FROM (SELECT count(1) AS 男生人数 FROM student WHERE s_sex = '男')a,
(SELECT count(1) AS 女生人数 FROM student WHERE s_sex = '女')b;
# 查询名字中含有"风"字的学生信息
SELECT *
FROM student
WHERE s_name LIKE '%风%';
# 查询同名同性学生名单,并统计同名人数
统计个数就是聚合的方式,很简单,直接group by就是了,大不了再用find_in_set就是了
SELECT s_name,s_sex,GROUP_CONCAT(s_id) sids,count(s_id) cnt
FROM student GROUP BY s_name,s_sex HAVING count(s_id) >=2;这是错误的写法,老哥啊
SELECT s1.s_name, s1.s_sex, count(*) AS 同名人数
FROM student s1,
student s2
WHERE s1.s_name = s2.s_name
AND s1.s_id <> s2.s_id
AND s1.s_sex = s2.s_sex
GROUP BY s1.s_name, s1.s_sex;
# 查询1990年出生的学生名单
SELECT *
FROM student
WHERE s_birth LIKE '1990%';
# 查询每门课程的平均成绩,结果按平均成绩降序排列,平均成绩相同时,按课程编号升序排列
SELECT score.c_id, c_name, round(avg(s_score), 2) AS 平均成绩
FROM score
JOIN course ON score.c_id = course.c_id
GROUP BY c_id
ORDER BY 平均成绩
DESC, score.c_id ASC;
# 查询平均成绩大于等于85的所有学生的学号、姓名和平均成绩
SELECT s.s_id,s.s_name,round(avg(sc.s_score),2) AS avgScore
FROM student s INNER JOIN score sc ON s.s_id = sc.s_id
GROUP BY s.s_id HAVING avgScore >= 85;
SELECT score.s_id, s_name, round(avg(s_score), 2)AS 平均成绩
FROM score
JOIN student ON student.s_id = score.s_id
GROUP BY score.s_id
HAVING 平均成绩
>= 85;
# 查询课程名称为"数学",且分数低于60的学生姓名和分数
SELECT s_name, s_score AS 数学成绩
FROM student
JOIN (SELECT s_id, s_score
FROM score,
course
WHERE score.c_id = course.c_id
AND c_name = '数学')a ON a.s_score < 60 AND student.s_id = a.s_id;
# 查询所有学生的课程及分数情况
- 相当于行列转换的用法了,由于需要就算总分,必须要要使用聚合
SELECT a.s_name,
SUM(CASE c.c_name WHEN '语文' THEN b.s_score ELSE 0 END) AS 语文,
SUM(CASE c.c_name WHEN '数学' THEN b.s_score ELSE 0 END) AS 数学,
SUM(CASE c.c_name WHEN '英语' THEN b.s_score ELSE 0 END) AS 英语,
SUM(b.s_score) AS 总分
FROM student a
JOIN score b ON a.s_id = b.s_id
JOIN course c ON b.c_id = c.c_id
GROUP BY s_name, a.s_id;
# 查询任何一门课程成绩在70分以上的学生姓名、课程名称和分数
SELECT s.s_id,s.s_name,sc.s_score FROM student s INNER JOIN score sc ON s.s_id = sc.s_id
WHERE sc.s_id not IN
(SELECT s_id FROM score WHERE s_score < 70 GROUP BY s_id);
- 又是一个错误的写法
SELECT s_name, c_name, s_score
FROM score
JOIN student ON student.s_id = score.s_id
JOIN course ON score.c_id = course.c_id
WHERE s_score < 70;
# 查询不及格的课程
SELECT s_name, c_name AS 不及格课程, tmp.s_score
FROM student
JOIN (SELECT s_id, s_score, c_name
FROM score,
course
WHERE score.c_id = course.c_id
AND s_score < 60)tmp ON student.s_id = tmp.s_id;
# 查询课程编号为01且课程成绩在80分以上的学生的学号和姓名
SELECT student.s_id, s_name, s_score AS score_01
FROM student
JOIN score ON student.s_id = score.s_id
WHERE c_id = '01'
AND s_score >= 80;
# 求每门课程的学生人数
SELECT course.c_id, course.c_name, count(1)AS 选课人数
FROM course
JOIN score ON course.c_id = score.c_id
GROUP BY score.c_id;
# 查询选修"张三"老师所授课程的学生中,成绩最高的学生信息及其成绩
– 查询老师id
- 此种查法会丢失调同样都是最高分的学生
SELECT s.*,c.c_name,sc.s_score
FROM student s INNER JOIN score sc ON s.s_id = sc.s_id
INNER join course c ON sc.c_id = c.c_id
INNER JOIN teacher t ON c.t_id = t.t_id
WHERE t.t_name= '张三' ORDER BY sc.s_score DESC LIMIT 1;
select s.*,sc.s_score FROM student s inner join score sc ON s.s_id = sc.s_id
where sc.s_score = (
SELECT max(sc.s_score)
FROM score sc INNER join course c ON sc.c_id = c.c_id
INNER JOIN teacher t ON c.t_id = t.t_id
WHERE t.t_name= '张三'
);
– 查询最高分(可能有相同分数)
SELECT max(s_score)
FROM score
JOIN (SELECT course.c_id, c_name
FROM course,
(SELECT t_id, t_name FROM teacher WHERE t_name = '张三')tmp
WHERE course.t_id = tmp.t_id)tmp2 ON score.c_id = tmp2.c_id;
# 查询不同课程成绩相同的学生的学生编号、课程编号、学生成绩
SELECT DISTINCT a.s_id, a.c_id, a.s_score
FROM score a,
score b
WHERE a.c_id <> b.c_id
AND a.s_score = b.s_score;
# 查询每门课程成绩最好的前两名
–方法1(该方法有bug, 不能查出临界的重复值, 例如查各科的第一名或前三名)
- 这里如果第一名的话,显然就有问题了
SELECT a.s_id, a.c_id, a.s_score
FROM score a
WHERE (SELECT count(1)
FROM score b
WHERE a.c_id = b.c_id
AND b.s_score >= a.s_score) <= 2
ORDER BY a.c_id ASC, a.s_score DESC;
–方法2(查前三名)
- 达成这种效果的话,其实find_in_set的方式更加合理和擅长
(SELECT * FROM score WHERE c_id = '01' ORDER BY s_score DESC LIMIT 3)
UNION (
SELECT * FROM score WHERE c_id = '02' ORDER BY s_score DESC LIMIT 3)
UNION (
SELECT * FROM score WHERE c_id = '03' ORDER BY s_score DESC LIMIT 3);
-方法三
- 仍然是使用find_in_set的方式,比起其他的真是好用很多了
SELECT sc.* FROM score sc INNER JOIN
(SELECT c_id,group_concat(s_id ORDER by s_score DESC) sids
FROM score GROUP BY c_id) tmp ON sc.c_id = tmp.c_id WHERE
find_in_set(sc.s_id,tmp.sids) BETWEEN 1 AND 2 ORDER BY sc.c_id,s_score DESC ;
# 统计每门课程的学生选修人数(超过5人的课程才统计)。要求输出课程号和选修人数,查询结果按人数降序排列,若人数相同,按课程号升序排列
SELECT DISTINCT course.c_id, tmp.选修人数
FROM course
JOIN (SELECT c_id, count(1) AS 选修人数 FROM score GROUP BY c_id)tmp
WHERE tmp.选修人数 >= 5
ORDER BY tmp.选修人数 DESC, course.c_id ASC;
# 检索至少选修两门课程的学生学号
SELECT s_id, count(c_id) AS totalCourse
FROM score
GROUP BY s_id
HAVING count(c_id) >= 2;
# 查询选修了全部课程的学生信息
SELECT student.*
FROM student,
(SELECT s_id, count(c_id) AS totalCourse FROM score GROUP BY s_id)tmp
WHERE student.s_id = tmp.s_id
AND totalCourse = 3;
# 查询各学生的年龄
– 按照出生日期来算,当前月日 < 出生年月的月日则,年龄减一
- date_format之后的可以直接进行加减运算,这个就算是记下了
SELECT s_name, s_birth, (DATE_FORMAT(NOW(), '%Y') - DATE_FORMAT(s_birth, '%Y') -
CASE
WHEN (DATE_FORMAT(NOW(), '%m%d') > DATE_FORMAT(s_birth, '%m%d')) THEN 1
ELSE 0 END) AS age
FROM student;
# 查询本周过生日的学生
–方法1
SELECT *,week(s_birth) FROM student
WHERE week(now()) = week(concat(date_format(now(),'%Y'),date_format(s_birth,'%m%d')));
- 以下全错啊!!
SELECT *
FROM student
WHERE WEEK(DATE_FORMAT(NOW(), '%Y%m%d')) = WEEK(s_birth);
# 查询本月过生日的学生
–方法1
SELECT *,month(s_birth)
FROM student
WHERE MONTH(DATE_FORMAT(NOW(), '%Y%m%d')) = MONTH(s_birth);
–方法2
- 这种方法很不正规
SELECT s_name, s_sex, s_birth
FROM student
WHERE substring(s_birth, 6, 2) = '03';
← tomcat假死