50道SQL练习题及答案

作者: 一叶云秋 | 来源:发表于2019-06-07 22:12 被阅读47次

    网上流传这这样的50道练习题,以下是我的解法,仅供各位联系和参考

    数据表介绍

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

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

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

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

    学生表 Student

    create table Student(SId varchar(10),Sname varchar(10),Sage datetime,Ssex varchar(10));
    insert into Student values('01' , '赵雷' , '1990-01-01' , '男');
    insert into Student values('02' , '钱电' , '1990-12-21' , '男');
    insert into Student values('03' , '孙风' , '1990-12-20' , '男');
    insert into Student values('04' , '李云' , '1990-12-06' , '男');
    insert into Student values('05' , '周梅' , '1991-12-01' , '女');
    insert into Student values('06' , '吴兰' , '1992-01-01' , '女');
    insert into Student values('07' , '郑竹' , '1989-01-01' , '女');
    insert into Student values('09' , '张三' , '2017-12-20' , '女');
    insert into Student values('10' , '李四' , '2017-12-25' , '女');
    insert into Student values('11' , '李四' , '2012-06-06' , '女');
    insert into Student values('12' , '赵六' , '2013-06-13' , '女');
    insert into Student values('13' , '孙七' , '2014-06-01' , '女');
    

    科目表 Course

    create table Course(CId varchar(10),Cname nvarchar(10),TId varchar(10));
    insert into Course values('01' , '语文' , '02');
    insert into Course values('02' , '数学' , '01');
    insert into Course values('03' , '英语' , '03');
    

    教师表 Teacher

    create table Teacher(TId varchar(10),Tname varchar(10));
    insert into Teacher values('01' , '张三');
    insert into Teacher values('02' , '李四');
    insert into Teacher values('03' , '王五');
    

    成绩表 SC

    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 "课程成绩高的学生的信息及课程分数

    join课程1成绩表和课程2成绩表,然后对该表进行筛选

    SELECT
        c.SId,
        d.Sname,
        d.Sage,
        d.Ssex,
        c.S_01,
        c.S_02
    FROM
        (
            SELECT
                a.SId,
                a.score AS S_01,
                b.score AS S_02
            FROM
                (
                    SELECT
                        *
                    FROM
                        50exercises.sc
                    WHERE
                        CId = 01
                ) AS a
            JOIN (
                SELECT
                    *
                FROM
                    50exercises.sc
                WHERE
                    CId = 02
            ) AS b ON a.SId = b.SId
            WHERE
                a.score > b.score
        ) AS c
    JOIN 50exercises.student AS d ON c.SId = d.SId
    

    1.1. 查询同时存在" 01 "课程和" 02 "课程的情况

    解题思路 join课程1和课程2的两张表

    SELECT
        a.SId,
        a.score AS S_01,
        b.score AS S_02
    FROM
        (
            SELECT
                *
            FROM
                50exercises.sc
            WHERE
                CId = 01
        ) AS a
    JOIN (
        SELECT
            *
        FROM
            50exercises.sc
        WHERE
            CId = 02
    ) AS b ON a.SId = b.SId
    

    1.2. 查询存在" 01 "课程但可能不存在" 02 "课程的情况(不存在时显示为 null )

    left join课程1和课程2

    SELECT
        a.SId,
        a.score AS S_01,
        b.score AS S_02
    FROM
        (
            SELECT
                *
            FROM
                50exercises.sc
            WHERE
                CId = 01
        ) AS a
    left JOIN (
        SELECT
            *
        FROM
            50exercises.sc
        WHERE
            CId = 02
    ) AS b ON a.SId = b.SId
    

    1.3. 查询不存在" 01 "课程但存在" 02 "课程的情况

    与1.2思路相似,反之即可

    SELECT
        a.SId,
        a.score AS S_02,
        b.score AS S_01
    FROM
        (
            SELECT
                *
            FROM
                50exercises.sc
            WHERE
                CId = 02
        ) AS a
    LEFT JOIN (
        SELECT
            *
        FROM
            50exercises.sc
        WHERE
            CId = 01
    ) AS b ON a.SId = b.SId
    where b.score IS NULL
    

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

    筛选出平均成绩大于60分,和学生表Join

    SELECT
        b.Sid,
        b.Sname,
        c.avg_s
    FROM
        50exercises.student AS b
    JOIN (
        SELECT
            a.SId,
            avg(a.score) AS avg_s
        FROM
            50exercises.sc AS a
        GROUP BY
            a.Sid
        HAVING
            avg(a.score) >= 60
    ) AS c ON b.SId = c.SId
    

    3. 查询在 SC 表存在成绩的学生信息

    找出SC表中的学生,然后join学生表

    SELECT
        a.*
    FROM
        50exercises.student AS a
    JOIN (
        SELECT DISTINCT
            SId
        FROM
            50exercises.sc
    ) AS b ON a.SId = b.SId
    

    4. 查询所有同学的学生编号、学生姓名、选课总数、所有课程的总成绩(没成绩的显示为 null )

    从学生表left join成绩表

    SELECT
        a.*, b.sum_s
    FROM
        50exercises.student AS a
    LEFT JOIN (
        SELECT
            SId,
            sum(score) AS sum_s
        FROM
            50exercises.sc
        GROUP BY
            SId
    ) AS b ON a.SId = b.SId
    

    4.1 查有成绩的学生信息

    从成绩表开始,然后匹配学生表即可

    SELECT
        SId,
        sum(score) AS sum_s
    FROM
        50exercises.sc
    GROUP BY
        SId
    

    5. 查询「李」姓老师的数量

    找到姓李的老师的表,然后count

    SELECT
        count(1)
    FROM
        50exercises.teacher
    WHERE Tname LIKE '李%'
    

    6. 查询学过「张三」老师授课的同学的信息

    先找出张三老师教的课,然后找到有这么课成绩的学生,然后join学生表

    SELECT
        *
    FROM
        50exercises.student AS e
    JOIN (
        SELECT
            c.SId
        FROM
            50exercises.sc AS c
        JOIN (
            SELECT
                a.CId
            FROM
                50exercises.course AS a
            JOIN (
                SELECT
                    *
                FROM
                    50exercises.teacher
                WHERE
                    Tname = '张三'
            ) AS b ON a.TId = b.TId
        ) AS d ON c.CId = d.CId
    ) AS f ON e.SId = f.SId
    

    7. 查询没有学全所有课程的同学的信息

    解法1,由于CId是整数,所以可以相加,那么只要找出不是6的或者为空的就可以

    SELECT
        *
    FROM
        student AS a
    LEFT JOIN (
        SELECT
            SId,
            SUM(CId) AS sum_cid
        FROM
            sc
        GROUP BY
            SId
    ) AS b ON a.SId = b.SId
    WHERE
        b.sum_cid <> 6
    OR b.sum_cid IS NULL
    

    标准解法,上过所有课的人,在sc表中出现的次数和课程表中课的数量相同,然后反选即可

    SELECT
        *
    FROM
        student
    WHERE
        student.sid NOT IN (
            SELECT
                sc.sid
            FROM
                sc
            GROUP BY
                sc.sid
            HAVING
                count(sc.cid) = (SELECT count(cid) FROM course)
        )
    

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

    首先得到学号01的同学学过的课程

    select `CId`
    from `50exercises`.sc
    where `SId`= 01
    

    然后取出至少就是筛选课程在这个范围内的记录,得到Sid

    select distinct `SId`
    from `50exercises`.sc
    where `CId`in(
        select `CId`
        from `50exercises`.sc
        where `SId`= 01
        )
    

    最后和信息表组合

    select b.*
    from
    (
    select distinct `SId`
    from `50exercises`.sc
    where `CId`in(
        select `CId`
        from `50exercises`.sc
        where `SId`= 01
        )
        ) as a
    join `50exercises`.student as b
    on a.SId = b.`SId`
    

    9. 查询和" 01 "号的同学学习的课程 完全相同的其他同学的信息

    select c.*
    from `50exercises`.sc as a
    join `50exercises`.student as c 
    on a.`SId`=c.`SId`
    group by a.SId
    having  group_concat(a.CId order by a.CId) = (
            select  group_concat(b.CId order by b.CId)
            from `50exercises`.sc as b
            where b.SId = "01"
            group by b.SId
            )
    

    10. 查询没学过"张三"老师讲授的任一门课程的学生姓名

    select distinct d.`Sname`
    from `50exercises`.teacher as a
    join `50exercises`.course as b
    on a.`TId`= b.`TId` and a.`Tname` != "张三"
    join `50exercises`.sc as c 
    on b.`CId` = c.`CId`
    join `50exercises`.student as d
    on c.`SId` =  d.`SId`
    

    11. 查询两门及其以上不及格课程的同学的学号,姓名及其平均成绩

    select a.`SId`,
                b.`Sname`,
                avg(a.score) as avg_score,
                sum(if(a.score < 60,1,0)) as smark
    from `50exercises`.sc as a
    join `50exercises`.student as b 
    on a.`SId` = b.`SId`
    group by a.`SId`
    having smark >=2
    

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

    SELECT
        *
    FROM
        sc AS a
    JOIN student AS b ON a.SId = b.SId
    WHERE
        a.CId = "01"
    AND a.score < 60
    ORDER BY
        a.score DESC
    

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

    SELECT
        *
    FROM
        sc AS a
    JOIN (
        SELECT
            Sid,
            avg(score) AS AVG_S
        FROM
            sc
        GROUP BY
            SId
    ) AS b ON a.SId = b.Sid
    ORDER BY
        b.AVG_S DESC
    

    14. 查询各科成绩最高分、最低分和平均分;以如下形式显示:课程 ID,课程 name,最高分,最低分,平均分,及格率,中等率,优良率,优秀率;及格为>=60,中等为:70-80,优良为:80-90,优秀为:>=90;要求输出课程号和选修人数,查询结果按人数降序排列,若人数相同,按课程号升序排列

    SELECT
        b.Cname,
        b.CId,
        max(a.score) AS "最高分",
        min(a.score) AS "最低分",
        avg(a.score) AS "平均分",
        sum(
    
            IF (a.score >= 60 AND a.score < 70, 1, 0)
        ) / count(DISTINCT Sid) "及格率",
        sum(
    
            IF (a.score >= 70 AND a.score < 80, 1, 0)
        ) / count(DISTINCT Sid) "中等率",
        sum(
    
            IF (a.score >= 80 AND a.score < 90, 1, 0)
        ) / count(DISTINCT Sid) "优良率",
        sum(IF(a.score >= 90, 1, 0)) / count(DISTINCT Sid) "优秀率"
    FROM
        sc AS a
    JOIN course AS b ON a.CId = b.CId
    GROUP BY
        CId
    

    15. 按各科成绩进行排序,并显示排名, Score 重复时保留名次空缺

    SELECT
        A.CId,
        A.SId,
        A.score,
    
    IF (
        a.cid =@tmid ,@rank :=@rank + 1 ,@rank := 1
    ) AS rank ,@tmid := a.cid
    FROM
        (SELECT * from SC order by cid asc,score DESC) AS A,
        (SELECT @rank := 0 ,@tmid := NULL) AS B
    

    15.1 按各科成绩进行排序,并显示排名, Score 重复时合并名次

    SELECT
        A.CId,
        A.SId,
        A.score,
        CASE
    WHEN a.cid <> @tmid THEN
        @rank := 1
    WHEN a.cid = @tmid
    AND a.score <> @tscore THEN
        @rank :=@rank + 1
    WHEN a.cid = @tmid
    AND a.score = @tscore THEN
        @rank := @rank
    ELSE @rank := 1
    END AS rank,
     @tmid := a.cid,
     @tscore := a.score
    FROM
        (
            SELECT
                *
            FROM
                SC
            ORDER BY
                cid ASC,
                score DESC
        ) AS A,
        (
            SELECT
                @rank := 1 ,@tmid := NULL ,@tscore := 0
        ) AS B 
    

    16. 查询学生的总成绩,并进行排名,总分重复时保留名次空缺

    看了下数据,没有总成绩相同的学生,检验不出效果,所以改成用01课程来检验

    SELECT
    a.SId,
    a.all_s,
    CASE
    WHEN a.all_s <> @tscore then @rank := @rank+1
    ELSE @rank = @rank
    END as rank,
    @tscore := a.all_s
    FROM
        (
            SELECT
                SId,
                sum(score) AS all_s
            FROM
                sc
            WHERE
                Cid = "01"
            GROUP BY
                SId
            ORDER BY
                all_s DESC
        ) AS a,
    (SELECT @rank := 0 ,@tscore := 0) AS b
    

    16.1 查询学生的总成绩,并进行排名,总分重复时不保留名次空缺

    SELECT
    a.SId,
    a.all_s,
    @rank := @rank+1 as rank
    FROM
        (
            SELECT
                SId,
                sum(score) AS all_s
            FROM
                sc
            WHERE
                Cid = "01"
            GROUP BY
                SId
            ORDER BY
                all_s DESC
        ) AS a,
    (SELECT @rank := 0 ) AS b
    

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

    和14题相同

    SELECT
        b.Cname,
        b.CId,
        sum(
    
            IF (a.score >= 0 AND a.score < 60, 1, 0)
        ) / count(DISTINCT Sid) "[0,60)",
        sum(
    
            IF (a.score >= 60 AND a.score < 70, 1, 0)
        ) / count(DISTINCT Sid) "[60,70)",
        sum(
    
            IF (a.score >= 70 AND a.score < 85, 1, 0)
        ) / count(DISTINCT Sid) "[70,85)",
        sum(IF(a.score >= 85, 1, 0)) / count(DISTINCT Sid) "[85,100]"
    FROM
        sc AS a
    JOIN course AS b ON a.CId = b.CId
    GROUP BY
        CId
    

    18. 查询各科成绩前三名的记录

    SELECT
        *
    FROM
        sc
    WHERE
        (
            SELECT
                count(*)
            FROM
                sc AS a
            WHERE
                sc.cid = a.cid
            AND sc.score < a.score
        ) < 3 ##是不是比自己大的有三条
    ORDER BY
        cid ASC,
        sc.score DESC;
    
    

    解法2

    SELECT
        a.sid,
        a.cid,
        a.score
    FROM
        sc a
    LEFT JOIN sc b ON a.cid = b.cid
    AND a.score < b.score
    GROUP BY
        a.cid,
        a.sid
    HAVING
        count(b.cid) < 3
    ORDER BY
        a.cid;
    
    

    19. 查询每门课程被选修的学生数

    SELECT
        CId,
        COUNT(DISTINCT SId) AS count_s
    FROM
        SC
    GROUP BY
        CId
    

    20. 查询出只选修两门课程的学生学号和姓名

    SELECT
        *
    FROM
        (
            SELECT
                SId,
                COUNT(DISTINCT CId) AS count_C
            FROM
                SC
            GROUP BY
                SId
            HAVING
                count_C <= 2
        ) AS a
    JOIN student AS b ON a.SId = b.SId
    

    21. 查询男生、女生人数

    SELECT
        Ssex,
        COUNT(DISTINCT SId) as Qty
    FROM
        student
    GROUP BY
        Ssex
    

    22. 查询名字中含有「风」字的学生信息

    SELECT
        *
    FROM
        student
    WHERE
        sname LIKE "%风%"
    

    23. 查询同名同性学生名单,并统计同名人数

    SELECT
        sname,
        COUNT(DISTINCT sid) AS Qty
    FROM
        student
    GROUP BY
        Sname
    HAVING
        qty > 1
    

    24. 查询 1990 年出生的学生名单

    SELECT
        *
    FROM
        student
    WHERE
        YEAR (Sage) = 1990
    

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

    SELECT
        CId,
        avg(score) AS avg_s
    FROM
        sc
    GROUP BY
        CId
    ORDER BY
        avg_s DESC,
        CId ASC
    

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

    SELECT
        a.SId,
        a.Sname,
        b.avg_s
    FROM
        student AS a
    JOIN (
        SELECT
            SId,
            avg(score) AS avg_s
        FROM
            sc
        GROUP BY
            SId
    ) AS b ON a.SId = b.SId
    

    27. 查询课程名称为「数学」,且分数低于 60 的学生姓名和分数

    SELECT
        c.Sname,
        d.score
    FROM
        (
            SELECT
                a.SId,
                a.score
            FROM
                sc AS a
            JOIN course AS b ON a.CId = b.CId
            WHERE
                a.score < 60
            AND b.Cname = '数学'
        ) AS d
    JOIN student AS c ON c.SId = d.SId
    

    28. 查询所有学生的课程及分数情况(存在学生没成绩,没选课的情况)

    SELECT
        *
    FROM
        student AS a
    JOIN course AS b
    LEFT JOIN sc AS c ON a.SId = c.SId
    AND b.CId = c.CId
    

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

    SELECT
        *
    FROM
        student AS a
    JOIN course AS b
    LEFT JOIN sc AS c ON a.SId = c.SId
    AND b.CId = c.CId
    where score > 70
    

    30. 查询不及格的课程

    SELECT 
        DISTINCT cid
    FROM
        sc
    WHERE
        score < 60
    

    31. 查询课程编号为 01 且课程成绩在 80 分以上的学生的学号和姓名

    SELECT
        b.*
    FROM
        (
            SELECT DISTINCT
                Sid
            FROM
                sc
            WHERE
                score >= 80
            AND Cid = '01'
        ) AS a
    JOIN student AS b ON a.Sid = b.Sid
    

    32. 求每门课程的学生人数

    SELECT
        cid,
        COUNT(DISTINCT sid)
    FROM
        sc
    GROUP BY
        CId
    

    33. 成绩不重复,查询选修「张三」老师所授课程的学生中,成绩最高的学生信息及其成绩

    SELECT
        *
    FROM
        teacher AS a
    JOIN course AS b ON a.TId = b.TId
    AND a.Tname = '张三'
    JOIN sc AS c ON b.CId = c.CId
    JOIN student AS d ON d.SId = c.SId
    HAVING
        max(c.score)
    

    34. 成绩有重复的情况下,查询选修「张三」老师所授课程的学生中,成绩最高的学生信息及其成绩

    SELECT
        *
    FROM
        teacher AS a
    JOIN course AS b ON a.TId = b.TId
    AND a.Tname = '张三'
    JOIN sc AS c ON b.CId = c.CId
    JOIN student AS d ON d.SId = c.SId
    WHERE
        c.score = (
            SELECT
                max(c.score)
            FROM
                teacher AS a
            JOIN course AS b ON a.TId = b.TId
            AND a.Tname = '张三'
            JOIN sc AS c ON b.CId = c.CId
            JOIN student AS d ON d.SId = c.SId
        )
    

    35. 查询不同课程成绩相同的学生的学生编号、课程编号、学生成绩

    SELECT
        a.cid,
        a.sid,
        a.score
    FROM
        sc AS a
    INNER JOIN sc AS b ON a.sid = b.sid
    AND a.cid != b.cid
    AND a.score = b.score
    GROUP BY
        cid,
        sid
    

    36. 查询每门功成绩最好的前两名

    SELECT
        *
    FROM
        sc
    WHERE
        (
            SELECT
                count(*)
            FROM
                sc AS a
            WHERE
                sc.cid = a.cid
            AND sc.score < a.score
        ) < 3 ##是不是比自己大的有三条
    ORDER BY
        cid ASC,
        sc.score DESC;
    

    37. 统计每门课程的学生选修人数(超过 5 人的课程才统计)

    SELECT
        CId,
        COUNT(DISTINCT SId) AS Qty
    FROM
        sc
    GROUP BY
        CId
    HAVING
        Qty > 5
    

    38. 检索至少选修两门课程的学生学号

    SELECT
        SId,
        COUNT(DISTINCT CId) AS Qty
    FROM
        sc
    GROUP BY
        SId
    HAVING
        Qty >= 2
    

    39. 查询选修了全部课程的学生信息

    SELECT
        b.*, COUNT(DISTINCT a.CId) AS Qty
    FROM
        sc AS a
    JOIN student AS b ON a.SId = b.SId
    GROUP BY
        SId
    HAVING
        Qty = (
            SELECT
                COUNT(DISTINCT CId)
            FROM
                course
        )
    

    40. 查询各学生的年龄,只按年份来算

    SELECT
        *, YEAR (NOW()) - YEAR (Sage) + 1 AS Age
    FROM
        student
    

    41. 按照出生日期来算,当前月日 < 出生年月的月日则,年龄减一

    SELECT
        *, TIMESTAMPDIFF(YEAR, Sage, NOW()) AS Age
    FROM
        student
    

    42. 查询本周过生日的学生

    SELECT
        *
    FROM
        student
    WHERE
        WEEKOFYEAR(Sage) = WEEKOFYEAR(NOW())
    

    43. 查询下周过生日的学生

    SELECT
        *
    FROM
        student
    WHERE
        WEEKOFYEAR(Sage) = WEEKOFYEAR(NOW())+1
    

    44. 查询本月过生日的学生

    SELECT
        *
    FROM
        student
    WHERE
        MONTH(Sage) = MONTH(NOW())
    

    45. 查询下月过生日的学生

    SELECT
        *
    FROM
        student
    WHERE
        MONTH(Sage) = MONTH(NOW())+1
    

    相关文章

      网友评论

        本文标题:50道SQL练习题及答案

        本文链接:https://www.haomeiwen.com/subject/dtavxctx.html