• sql语句练习题 50题


    在网上搜索sql练习题,参考借鉴了https://blog.csdn.net/fashion2014/article/details/78826299

    所有的题我都自己做了一遍,敲过了一遍,代码方面应该是没有问题的。

    做完之后,对连接,分组,逆向思维,有了更深刻的认识,同时还学到了case语法,关于时间的函数,以及排名的实现

    有的语句可能写的比较累赘麻烦,这里是为了练习,就不要在意这些了

     有很多题目,例如算平均数的地方都是有些争议,例如学生压根没选其中某门课,算平均分是按学生自己选的课程,还是按所有的课程数目,这个就看大家怎么去理解。

    表结构以及表数据

      -- 学生编号,学生姓名, 出生年月,学生性别
    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`)
    );
    -- 学生编号,课程编号,分数`course`
    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);

    -------------------------------------------------------------------------------------------------

    -- 1、查询"01"课程比"02"课程成绩高的学生的信息及课程分数

    /*(题目说的不清楚,假使这里要查的学生信息只有学生编号,学生姓名,课程分数由于比较的是01和02,只展示01课程和02课程的分数) */

    SELECT
    t1.`s_id`,
    t1.`s_name`,
    t2.`s_score` AS 01course,
    t3.`s_score` AS 02course
    FROM  Student t1 ,Score t2,Score t3
    WHERE t1.`s_id`=t2.`s_id`
    AND   t1.`s_id`=t3.`s_id`
    AND   t2.`c_id`='01'
    AND   t3.`c_id`='02'
    AND   t2.`s_score`>t3.`s_score`;

    /*上面是隐式内连接的写法,把几张表连起来用where筛选,下面是先显式内连接再外连接*/

    SELECT
    t1.`s_id`,t1.`s_name`,
    t2.`s_score` AS 01course,
    t3.`s_score` AS 02course
    FROM Student t1 
    JOIN Score t2 ON t1.`s_id` =t2.`s_id` AND t2.`c_id`='01'
    LEFT JOIN Score t3 ON t1.`s_id`=t3.`s_id` AND t3.`c_id`='02' WHERE t2.`s_score`>t3.`s_score` ;

    为了方便好理解这个,拆开看下每步求得是什么

     

     

     

     如果不加where的比较大小判断

     

     这样就是有选了课程1的学生,去左连选了课程2的学生。出来的结果就是只选了课程1的学生(例如图中的吴兰)和同时选了01,02课程的学生。原作者在And t3.c_id='02'多加了or  t3.c_id is null,这里我也不清楚为什么要这么写,而且不写的结果也是选了01的和同时选了0102的。

    /*第三种写法,采用子查询的方式,大体上也是先分开筛选01,02的,不过感觉写的有点重复,这里是练习,就不在意这些了*/

    SELECT  t1.`s_id`,t1.`s_name`, 
    t2.`s_score` AS 01course,
    t3.s_score AS 02Course
    FROM Student t1,(SELECT s1.`s_id` ,s1.`s_score` FROM Score s1 WHERE s1.`c_id`='01' ) t2,
    (SELECT s2.`s_id`,s2.`s_score` FROM Score s2 WHERE s2.`c_id`='02') t3
    WHERE  t1.`s_id`=t2.s_id AND t1.`s_id`=t3.s_id AND t2.s_score>t3.s_score;

    -------------------------------------------------------------------------------------------------

    -- 2、查询"01"课程比"02"课程成绩低的学生的信息及课程分数

    /*这个跟第一题一样,改变下比较的符号就行了*/

    SELECT
    t1.`s_id`,
    t1.`s_name`,
    t2.`s_score` AS 01course,
    t3.`s_score` AS 02course
    FROM  Student t1 ,Score t2,Score t3
    WHERE t1.`s_id`=t2.`s_id`
    AND   t1.`s_id`=t3.`s_id`
    AND   t2.`c_id`='01'
    AND   t3.`c_id`='02'
    AND   t2.`s_score`<t3.`s_score`;
    -- ------------------
    SELECT
    t1.`s_id`,t1.`s_name`,
    t2.`s_score` AS 01course,
    t3.`s_score` AS 02course;
    FROM Student t1 
    JOIN Score t2 ON t1.`s_id` =t2.`s_id` AND t2.`c_id`='01'
    LEFT JOIN Score t3 ON t1.`s_id`=t3.`s_id` AND t3.`c_id`='02' 
    WHERE t2.`s_score`<t3.`s_score` ;
    -- ------------------
    SELECT  t1.`s_id`,t1.`s_name`, 
    t2.`s_score` AS 01course,
    t3.s_score AS 02Course
    FROM Student t1,(SELECT s1.`s_id` ,s1.`s_score` FROM Score s1 WHERE s1.`c_id`='01' ) t2,
    (SELECT s2.`s_id`,s2.`s_score` FROM Score s2 WHERE s2.`c_id`='02') t3
    WHERE  t1.`s_id`=t2.s_id AND t1.`s_id`=t3.s_id AND t2.s_score<t3.s_score;

    -- 3、查询平均成绩大于等于60分的同学的学生编号和学生姓名和平均成绩

    这个题考的是分组,我们先只查学生的id和学生平均成绩大于60的,只在score表上做操作。注意分组后再加筛选条件用having

     SELECT  
     t1.`s_id`,
     AVG(t1.`s_score`) AS avgnumber  
     FROM score t1
     GROUP BY t1.`s_id`
     HAVING AVG(t1.`s_score`)>60;

    然后我们再将其和学生表联系起来

     SELECT
     t1.`s_id`,
     t1.`s_name`,
     AVG(t2.`s_score`) AS avgnumber
     FROM Student t1,Score t2 
     WHERE t1.`s_id`=t2.`s_id`
     GROUP BY t2.`s_id`
     HAVING AVG(t2.`s_score`)>60;

    结果如下

     

     下面是原作者的,原作者用了保留小数精确度的函数,。然后分组条件那里我觉得写一个就行,毕竟学生id和学生姓名是一一对应关系。

    SELECT b.s_id,b.s_name,ROUND(AVG(a.s_score),2) AS avg_score FROM 
        student b 
        JOIN score a ON b.s_id = a.s_id
        GROUP BY b.s_id,b.s_name HAVING avg_score >=60;

    --  5、查询所有同学的学生编号、学生姓名、选课总数、所有课程的总成绩

    这道题我原本用的内连接,但是用内连接展示的只能是符合条件两表都有的数据。有个数据只在学生表有,但是score表没他的课程和分数记录

    SELECT 
    t1.`s_id`,t1.`s_name`,
    COUNT(t2.`c_id`) AS CourseSum,
    SUM(t2.`s_score`) AS ScoreSum
    FROM Student t1 ,Score t2 
    WHERE t1.`s_id`=t2.`s_id`
    GROUP BY t2.`s_id` ;

     

     没有学生王菊的数据,于是采用外连接的方法,除去符合条件的,还包括单表独有的

    SELECT 
    t1.`s_id`,t1.`s_name`,
    IFNULL(COUNT(t2.`c_id`),0)  AS CourseSum,
    IFNULL(SUM(t2.`s_score`),0) AS ScoreSum  
    FROM student t1 LEFT JOIN score t2
    ON t1.`s_id`=t2.`s_id` GROUP BY t2.`s_id`;

     

     -- 6、查询"李"姓老师的数量

    SELECT
    COUNT(t1.t_id)
    FROM (SELECT teacher.`t_id` FROM teacher  WHERE teacher.`t_name` LIKE '李%') t1 ;
    SELECT COUNT(t_id) FROM teacher WHERE t_name LIKE '李%';

    -- 7、查询学过"张三"老师授课的同学的信息 

    /*方式一:通过内连接的方式把4张表连起来,加上筛选条件,比较好理解*/

    SELECT 
    t1.`s_id`,t1.`s_name`
    FROM student t1,course t2,teacher t3,score t4
    WHERE t3.`t_name`='张三'
    AND t3.`t_id`=t2.`t_id`
    AND t2.`c_id`=t4.`c_id`
    AND t4.`s_id`=t1.`s_id`;

    /*方式二:通过子查询的方式,先根据课程表和老师表选出张三老师教的课程编号,然后在成绩表里去匹配这些编号,进而得到学生信息*/

    SELECT 
    a.`s_id`,a.`s_name`
    FROM  student a JOIN score b 
    ON a.`s_id`=b.`s_id`
    WHERE b.`c_id` IN
    (SELECT  
    c.`c_id`
    FROM course c JOIN teacher d
    ON c.`t_id`=d.`t_id`
    WHERE d.`t_name`='张三'
    );

    /*原作者方式:连续子查询,先求出张三老师的老师编号,根据老师编号找到课程编号,再去score中根据课程编号找到学生的信息*/

    SELECT a.*
    FROM student a 
    JOIN score b ON a.s_id=b.s_id 
    WHERE b.c_id IN(
            SELECT c_id 
            FROM course 
            WHERE t_id =(
                SELECT t_id 
                FROM teacher 
                WHERE t_name = '张三'));

    -- 8、查询没学过"张三"老师授课的同学的信息 

    /*方式一:由于上题以及知道了学过张三老师的同学信息,那么就把上题作为一个子查询用进来,所有学生的信息,使用not in,如果学生id不在张三课程学生的id里,即为没学过的*/

    SELECT 
    e.`s_id`,e.`s_name`
    FROM student e
    WHERE e.`s_id` NOT IN
    (
    SELECT 
    a.`s_id`
    FROM  student a JOIN score b 
    ON a.`s_id`=b.`s_id`
    WHERE b.`c_id` IN
    (SELECT  
    c.`c_id`
    FROM course c JOIN teacher d
    ON c.`t_id`=d.`t_id`
    WHERE d.`t_name`='张三'
    )
    )

    /*方式二:与方式一相同,不过排除方式是使用left join  ,并且连接条件加上右表 为null,这样即是左表独有的数据*/ 

    SELECT 
    e.`s_id`,e.`s_name`
    FROM student e
    LEFT JOIN 
    (
    SELECT 
    a.`s_id`
    FROM  student a JOIN score b 
    ON a.`s_id`=b.`s_id`
    WHERE b.`c_id` IN
    (SELECT  
    c.`c_id`
    FROM course c JOIN teacher d
    ON c.`t_id`=d.`t_id`
    WHERE d.`t_name`='张三'
    )
    ) g ON e.`s_id`=g.`s_id` WHERE g.`s_id` IS NULL ;

    /*方式三:连续子查询,根据老师姓名查老师id,根据老师id查课程id,根据课程id查学生id,再排除*/

    SELECT 
    a.`s_id`,a.`s_name`
    FROM student a
    WHERE a.`s_id` NOT IN(
      SELECT  b.`s_id`
      FROM student b ,score c WHERE b.`s_id`=c.`s_id` AND c.`c_id` IN(
            SELECT  d.`c_id`
            FROM course d
            WHERE d.`t_id` IN(
                 SELECT  teacher.`t_id`
                 FROM teacher  
                 WHERE   teacher.`t_name`='张三'        
            )
    )
    )

     --  9 、查询学过编号为"01"并且也学过编号为"02"的课程的同学的信息

    /*方式一:形式上复杂点,但是很好理解,学生表单独和分数表去显式内连接两次,两次的筛选条件分别是课程号为01,02.然后形成的两个结果集再显示内连接下, 连接条件即是同时选了01,02的,因为是同时,所以最外面的s_id和s_name写前面的还是后面的都无所谓*/

    SELECT t5.s_id,t5.s_name FROM
    (SELECT 
    t1.`s_id`, t1.`s_name`
    FROM student t1 JOIN  score t2
    ON t1.`s_id`=t2.`s_id`
    WHERE t2.`c_id` ='01') t6
    JOIN (SELECT t3.`s_id`,t3.`s_name`
          FROM student t3 JOIN score t4
          ON t3.`s_id`=t4.`s_id`
          WHERE t4.`c_id`='02') t5 ON t5.`s_id`=t6.`s_id`;

    /*方式二:与上面是一个思路,只不过第一次先显式内连接求选了01的学生信息,后面则直接和分数表再内连接,因为同时选了0102的,那么选了01的学生必定在分数表里同时找到02的记录,所以后面直接连分数表,没有像上面连结果集*/

    SELECT t3.s_id,t3.s_name 
    FROM
    (SELECT 
    t1.`s_id`, t1.`s_name`
    FROM student t1 JOIN  score t2
    ON t1.`s_id`=t2.`s_id`
    WHERE t2.`c_id` ='01') t3
    JOIN score t4 ON t3.s_id=t4.`s_id` AND t4.`c_id`='02'  ;

    /*方式三:采用隐式内连接,where 加and把几个连接条件和筛选条件全写上,比较好理解*/

    SELECT 
    t1.`s_id`,t1.`s_name`
    FROM student t1,score t2,score t3
    WHERE t1.`s_id`=t2.`s_id` 
    AND t2.`c_id`='01' 
    AND t1.`s_id`=t3.`s_id` 
    AND t3.`c_id`='02' 

    -- 10、查询学过编号为"01"但是没有学过编号为"02"的课程的同学的信息

    /*方式一:先找出修了01的学生信息,然后找出修了02的学生的信息,not in排除*/

     SELECT     
     t1.`s_id`,t1.`s_name`
     FROM student t1
     JOIN score t2 ON t1.`s_id`=t2.`s_id` 
     WHERE t2.`c_id`='01' AND t1.`s_id` NOT IN
     (
    SELECT  t4.`s_id`
    FROM student t4
    JOIN score t5 ON t4.`s_id`=t5.`s_id`
    WHERE t5.`c_id`='02'  
     ) ;

    /*方式二:先找出修了01的学生信息,然后直接通过score表找修了02课程的学生信息,因为分数表有学生id,不需要像第一种去做连接*/

     SELECT 
     t1.`s_id`,t1.`s_name`
     FROM  student t1
     WHERE t1.`s_id` 
     IN(
       SELECT  t2.`s_id`
       FROM student t2,score t3
       WHERE t2.`s_id`=t3.`s_id`
       AND t3.`c_id`='01'
       AND t2.`s_id` NOT IN (
          SELECT  t4.`s_id`
          FROM score t4 WHERE t4.`c_id`='02'     
       )
     )

    /*方式三:先显式内连接,分别找出修了01,02的,然后两个结果集再左外连接,排除公共的,即令两个集合连接时右边的条件为null,这样就剩下左边独有的*/

    SELECT t3.s_id,t3.s_name
    FROM 
     (SELECT     
     t1.`s_id`,t1.`s_name`
     FROM student t1
     JOIN score t2 ON t1.`s_id`=t2.`s_id` 
     WHERE t2.`c_id`='01' ) t3
     LEFT JOIN (
    SELECT t4.`s_id`,t4.`s_name`
    FROM student t4 JOIN score t5
     ON t4.`s_id`=t5.`s_id`
     WHERE t5.`c_id`='02' 
     ) t6 ON t3.s_id=t6.s_id WHERE t6.s_id IS NULL;

    /*方式四:原作者提供,查找是否学习0201课程的时候先不用与学生表关联,只需排除,得到学号,最后再从学生表查找学生信息,这里是在练习,所以各种写法都尝试着写写*/

     SELECT a.* FROM 
        student a 
        WHERE a.s_id IN (SELECT s_id FROM score WHERE c_id='01' ) AND a.s_id NOT IN(SELECT s_id FROM score WHERE c_id='02')

     -- 11、查询没有学全所有课程的同学的信息 

    /*方式一:连接分组,计算课程的数目是否小于课程表的数目,因为包括一门课都没选的,所以要用左连*/

    SELECT 
    t1.`s_id`,t1.`s_name`,COUNT(t2.c_id)
    FROM student t1 LEFT JOIN score t2
    ON t1.`s_id`=t2.s_id GROUP BY t1.`s_id`
    HAVING COUNT(t2.c_id)<(SELECT COUNT(t3.`c_id`) FROM course t3 )

    /*方式二:先单表分组,找出学全了课程的学生id,然后利用学生表去筛选下,和上面是两种思维*/

    SELECT 
    t1.`s_id`,t1.`s_name`
    FROM student t1 WHERE t1.`s_id` NOT IN
    (
    SELECT    t2.`s_id`
    FROM score t2 GROUP BY t2.`s_id` HAVING COUNT(t2.`c_id`)=(SELECT COUNT(t3.c_id)FROM course t3)
    )

    -- 12、查询至少有一门课与学号为"01"的同学所学相同的同学的信息

    /*方式一:先找出01同学学的课程,两表连接,除去01同学本身,*/

    SELECT 
    DISTINCT  t2.`s_id`,  t2.`s_name`
    FROM student t2,score t3
    WHERE t2.`s_id`=t3.`s_id`
    AND t2.`s_id`!='01' AND t3.`c_id` IN(
    SELECT t1.`c_id`
    FROM score  t1 WHERE t1.`s_id`='01' ) ;

    /*方式二:连续子查询*/

     SELECT t1.`s_id`,t1.`s_name`
     FROM student t1 
     WHERE t1.`s_id`!='01' AND t1.`s_id` IN(
                      SELECT  t2.`s_id` FROM score t2 WHERE t2.`c_id` IN
                       (
                       SELECT t3.`c_id` FROM score t3 WHERE t3.`s_id`='01'
                       ) 
     )  ;

    -- 13、查询和"01"号的同学学习的课程完全相同的其他同学的信息

    这个题也是想了很久,一开始想的思路是,在学生表和分数表连接后用in(01学过的课程)然后加个分组判断下数目和01学过课程数相同的,但这种是不对的,例如01学了abc,02学了acd,02有一门课程在01学过的名单里,这就被记录上了,但其实他们的课程不完全相同。

    后来想到了在判断课程数的条件下,利用双重否定,即not in(01学过的课程),这里也不用像in一样纠结是满足一个还是全部之类的问题,只要学生有一门课程不在01的课程id集合里,就一定会被记录的。然后再正常的连接,加条件,学生不在(学过01同学没学过课程的学生集合),而且加上了与01课程数相同的条件,这样求出来的就是与01完全一样的课程的同学

    思路分解

    -- 01号同学的课程数量 
     SELECT COUNT(t1.`c_id`)FROM  score t1 WHERE t1.`s_id`='01';
    -- 01同学所选课程的id
     SELECT  t1.`c_id` FROM score t1 WHERE t1.`s_id`='01';
    -- 课程与01同学有不同的同学的id,有一门即会被记录
     SELECT  t2.`s_id`  FROM score t2 WHERE t2.`c_id` NOT IN( SELECT  t1.`c_id` FROM score t1 WHERE t1.`s_id`='01');

    解答

    SELECT  t3.`s_id`,t3.`s_name`
    FROM  student t3 JOIN score t4
    ON t3.`s_id`=t4.`s_id` 
    WHERE t4.`s_id`!=01
    AND t4.`s_id` NOT IN
    (SELECT  t2.`s_id`  FROM score t2 WHERE t2.`c_id` NOT IN( SELECT  t1.`c_id` FROM score t1 WHERE t1.`s_id`='01')
    ) 
    GROUP BY t4.`s_id` 
    HAVING COUNT(t4.`c_id`)=(SELECT COUNT(t1.`c_id`)FROM  score t1 WHERE t1.`s_id`='01');

    /*方式二:来源原作者文章,供大家参考,也是利用的双重否定*/

    SELECT
     Student.*
    FROM
     Student
    WHERE
     s_id IN (SELECT s_id FROM Score GROUP BY s_id HAVING COUNT(s_id) = (
        SELECT COUNT(c_id) FROM Score WHERE s_id = '01'
       )
     )
    AND s_id NOT IN (
     SELECT s_id FROM Score
     WHERE c_id IN(
       SELECT DISTINCT c_id FROM Score
       WHERE c_id NOT IN (
         SELECT c_id FROM Score WHERE s_id = '01'
        )
      ) GROUP BY s_id
    ) 
    AND s_id NOT IN ('01')

    /*方式三:来源原作者文章,供大家参考*/

    SELECT
     t3.*
    FROM
     (
      SELECT
       s_id,
       GROUP_CONCAT(c_id ORDER BY c_id) group1
      FROM
       score
      WHERE
       s_id &lt;> '01'
      GROUP BY
       s_id
     ) t1
    INNER JOIN (
     SELECT
      GROUP_CONCAT(c_id ORDER BY c_id) group2
     FROM
      score
     WHERE
      s_id = '01'
     GROUP BY
      s_id
    ) t2 ON t1.group1 = t2.group2
    INNER JOIN student t3 ON t1.s_id = t3.s_id

    -- 14查询没学过张三老师讲授的任何一门课的学生姓名

    /*根据课程表和教师表找出张三教的课程的集合,然后通过分数表找出学了张三课程的学生,最后再用学生表not in排除*/

    SELECT s1.`s_id`,s1.`s_name`
    FROM  student  s1 WHERE s1.`s_id`
    NOT IN(
    SELECT t4.`s_id`
    FROM  score t4
    WHERE  t4.`c_id`  IN(
        SELECT t2.`c_id`
        FROM teacher t1,course t2
        WHERE t1.`t_id`=t2.`t_id`
        AND t1.`t_name`='张三' 
    ))

    -- 15、查询两名及其以上不及格课程同学的学号,姓名,及平均成绩

    /*方式一:连接分组的同时,把分数限制加上,分组后把符合条件的行筛出来,考的知识点就是count里不能写判断条件,count(*)算行数*/

    
    SELECT    t1.`s_id`,t1.`s_name` ,SUM(t2.`s_score`)/COUNT(t2.`c_id`) AS avgnumber
    FROM student t1,score t2
    WHERE
    t1.`s_id`=t2.`s_id`
    AND t2.s_score<60
    GROUP BY t2.`s_id`
    HAVING  COUNT(*)>=2

    /*方式二:先找出两门没及格的学生id,再连接表*/

    SELECT t2.`s_id`,t2.`s_name`,SUM(t3.`s_score`)/COUNT(t3.`c_id`) AS avgnumber
    FROM student t2,score t3
    WHERE t2.`s_id`=t3.`s_id`
    AND t3.`s_id` IN(
    SELECT  t1.`s_id`
    FROM score t1 WHERE t1.`s_score`<60 GROUP BY t1.`s_id` HAVING COUNT(*)>=2
    )
    GROUP BY t2.s_id

    -- 16、检索"01"课程分数小于60,按分数降序排列的学生信息

    SELECT t1.`s_id`,t1.`s_name`,t2.`s_score`
    FROM student t1,score t2
    WHERE t1.`s_id`=t2.`s_id`
    AND t2.`s_score`<60
    AND t2.`c_id`='01'
    ORDER BY t2.`s_score` DESC ;

     -- 17、按平均成绩从高到低显示所有学生的所有课程的成绩以及平均成绩

    /*如果要带上一门课都没选的学生,连接处改为左连接*/

    SELECT  t1.`s_id`,t1.`s_name`,(SELECT  t3.`s_score`  FROM score t3 WHERE t3.s_id=t2.`s_id`  AND t3.`c_id`='01') AS 语文,       
                                  (SELECT  t4.s_score    FROM score t4 WHERE t4.s_id=t2.`s_id`  AND t4.c_id  ='02') AS 数学,
                                  (SELECT  t5.s_score    FROM score t5 WHERE t5.s_id=t2.s_id    AND t5.c_id  ='03') AS 英语,
                                  SUM(t2.s_score)/COUNT(t2.c_id) AS avgnumber
    FROM student t1,score t2
    WHERE t1.`s_id`=t2.`s_id`       
    GROUP BY t1.`s_id`
    ORDER BY avgnumber DESC;

    -- 18.查询各科成绩最高分、最低分和平均分:以如下形式显示:课程ID,课程name,最高分,最低分,平均分,及格率,中等率,优良率,优秀率
    -- 及格为>=60,中等为:70-80,优良为:80-90,优秀为:>=90

    /*这里要学下case语法,简单介绍一下,具体的可以网上搜

    case  字段

    when 判断条件 then  结果 else  结果

    end

    */

    SELECT 
    t2.`c_id`,
    t2.`c_name`,
    MAX(t1.`s_score`),
    MIN(t1.`s_score`),
    AVG(t1.`s_score`),
     100*SUM(CASE WHEN t1.s_score >=60 THEN 1 ELSE 0 END)/COUNT(1) AS 及格率,
     100*SUM(CASE WHEN t1.s_score >=70 AND t1.s_score<80  THEN 1 ELSE 0 END)/COUNT(1) AS 中等率,
     100*SUM(CASE WHEN t1.s_score >=80 AND t1.s_score<90  THEN 1 ELSE 0 END)/COUNT(1) AS 优良率,
     100*SUM(CASE WHEN t1.s_score >=90 THEN 1 ELSE 0 END  )/COUNT(1) AS 优秀率
    FROM score t1,course t2    
    WHERE t1.`c_id`=t2.`c_id`
    GROUP BY t1.`c_id`;

    -- 19、按各科成绩进行排序,并显示排名 

    /*8.0有rank()函数,8.0一下没有,可以使用用户变量,从这里开始会有好几道关于名次的题目,把这里的三种方式弄清楚就差不多了*/

    -- 普通使用

    SELECT t1.`s_id`,t1.`c_id`,t1.`s_score`,@r:=@r+1 AS '名次'
    FROM score t1 ,(SELECT @r:=0)  q ORDER BY t1.`s_score` DESC ;

     -- 并排名次展示

    SELECT t1.`s_id`,t1.`c_id`,t1.`s_score`,(CASE WHEN @temp=t1.`s_score` THEN @r 
                                        WHEN @temp:=t1.`s_score`THEN @r:=@r+1 END) AS '名次'
    FROM score t1,(SELECT @r:=0,@temp :=NULL) q ORDER BY t1.`s_score` DESC;

     -- 并排名次跳过

     SELECT  a.s_id,a.c_id,a.s_score,a.名次 FROM
    (  SELECT t1.`s_id`,t1.`c_id`,t1.`s_score`,@r:=IF(@temp=t1.`s_score` , @r,@ra) AS '名次' ,@ra:=@ra+1,@temp:=t1.`s_score`FROM score t1,
                                                                                (SELECT @r:=0,@temp:=NULL,@ra:=1)q ORDER BY t1.`s_score`DESC
     ) a            ;

     上面的几种写法都是不分课程,所有的混在一起,因为题目说的也不明确,下面用分开的

      SELECT * FROM
     ( SELECT t1.`s_id`,t1.`c_id`,t1.`s_score`,@r:=@r+1 AS'名次'
      FROM score t1,(SELECT @r:=0)a WHERE t1.`c_id`='01' ORDER BY t1.`s_score`DESC
      ) AS k1
      UNION
      SELECT * FROM
     ( SELECT t2.s_id,t2.`c_id`,t2.s_score,@s:=@s+1 AS '名次'
      FROM score t2, (SELECT @s:=0)b WHERE t2.c_id='02'  ORDER BY t2.s_score DESC
      ) AS k2
      UNION
      SELECT *FROM
      (SELECT  t3.s_id,t3.c_id,t3.s_score,@t:=@t+1 AS '名次'
      FROM score t3,(SELECT @t:=0)c WHERE t3.c_id='03' ORDER BY t3.s_score DESC  
      )AS k3                                             
    ;

     -- 20、查询学生的总成绩并进行排名

    SELECT a.*,@r:=@r+1 AS '名次'
    FROM
    (SELECT t1.`s_id`,IFNULL(SUM(t1.`s_score`),0) AS sumnumber
    FROM score t1
    GROUP BY t1.`s_id` 
    ORDER BY sumnumber DESC) a,(SELECT @r:=0)b

     -- 21、查询不同老师所教不同课程平均分从高到低显示 

    SELECT  t3.`t_name`,t2.`c_name`,AVG(t1.`s_score`) AS avgnumber
    FROM score t1,course t2,teacher t3
    WHERE t1.`c_id`=t2.`c_id`
    AND   t2.`t_id`=t3.`t_id`
    GROUP BY t1.`c_id` 
    ORDER BY avgnumber DESC;

    -- 22、查询所有课程的成绩第2名到第3名的学生信息及该课程成绩

    /*这个题我直接拿的原作者的,把课程单独分开算的话,其实每个题跟前面几道求名次的题差不多,然后再筛选2-3名,最后三个部份并起来*/

    SELECT d.*,c.排名,c.s_score,c.c_id FROM (
                    SELECT a.s_id,a.s_score,a.c_id,@i:=@i+1 AS 排名 FROM score a,(SELECT @i:=0)s WHERE a.c_id='01'  
                                    ORDER BY a.s_score DESC  
                )c
                LEFT JOIN student d ON c.s_id=d.s_id
                WHERE 排名 BETWEEN 2 AND 3
                UNION
                SELECT d.*,c.排名,c.s_score,c.c_id FROM (
                    SELECT a.s_id,a.s_score,a.c_id,@j:=@j+1 AS 排名 FROM score a,(SELECT @j:=0)s WHERE a.c_id='02'  
                                    ORDER BY a.s_score DESC
                )c
                LEFT JOIN student d ON c.s_id=d.s_id
                WHERE 排名 BETWEEN 2 AND 3
                UNION
                SELECT d.*,c.排名,c.s_score,c.c_id FROM (
                    SELECT a.s_id,a.s_score,a.c_id,@k:=@k+1 AS 排名 FROM score a,(SELECT @k:=0)s WHERE a.c_id='03' 
                                    ORDER BY a.s_score DESC
                )c
                LEFT JOIN student d ON c.s_id=d.s_id
                WHERE 排名 BETWEEN 2 AND 3;

    -- 23、统计各科成绩各分数段人数:课程编号,课程名称,[100-85],[85-70],[70-60],[0-60]及所占百分比

    SELECT 
    t1.`c_id`,t2.`c_name`,
    SUM(CASE WHEN t1.`s_score`>85 AND t1.`s_score`<=100 THEN 1 ELSE 0 END)    AS '85-100人数',100*SUM(CASE WHEN t1.`s_score`>85 AND t1.`s_score`<=100 THEN 1 ELSE 0 END) /COUNT(1) AS 占比,
    SUM(CASE WHEN t1.s_score  >70 AND t1.s_score  <=85  THEN 1 ELSE 0 END)    AS '70-85人数' ,100*SUM(CASE WHEN t1.s_score  >70 AND t1.s_score  <=85  THEN 1 ELSE 0 END) /COUNT(1) AS 占比,
    SUM(CASE WHEN t1.s_score  >60 AND t1.s_score  <=70  THEN 1 ELSE 0 END)    AS '60-70人数' ,100*SUM(CASE WHEN t1.s_score  >60 AND t1.s_score  <=70  THEN 1 ELSE 0 END) /COUNT(1) AS 占比,
    SUM(CASE WHEN t1.s_score  >0 AND t1.s_score   <=60  THEN 1 ELSE 0 END)    AS '0-60人数'  ,100*SUM(CASE WHEN t1.s_score  >0 AND t1.s_score   <=60  THEN 1 ELSE 0 END) /COUNT(1) AS 占比
    FROM score t1, course t2
    WHERE t1.`c_id`=t2.`c_id`
    GROUP BY t1.`c_id`;

    -- 24、查询学生平均成绩及其名次 

    /*分组后再用变量去完成名次功能会出问题,名次排序是跟着id走的,而且变量初始赋值语句不知道写哪合适,所以先分组排序作为一个集合,再进行排序*/

    SELECT a.*,@r:=@r+1 AS '名次'
    FROM
    (SELECT t1.`s_id`,SUM(t1.`s_score`)/COUNT(1) AS avgNumber
    FROM score t1
    GROUP BY t1.`s_id`
    ORDER BY avgNumber DESC )a,(SELECT @r:=0)b

     -- 25、查询各科成绩前三名的记录

    /*这个题我直接拿的原作者的答案,还是不太明白*/

    SELECT a.s_id,a.c_id,a.s_score 
     FROM score a  LEFT JOIN score b 
     ON a.c_id = b.c_id AND a.s_score<b.s_score
    GROUP BY a.s_id,a.c_id,a.s_score HAVING COUNT(b.s_id)<3
    ORDER BY a.c_id,a.s_score DESC;

    -- 26、查询每门课程被选修的学生数

    SELECT t1.`c_id`,COUNT(t1.`s_id`) FROM score t1 GROUP BY t1.`c_id`

    -- 27、查询出只有两门课程的全部学生的学号和姓名

    SELECT t2.`s_id`,t2.`s_name`
    FROM score t1,student t2 WHERE
    t1.`s_id`=t2.`s_id`
    GROUP BY t1.`s_id` 
    HAVING COUNT(t1.`c_id`)=2;

    -- 28、查询男生、女生人数

    SELECT  t1.`s_sex`,COUNT(t1.`s_sex`)
    FROM student t1 GROUP BY t1.`s_sex`

    -- 29、查询名字中含有"风"字的学生信息

    SELECT  t1.`s_id`,t1.`s_name` FROM student t1 WHERE t1.`s_name` LIKE '%风%'

    -- 30、查询同名同性别学生名单,并统计同名人数 

    /*这个是直接拿的原作者的,题目都不是很明白,同名是同姓还是同姓名,语句倒不是很难理解*/

    SELECT t1.`s_name`,t1.`s_sex`,COUNT(1)
    FROM student t1,student t2
    WHERE t1.`s_id`!=t2.s_id
    AND t1.`s_name`=t2.s_name
    AND t1.`s_sex`=t2.s_sex
    GROUP BY t1.`s_name`,t1.`s_sex`

    -- 31、查询1990年出生的学生名单

    SELECT t1.`s_id`,t1.`s_name` FROM student t1 WHERE t1.`s_birth` LIKE '1990%';

    -- 32、查询每门课程的平均成绩,结果按平均成绩降序排列,平均成绩相同时,按课程编号升序排列 

    SELECT  t1.`c_id`,AVG(t1.`s_score`) AS avgnumber
    FROM score t1 GROUP BY t1.`c_id`
    ORDER BY AVG(t1.`s_score`) DESC  ,t1.`c_id` ASC  

    -- 33、查询平均成绩大于等于85的所有学生的学号、姓名和平均成绩

    SELECT  t1.`s_id`,t1.`s_name`,AVG(t2.`s_score`)
    FROM student t1,score t2
    WHERE t1.`s_id`=t2.`s_id`
    GROUP BY t1.`s_id`
    HAVING AVG(t2.`s_score`)>=85;

    -- 34、查询课程名称为"数学",且分数低于60的学生姓名和分数 

    SELECT t1.`s_name`,t2.`s_score` 
    FROM student t1,score t2,course t3
    WHERE t1.`s_id`=t2.`s_id` 
    AND t2.`c_id`=t3.c_id
    AND t3.c_name='数学'
    AND t2.`s_score`<60;

    -- 35、查询所有学生的课程及分数情况; 

    /*这个我是按着原作者的思路写的,每门课的成绩展示,用sum和case组合起来还是很巧妙的*/

    SELECT  t1.`s_name`,
    SUM(CASE  WHEN t3.`c_name`='语文' THEN t2.`s_score` ELSE 0 END  ) AS '语文',
    SUM(CASE  WHEN t3.`c_name`='数学' THEN t2.`s_score` ELSE 0 END  ) AS '数学',
    SUM(CASE  WHEN t3.`c_name`='英语' THEN t2.`s_score` ELSE 0 END  ) AS '英语'                 
    FROM student t1 LEFT JOIN score t2 
    ON t1.`s_id`=t2.`s_id`
    LEFT JOIN course t3 
    ON t2.`c_id`=t3.`c_id`
    GROUP BY t1.`s_id`

    -- 36、查询任何一门课程成绩在70分以上的姓名、课程名称和分数;

    SELECT t2.`s_name`,t3.c_name,t1.`s_score`
    FROM score t1,student t2,course t3
    WHERE t1.`s_id`=t2.`s_id`
    AND t1.`c_id`=t3.c_id
    AND  t1.`s_score`>70;

    -- 37、查询不及格的课程

    SELECT t2.`s_name`,t3.c_name,t1.`s_score`
    FROM score t1,student t2,course t3
    WHERE t1.`s_id`=t2.`s_id`
    AND t1.`c_id`=t3.c_id
    AND  t1.`s_score`<60;

    -- 38、查询课程编号为01且课程成绩在80分以上的学生的学号和姓名;

    SELECT t2.`s_id`, t2.`s_name`
    FROM score t1,student t2
    WHERE t1.`s_id`=t2.`s_id`
    AND  t1.`c_id`='01'
    AND t1.`s_score`>=80;

    -- 39、求每门课程的学生人数 

    SELECT t1.`c_id`,COUNT(*) AS 选课人数
    FROM score t1
    GROUP BY t1.`c_id`;

    -- 40、查询选修"张三"老师所授课程的学生中,成绩最高的学生信息及其成绩

    /*张三老师教的课程id*/

    SELECT  t1.`c_id` FROM course t1,teacher t2 WHERE t1.`t_id`=t2.`t_id` AND t2.`t_name`='张三';
    SELECT  t3.s_name,t4.`s_score`
    FROM student t3,score t4
    WHERE t3.s_id=t4.`s_id` AND t4.`c_id` IN (SELECT  t1.`c_id` FROM course t1,teacher t2 WHERE t1.`t_id`=t2.`t_id` AND t2.`t_name`='张三')
    ORDER BY t4.`s_score` DESC LIMIT 0,1;

    -- 41、查询不同课程成绩相同的学生的学生编号、课程编号、学生成绩 

    SELECT  DISTINCT t1.`s_id`,t1.`c_id`,t1.`s_score`
    FROM score t1,score t2
    WHERE t1.`c_id`!=t2.`c_id`
    AND   t1.`s_score`=t2.`s_score`;

    -- 42、查询每门功成绩最好的前两名 

    SELECT a.s_id,a.c_id,a.s_score FROM score a
            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;

    -- 43、统计每门课程的学生选修人数(超过5人的课程才统计)。要求输出课程号和选修人数,查询结果按人数降序排列,若人数相同,按课程号升序排列  

    SELECT  t1.c_id,COUNT(*) AS learnNumber FROM score t1 GROUP BY t1.c_id HAVING learnNumber>5 ORDER BY learnNumber DESC,c_id ASC;

    -- 44、检索至少选修两门课程的学生学号 

    SELECT  t2.`s_id` ,COUNT(1) FROM score t2  GROUP BY t2.`s_id` HAVING COUNT(1)>=2 ;

    -- 45、查询选修了全部课程的学生信息 

     SELECT t1.`s_id`,t1.`s_name`
       FROM student t1,score t2
       WHERE t1.`s_id`=t2.`s_id`
       GROUP BY t1.`s_id` HAVING COUNT(1)= ( SELECT COUNT(1) FROM course  )

    -- 46、查询各学生的年龄(按照出生日期来算,当前月日 < 出生年月的月日则,年龄减一)

    /*初次接触关于时间的题目,可以跳过这个题,看看后面的题,摸清关键字怎么用再来看这个题,同时这个题借助case语法*/

    SELECT t1.`s_name`, t1.`s_birth`,
                              (DATE_FORMAT(NOW(),'%Y')-DATE_FORMAT(t1.`s_birth`,'%Y')
                             -( CASE WHEN DATE_FORMAT(NOW(),'%m%d')<DATE_FORMAT(t1.`s_birth`,'%m%d')  
                                THEN 1 ELSE 0 END) )AS age
        FROM student t1

    -- 47、查询本周过生日的学生

    /*weak函数,计算日期是本年的第几个星期*/

    SELECT WEEK(DATE_FORMAT(NOW(),'%Y%m%d'))
    SELECT t1.`s_id`,t1.`s_name`,t1.`s_birth`
    FROM student t1
    WHERE WEEK(DATE_FORMAT(NOW(),'%Y%m%d'))=WEEK(t1.`s_birth`);

    -- 48、查询下周过生日的学生

    SELECT t1.`s_id`,t1.`s_name`,t1.`s_birth` 
    FROM student t1
    WHERE WEEK(DATE_FORMAT(NOW(),'%Y%m%d'))+1=WEEK(t1.`s_birth`)

    -- 49、查询本月过生日的学生

    SELECT t1.`s_id`,t1.`s_name`,t1.`s_birth`
    FROM student t1
    WHERE MONTH(DATE_FORMAT(NOW(),'%Y%m%d'))=MONTH(t1.`s_birth`);

    -- 50、查询下月过生日的学生

    SELECT  t1.`s_id`,t1.`s_name`,t1.`s_birth` 
    FROM student t1
    WHERE MONTH(DATE_FORMAT(NOW(),'%Y%m%d'))+1=MONTH(t1.`s_birth`);
  • 相关阅读:
    Java日期相关操作
    Java中this的功能与作用
    DCL双检查锁机制实现的线程安全的单例模式
    Java 二分查找
    Java冒泡排序
    Java多线程编程(二)
    SSH小结
    Python快速上手JSON指南
    趣谈、浅析CRLF和LF
    linux开发神器--Tmux
  • 原文地址:https://www.cnblogs.com/kc1995/p/14001059.html
Copyright © 2020-2023  润新知