跳转至

06. SQL 题目练习

为什么你必须写好SQL?

在我们工作中,无论是业务人员,还是开发人员,或是管理者,如今,几乎每个人都必须使用某种形式的数据,因为数据毕竟是信息的呈现,要获取信息必须得依赖数据,而这些数据通常是以电子表格或是数据库的形式存放。        

现状1:从业务人员视角来看,在企业里面,我们当前的现状就是,业务人员想要看哪些数据得依赖开发人员从数据库中提取数据,而这一过程需要漫长的等待,影响工作效率,如果我们懂简单的SQL,自己能从数据库提取数据,那么工作效率就会有大的提升,在同样的岗位中能够脱颖而出       

现状2:从数据分析师视角来看,习SQL几乎成为数分必备的技能,如果这个技能不达标,基本上很难通过面试,而且近几年SQL面试的题目也越来越难,要想通过面试几乎成为数据分析师必须且深度掌握的技能。      

现状3:从数据开发者角度来看,对于数据开发者来讲,典型的像数仓同学,基本天天与SQL打交道,这里其实与数据分析岗位有交叉的部分,对于SQL的掌握不言而喻。

SQL语法很简单,但几乎没几个人写的很好

这里不得不提国内语言的鄙视链,在大多数程序员眼里,他们认为SQL称不上一门语言,因为门槛太低,语法很简单就几个命令就能搞定,不需要专门学,或是成为一种岗位。有这种认识的往往都不是从事数据相关的人员,他们实际工作中使用SQL语言也很简单,就是简单的增删改查,甚至有时候面试问他们分组TOPN的问题都会难倒一大片,而对从事数据开发或数据分析师来讲,分组TOPN问题却很简单,这就是平时工作方向的不同带来的误区。不同的岗位有不同的工作方向和重点,我们不能以语言简单程度来区分岗位的优劣,或有鄙视心里,因为毕竟语言只是一种工具,而程序员最重要的还是逻辑思维能力,如果我拿语法比较简单的语言比如SQL去处理复杂的业务逻辑,其实未必就是一件简单的事情,他背后需要的是数据处理的逻辑思维及业务知识,其实此时SQL仅仅只是个工具。

在国外Data Science面试中,对SQL的考察,其实要求很高,很多公司要求必须熟练掌握SQL相关基础语法,并具备极强的数据处理思维逻辑,很多面试者也在SQL考察环节栽了跟头。在众多求职者中,我们分析其原因,这些求职者并不是不懂SQL语法,而是缺乏数据分析的思维能力,缺乏必要的实战技巧。甚至我们经常跟很多经验丰富数仓开发同学去聊,他们在用SQL解决实际业务问题时,都是这样的处理逻辑,遇到要分析的指标,先分析指标的含义,搞清楚逻辑及需要取数的源表后,就开始像套公式般找各种内置的函数去套,看看哪种函数能帮我解决业务问题,像极了某些语言开发者去寻找API的过程。但作为成熟的开发者来说,我们在处理数据问题或写代码时是这样吗?这里我们先打个问号,留给读者自己体会。倘若我们的业务逻辑稍微复杂些,套用函数或API套不动了怎么办?业务不做了吗?去跟业务撕逼吗?哈哈,我想办法总比困难多。这也就是我们所说的工作了好多年,你发现没几个人会把SQL写的很好,实际上呢?遇到复杂的业务逻辑或面试题也会凉凉。。。。。。当然实在不行了,我们也可以换语言实现嘛,总之办法总比困难多。最后,对于一个成熟的SQLer,不仅仅只是停留在实现业务逻辑的角度,更重要的一点还要从底层执行引擎的角度去理解SQL执行过程,看懂执行计划,并能写出性能较高的SQL。  

SQL题目练习

--创建表student
CREATE TABLE student(
    name VARCHAR(10),
    kecheng VARCHAR(10),
    fengshu INT
)

--插入数据到表student中
INSERT INTO student VALUES('张三','语文',81);
INSERT INTO student VALUES('张三','数学',75);
INSERT INTO student VALUES('李四','语文',76);
INSERT INTO student VALUES('李四','数学',90);
INSERT INTO student VALUES('王五','语文',81);
INSERT INTO student VALUES('王五','数学',100);
INSERT INTO student VALUES('王五','英语',90);


-- 查询出每门课都大于80分的学生姓名

-- 因为一个学生有多门课程,可能所有课程都大于80分,可能有些课程大于80分,另外一些课程少于80分,也可能所有课程都小于80分。
-- 那么我们要查找出所有大于80分的课程的学生姓名,我们可以反向思考,找出课程小于80分(可以找出有一些课程小于80分,所有课程小于80分的学生)的学生姓名再排除这些学生剩余的就是所有课程都大于80分的学生姓名了。 

SELECT DISTINCT name FROM student WHERE name NOT IN (SELECT DISTINCT name FROM student WHERE fengshu<=80);

/* not in */ 
SELECT DISTINCT A.name FROM student A WHERE A.name NOT IN(SELECT DISTINCT S.name FROM student S WHERE S.score <80);

/* not exists */ 
SELECT DISTINCT A.name FROM student A  WHERE NOT EXISTS (SELECT 1 FROM student S WHERE  S.score <80 AND S.name =A.name);

SQL案例题

-- 建库
CREATE DATABASE `emp`;

-- 打开库
USE emp;

-- 部门信息表(部门编号,部门名称,位置)
CREATE TABLE `dept`( 
    `deptno` INT(2) NOT NULL, 
    `dname` VARCHAR(14), 
    `loc` VARCHAR(13), 
    CONSTRAINT pk_dept PRIMARY KEY(deptno) 
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

-- 员工信息表(员工编号,员工姓名,工作职位,上级领导,入职日期,月薪,津贴,部门编号)
CREATE TABLE `emp` ( 
    `empno` INT(4) NOT NULL PRIMARY KEY, 
    `ename` VARCHAR(10), 
    `job` VARCHAR(9), 
    `mgr` INT(4), 
    `hiredate` DATE, 
    `sal` FLOAT(7,2), 
    `comm` FLOAT(7,2), 
    `deptno` INT(2), 
    CONSTRAINT fk_deptno FOREIGN KEY(deptno) REFERENCES dept(deptno) 
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

-- 薪水等级信息表(等级,最低薪水,最高薪水)
CREATE TABLE `salgrade` ( 
    `grade` INT, 
    `losal` INT, 
    `hisal` INT 
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;


-- 数据
INSERT INTO dept VALUES (10,'ACCOUNTING','NEW YORK'); 
INSERT INTO dept VALUES (20,'RESEARCH','DALLAS');
INSERT INTO dept VALUES (30,'SALES','CHICAGO'); 
INSERT INTO dept VALUES (40,'OPERATIONS','BOSTON');
INSERT INTO emp VALUES (7369,'SMITH','CLERK',7902,'1980-12-17',800,NULL,20); 
INSERT INTO emp VALUES (7499,'ALLEN','SALESMAN',7698,'1981-02-20',1600,300,30); 
INSERT INTO emp VALUES (7521,'WARD','SALESMAN',7698,'1981-02-22',1250,500,30); 
INSERT INTO emp VALUES (7566,'JONES','MANAGER',7839,'1981-04-02',2975,NULL,20);
INSERT INTO emp VALUES (7654,'MARTIN','SALESMAN',7698,'1981-09-28',1250,1400,30); 
INSERT INTO emp VALUES (7698,'BLAKE','MANAGER',7839,'1981-05-01',2850,NULL,30); 
INSERT INTO emp VALUES (7782,'CLARK','MANAGER',7839,'1981-06-09',2450,NULL,10); 
INSERT INTO emp VALUES (7788,'SCOTT','ANALYST',7566,'1987-07-13',3000,NULL,20); 
INSERT INTO emp VALUES (7839,'KING','PRESIDENT',NULL,'1981-11-07',5000,NULL,10); 
INSERT INTO emp VALUES(7844,'TURNER','SALESMAN',7698,'1981-09-08',1500,0,30); 
INSERT INTO emp VALUES (7876,'ADAMS','CLERK',7788,'1987-07-13',1100,NULL,20); 
INSERT INTO emp VALUES (7900,'JAMES','CLERK',7698,'1981-12-03',950,NULL,30); 
INSERT INTO emp VALUES (7902,'FORD','ANALYST',7566,'1981-12-03',3000,NULL,20); 
INSERT INTO emp VALUES (7934,'MILLER','CLERK',7782,'1982-01-23',1300,NULL,10);
INSERT INTO salgrade VALUES (1,700,1200); 
INSERT INTO salgrade VALUES (2,1201,1400); 
INSERT INTO salgrade VALUES (3,1401,2000); 
INSERT INTO salgrade VALUES (4,2001,3000); 
INSERT INTO salgrade VALUES (5,3001,9999);
-- 1. 列出与"SCOTT"从事相同工作的所有员工及部门名称。

-- 获取SCOTT的工作  
SELECT job FROM emp WHERE ename='SCOTT'

-- 关联部门表,获取部门名称,查出(员工,部门)    
SELECT e.ename, d.dname FROM emp e, dept d WHERE e.job =( SELECT job FROM emp WHERE ename = 'SCOTT' ) AND e.ename<>'SCOTT' AND e.deptno=d.deptno


-- 2. 列出公司各个工资等级雇员的数量、平均工资。
SELECT s.grade,count(*),avg(e.sal) FROM emp e LEFT JOIN salgrade s ON e.sal BETWEEN s.losal AND s.hisal GROUP BY s.grade ;

-- 3. 列出薪金高于在部门30工作的所有员工的薪金的员工姓名和薪金、部门名称。
SELECT ename,sal,d.dname,d.deptno FROM emp e LEFT JOIN dept d ON e.deptno = d.deptno WHERE e.sal > (SELECT max(sal) FROM emp WHERE deptno = 30);

-- 4. 列出在每个部门工作的员工数量、平均工资和平均服务期限。
SELECT count(*),avg(sal),avg(YEAR(now())-YEAR(hiredate)) FROM emp GROUP BY deptno;

-- 5. 列出所有员工的姓名、部门名称和工资。
SELECT e.ename,d.dname,e.sal FROM emp e LEFT JOIN dept d ON d.deptno = e.deptno;

-- 6. 列出所有部门的详细信息和部门人数
SELECT d.*,count(e.ename) FROM dept d LEFT JOIN emp e ON e.deptno = d.deptno GROUP BY d.deptno;

-- 7. 列出各种工作的最低工资及从事此工作的雇员姓名。
SELECT t.job ,a.ename , t.minsal FROM emp a LEFT JOIN (SELECT e.job AS job , min(e.sal) AS minsal FROM emp e GROUP BY e.job) t ON a.job = t.job;

-- 8. 列出各个部门的MANAGER(经理)的最低薪金、姓名、部门名称、部门人数。
SELECT a.mm,c.ename,c.job,b.dname,b.cc FROM (SELECT d.deptno,min(sal) mm FROM emp e LEFT JOIN dept d ON e.deptno = d.deptno WHERE job = 'MANAGER' GROUP BY deptno) a LEFT JOIN (SELECT d.deptno,d.dname,count(*) cc FROM emp e LEFT JOIN dept d ON e.deptno = d.deptno GROUP BY d.deptno) b ON a.deptno = b.deptno LEFT JOIN emp c ON c.sal = a.mm AND b.deptno = c.deptno ;

-- 9. 列出所有员工的年工资,所在部门名称,按年薪从低到高排序。
SELECT empno,ename,sal * 12 ,d.dname FROM emp LEFT JOIN dept d ON d.deptno = emp.deptno ORDER BY sal * 12 ASC;

-- 10. 查出某个员工的上级主管及所在部门名称,并要求出这些主管中的月薪超过3000

-- 11. 求出部门名称中,带"S"字符的部门员工的、工资合计、部门人数。

-- 12. 给任职日期超过30年或者在87年雇佣的雇员加薪,加薪原则:10部门增长10%,20部门增长20%, 30部门增长30%,依次类推。

-- 13. 列出至少有一个员工的所有部门的信息。
SELECT  DISTINCT d.* FROM dept d JOIN emp e ON d.deptno = e.deptno; 

-- 14. 列出月薪比JAMES低的所有员工。
SELECT * FROM emp WHERE sal < (SELECT sal FROM emp WHERE ename = 'JAMES')

-- 15. 列出所有员工的姓名以及其直接上级的姓名。
SELECT a.empno,a.ename AS 'e_name',b.ename AS 'm_name' FROM emp a LEFT JOIN emp b ON a.mgr = b.empno;

-- 16. 列出受雇日期早于其直接上级的所有员工的编号、姓名,部门名称。
-- 17. 列出部门名称和这些部门的员工信息,同时列出那些没有员工的部门。
-- 18. 列出所有"CLERK(职员)"的姓名以及部门名称,部门的人数。
-- 19. 列出最低薪金大于1500的各种工作以及从事此工作的全部雇员人数。
-- 20. 列出在部门"SALES"工作的员工的姓名,假定不知道销售部的部门编号。
-- 21. 列出薪金高于公司平均薪金的所有员工,所在部门,上级领导,公司的工资等级。
-- 22. 列出至少有一个员工的所有部门编号、名称,并统计出这些部门的平均工资、最低工资、最高工 资。
-- 23. 列出薪金比“SMITH”或“ALLEN”多的所有员工的编号、姓名、部门名称、其领导姓名。
-- 24. 列出所有员工的编号、姓名及其直接上级的编号、姓名,显示的结果按领导年工资的降序排列。
-- 25. 列出受雇日期早于其直接上级的所有员工的编号、姓名、部门名称、部门位置、部门人数。
-- 26. 列出部门名称和这些部门的员工信息(数量、平均工资),同时列出那些没有员工的部门。
-- 27. 列出所有“CLERK”(办事员)的姓名及其部门名称,部门的人数,工资等级。
-- 28. 列出最低薪金大于1500的各种工作及此从事此工作的全部雇员人数及所在部门名称、位置、平均工 资。
-- 29. 列出在部门“SALES”(销售部)工作的员工的姓名、基本工资、雇佣日期、部门名称,假定不知道 销售部的部门编号。
-- 30. 列出薪金高于公司平均薪金的所有员工,所在部门,上级领导,公司的工资等级。
-- 31. 列出与“SCOTT”从事相同工作的所有员工及部门名称,部门人数。
-- 32. 查询dept表的结构
-- 33. 检索emp表,用is a 这个字符串来连接员工姓名和工种两个字段
-- 34. 检索emp表中有提成的员工姓名、月收入及提成。
-- DDL

-- 学生表
-- Student(SId,Sname,Sage,Ssex)
-- SId 学生编号,Sname 学生姓名,Sage 出生年月,Ssex 学生性别

-- 课程表
-- Course(CId,Cname,TId)
-- CId 课程编号,Cname 课程名称,TId 教师编号

-- 教师表
-- Teacher(TId,Tname)
-- TId 教师编号,Tname 教师姓名

-- 成绩表
-- SC(SId,CId,score)
-- SId 学生编号,CId 课程编号,score 分数

CREATE TABLE Student(sid VARCHAR(10),sname VARCHAR(10),sage DATETIME,ssex nvarchar(10));  
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' , '女');  
CREATE TABLE Course(cid VARCHAR(10),cname VARCHAR(10),tid VARCHAR(10));  
INSERT INTO Course VALUES('01' , '语文' , '02');  
INSERT INTO Course VALUES('02' , '数学' , '01');  
INSERT INTO Course VALUES('03' , '英语' , '03');  
CREATE TABLE Teacher(tid VARCHAR(10),tname VARCHAR(10));  
INSERT INTO Teacher VALUES('01' , '张三');  
INSERT INTO Teacher VALUES('02' , '李四');  
INSERT INTO Teacher VALUES('03' , '王五');  
CREATE TABLE SC(sid VARCHAR(10),cid VARCHAR(10),score DECIMAL(18,1));  
INSERT INTO SC VALUES('01' , '01' , 80);  
INSERT INTO SC VALUES('01' , '02' , 90);  
INSERT INTO SC VALUES('01' , '03' , 99);  
INSERT INTO SC VALUES('02' , '01' , 70);  
INSERT INTO SC VALUES('02' , '02' , 60);  
INSERT INTO SC VALUES('02' , '03' , 80);  
INSERT INTO SC VALUES('03' , '01' , 80);  
INSERT INTO SC VALUES('03' , '02' , 80);  
INSERT INTO SC VALUES('03' , '03' , 80);  
INSERT INTO SC VALUES('04' , '01' , 50);  
INSERT INTO SC VALUES('04' , '02' , 30);  
INSERT INTO SC VALUES('04' , '03' , 20);  
INSERT INTO SC VALUES('05' , '01' , 76);  
INSERT INTO SC VALUES('05' , '02' , 87);  
INSERT INTO SC VALUES('06' , '01' , 31);  
INSERT INTO SC VALUES('06' , '03' , 34);  
INSERT INTO SC VALUES('07' , '02' , 89);  
INSERT INTO SC VALUES('07' , '03' , 98);



-- 1. 查询“01”课程比“02”课程成绩高的所有学生的学号;
SELECT DISTINCT t1.sid AS sidfrom   
    (SELECT * FROM sc WHERE cid='01')t1  
LEFT JOIN   
    (SELECT * FROM sc WHERE cid='02')t2  
ON t1.sid=t2.sid  
WHERE t1.score>t2.score

-- 2. 查询平均成绩大于60分的同学的学号和平均成绩;
SELECT   
    sid  
    ,avg(score)  
FROM sc  
GROUP BY sid  
HAVING avg(score)>60

-- 3. 查询所有同学的学号、姓名、选课数、总成绩
SELECT  
    student.sid AS sid  
    ,sname  
    ,count(DISTINCT cid) course_cnt  
    ,sum(score) AS total_score  
FROM student  
LEFT JOIN sc  
ON student.sid=sc.sid  
GROUP BY sid,sname

-- 4. 查询姓“李”的老师的个数;
SELECT  
    count(DISTINCT tid) AS teacher_cnt  
FROM teacher  
WHERE tname LIKE '李%'

-- 5. 查询没学过“张三”老师课的同学的学号、姓名;
SELECT  
    sid,sname  
FROM student  
WHERE sid NOT IN   
    (  
        SELECT  
            sc.sid  
        FROM teacher  
        LEFT JOIN course  
            ON teacher.tid=course.tid  
        LEFT JOIN sc  
            ON course.cid=sc.cid  
        WHERE teacher.tname='张三'  
    )

-- 6. 查询学过“01”并且也学过编号“02”课程的同学的学号、姓名;
SELECT  
    t.sid AS sid  
    ,sname  
FROM   
    (  
        SELECT  
            sid  
            ,count(IF(cid='01',score,NULL)) AS count1  
            ,count(IF(cid='02',score,NULL)) AS count2  
        FROM sc  
        GROUP BY sid  
        HAVING count(IF(cid='01',score,NULL))>0 AND count(IF(cid='02',score,NULL))>0  
    )t  
LEFT JOIN student  
    ON t.sid=student.sid

-- 7. 查询学过“张三”老师所教的课的同学的学号、姓名;
SELECT  
    student.sid  
    ,sname  
FROM   
    (  
        SELECT  
            DISTINCT cid   
        FROM course  
        LEFT JOIN teacher   
        ON course.tid=teacher.tid  
        WHERE teacher.tname='张三'  
    )course  
LEFT JOIN sc   
    ON course.cid=sc.cid  
LEFT JOIN student  
    ON sc.sid=student.sid  
GROUP BY student.sid,sname

-- 8. 查询课程编号“01”的成绩比课程编号“02”课程低的所有同学的学号、姓名;
SELECT  
    t1.sid,sname  
FROM   
    (  
        SELECT DISTINCT t1.sid AS sid  
        FROM   
            (SELECT * FROM sc WHERE cid='01')t1  
        LEFT JOIN   
            (SELECT * FROM sc WHERE cid='02')t2  
        ON t1.sid=t2.sid  
        WHERE t1.score>t2.score  
    )t1  
LEFT JOIN student  
    ON t1.sid=student.sid

-- 9. 查询所有课程成绩小于60分的同学的学号、姓名;
SELECT  
    t1.sid,sname  
FROM   
    (  
        SELECT  
            sid,max(score)  
        FROM sc  
        GROUP BY sid  
        HAVING max(score<60)  
    )t1  
LEFT JOIN student  
    ON t1.sid=student.sid

-- 10. 查询没有学全所有课的同学的学号、姓名;
SELECT  
    t1.sid,sname  
FROM   
    (  
        SELECT  
            count(cid),sid  
        FROM sc  
        GROUP BY sid  
        HAVING count(cid) < (SELECT count(DISTINCT cid) FROM course)  
    )t1  
LEFT JOIN student  
    ON t1.sid=student.sid

-- 11. 查询至少有一门课与学号为“01”的同学所学相同的同学的学号和姓名;
SELECT  
    DISTINCT sc.sid  
FROM   
    (  
        SELECT  
            cid  
        FROM sc  
        WHERE sid='01'  
    )t1  
LEFT JOIN sc  
    ON t1.cid=sc.cid

-- 12. 查询和"01"号的同学学习的课程完全相同的其他同学的学号和姓名
#注意是和'01'号同学课程完全相同但非学习课程数相同的,这里我用左连接解决这个问题select  
    t1.sid,sname  
FROM  
    (  
        SELECT  
            sc.sid  
            ,count(DISTINCT sc.cid)  
        FROM   
            (  
                SELECT  
                    cid  
                FROM sc  
                WHERE sid='01'  
            )t1 #选出01的同学所学的课程  
        LEFT JOIN sc  
            ON t1.cid=sc.cid  
        GROUP BY sc.sid  
        HAVING count(DISTINCT sc.cid)= (SELECT count(DISTINCT cid) FROM sc WHERE sid = '01')  
    )t1  
LEFT JOIN student  
    ON t1.sid=student.sid  
WHERE t1.sid!='01'

-- 13. 把“SC”表中“张三”老师教的课的成绩都更改为此课程的平均成绩;
-- 暂跳过update题目


-- 14. 查询没学过"张三"老师讲授的任一门课程的学生姓名
SELECT   
    sname  
FROM student  
WHERE sid NOT IN  
    (  
        SELECT  
            DISTINCT sid  
        FROM sc  
        LEFT JOIN course  
            ON sc.cid=course.cid  
        LEFT JOIN teacher  
            ON course.tid=teacher.tid   
        WHERE tname='张三'  
    )

-- 15. 查询两门及其以上不及格课程的同学的学号,姓名及其平均成绩
SELECT  
    t1.sid,sname,avg_score  
FROM   
    (  
        SELECT  
            sid,count(IF(score<60,cid,NULL)),avg(score) AS avg_score  
        FROM sc  
        GROUP BY sid  
        HAVING count(IF(score<60,cid,NULL)) >=2  
    )t1  
LEFT JOIN student  
    ON t1.sid=student.sid

-- 16. 检索"01"课程分数小于60,按分数降序排列的学生信息
SELECT   
    sid,IF(cid='01',score,100)FROM sc  
WHERE IF(cid='01',score,100)<60  
ORDER BY IF(cid='01',score,100) DESC

-- 17. 按平均成绩从高到低显示所有学生的平均成绩
SELECT sid,avg(score)  
FROM sc  
GROUP BY sid  
ORDER BY avg(score) DESC

-- 18. 查询各科成绩最高分、最低分和平均分:以如下形式显示:课程ID,课程name,最高分,最低分,平均分,及格率
SELECT  
    sc.cid  
    ,cname  
    ,max(score) AS max_score  
    ,min(score) AS min_score  
    ,avg(score) AS avg_score  
    ,count(IF(score>=60,sid,NULL))/count(sid) AS pass_rate  
 FROM sc   
 LEFT JOIN course  
    ON sc.cid=course.cid  
 GROUP BY sc.cid

-- 19. 按各科平均成绩从低到高和及格率的百分数从高到低顺序
#这里先按照平均成绩排序,再按照及格百分数排序,  
SELECT   
    cid  
    ,avg(score) AS avg_score  
    ,count(IF(score>=60,sid,NULL))/count(sid) AS pass_rate  
FROM sc  
GROUP BY cid  
ORDER BY avg_score,pass_rate DESC

-- 20. 查询学生的总成绩并进行排名
SELECT  
    sid  
    ,sum(score) AS sum_score  
FROM sc  
GROUP BY sid  
ORDER BY sum_score DESC

-- 21. 查询不同老师所教不同课程平均分从高到低显示
SELECT  
    tid  
    ,avg(score) AS avg_score  
FROM course  
LEFT JOIN sc  
    ON course.cid=sc.cid  
GROUP BY tid  
ORDER BY avg_score DESC

-- 22. 查询所有课程的成绩第2名到第3名的学生信息及该课程成绩
SELECT  
    sid,rank_num,score,cid  
FROM  
    (  
        SELECT  
            rank() OVER(PARTITION BY cid ORDER BY score DESC) AS rank_num  
            ,sid  
            ,score  
            ,cid  
        FROM sc  
    )t  
WHERE rank_num IN (2,3)

-- 23. 统计各科成绩各分数段人数:课程编号,课程名称,[100-85],[85-70],[70-60],[0-60]及所占百分比
SELECT  
    sc.cid  
    ,cname  
    ,count(IF(score BETWEEN 85 AND 100,sid,NULL))/count(sid)  
    ,count(IF(score BETWEEN 70 AND 85,sid,NULL))/count(sid)  
    ,count(IF(score BETWEEN 60 AND 70,sid,NULL))/count(sid)  
    ,count(IF(score BETWEEN 0 AND 60,sid,NULL))/count(sid)  
FROM sc  
LEFT JOIN course  
    ON sc.cid=course.cid  
GROUP BY sc.cid,cname

-- 24. 查询学生平均成绩及其名次
SELECT  
    sid  
    ,avg_score  
    ,rank() OVER (ORDER BY avg_score DESC)  
FROM   
    (  
        SELECT  
            sid  
            ,avg(score) AS avg_score  
        FROM sc  
        GROUP BY sid  
    )t

-- 25. 查询各科成绩前三名的记录
SELECT  
    sid,cid,rank1from   
    (  
        SELECT  
            cid  
            ,sid  
            ,rank() OVER(PARTITION BY cid ORDER BY score DESC) AS rank1  
        FROM sc  
    )twhere rank1<=3

-- 26. 查询每门课程被选修的学生数
SELECT  
    count(sid)  
    ,cid  
FROM sc  
GROUP BY cid

-- 27. 查询出只选修了一门课程的全部学生的学号
SELECT  
    sid  
FROM sc  
GROUP BY sid  
HAVING count(cid) =1

-- 28. 查询男生、女生人数
SELECT  
    ssex  
    ,count(DISTINCT sid)  
FROM student          
GROUP BY ssex

-- 29. 查询名字中含有"风"字的学生信息
SELECT  
    sid,sname  
FROM student  
WHERE sname LIKE '%风%'

-- 30. 查询同名同性学生名单,并统计同名人数
SELECT  
    ssex  
    ,sname  
    ,count(sid)  
FROM student  
GROUP BY ssex,sname  
HAVING count(sid)>=2

-- 31. 查询1990年出生的学生名单(注:Student表中Sage列的类型是datetime)
SELECT  
    sid,sname,sage  
FROM student  
WHERE YEAR(sage)=1990

-- 32. 查询每门课程的平均成绩,结果按平均成绩升序排列,平均成绩相同时,按课程号降序排列
SELECT  
    cid,avg(score) AS avg_score  
FROM sc  
GROUP BY cid  
ORDER BY avg_score,cid DESC

-- 33. 查询不及格的课程,并按课程号从大到小排列
SELECT  
    cid,sid,score  
FROM sc  
WHERE score<60  
ORDER BY cid DESC,sid

-- 34. 查询课程编号为"01"且课程成绩在60分以上的学生的学号和姓名;
SELECT  
    sid,cid,score  
FROM sc  
WHERE cid='01' AND score>60

-- 35. 查询选修“张三”老师所授课程的学生中,成绩最高的学生姓名及其成绩
SELECT  
    sc.sid,sname,cname,score  
FROM sc  
LEFT JOIN course  
    style="font-weight: 600;">=course.cid  
LEFT JOIN teacher  
    style="font-weight: 600;">=teacher.tid  
LEFT JOIN student  
    style="font-weight: 600;">=student.sid  
WHERE tname='张三'  
ORDER BY score DESC  
LIMIT 1;

-- 36. 查询每门功课成绩最好的前两名
SELECT  
    cid,sid,rank1  
FROM   
    (  
        SELECT  
            cid  
            ,sid  
            ,rank() OVER(PARTITION BY cid ORDER BY score DESC) AS rank1  
        FROM sc   
    )t  
WHERE rank1 <=2

-- 37. 统计每门课程的学生选修人数(超过5人的课程才统计)。要求输出课程号和选修人数,查询结果按人数降序排列,若人数相同,按课程号升序排列
SELECT  
    cid  
    ,count(sid) AS cnt  
FROM sc  
GROUP BY cid  
HAVING cnt>=5  
ORDER BY count(sid) DESC,cid

-- 38. 检索至少选修两门课程的学生学号
SELECT  
    sid  
    ,count(cid)  
FROM sc  
GROUP BY sid  
HAVING count(cid)>=2

-- 39. 查询选修了全部课程的学生信息
SELECT  
    sid  
    ,count(cid)  
FROM sc  
GROUP BY sid  
HAVING count(cid)=(SELECT count(DISTINCT cid) FROM sc)

-- 40. 查询各学生的年龄
SELECT  
    sid,sname,YEAR(curdate())-YEAR(sage) AS sage  
FROM student

-- 41. 查询本周过生日的学生
SELECT  
    sid,sname,sage  
FROM student  
WHERE weekofyear(sage)=weekofyear(curdate())

-- 42. 查询下周过生日的学生
SELECT   
    sid,sname,sage  
FROM student  
WHERE weekofyear(sage) = weekofyear(date_add(curdate(),interval 1 week))

-- 43 查询本月过生日的学生
SELECT  
    sid,sname,sage  
FROM student  
WHERE month(sage) = month(curdate())

-- 44. 查询下月过生日的学生
SELECT  
    sid,sname,sage  
FROM student  
WHERE month(date_sub(sage,interval 1 month)) = month(curdate())