SQL习题

作者: 浪汐颜 | 来源:发表于2020-05-05 18:31 被阅读0次

SQL习题

tips:简书不支持页内跳转,页内跳转链接都是参照markdown语法书写
且题目来源于知乎作者:TOMOCAT链接:https://zhuanlan.zhihu.com/p/53302593
个人仅做题目解析和做答。

目录

1.环境搭建

1.1表结构

1.2生成各表

2.题目目录


1.环境搭建sqlite

1.1表结构

--学生表
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 分数

1.2生成各表
--创建Student表
create table Student(sid varchar(10) PRIMARY KEY NOT NULL, 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-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 Student values('09', '李云', '1990-05-06', '女');
--创建Teacher表
create table Teacher(tid varchar(10) PRIMARY KEY NOT NULL,tname varchar(10)); 
insert into Teacher values('01' , '张三'); 
insert into Teacher values('02' , '李四');
insert into Teacher values('03' , '王五');
--创建Course
create table Course(cid varchar(10) PRIMARY KEY NOT NULL, cname varchar(10), tid varchar(10),
                   FOREIGN KEY(tid) REFERENCES Teacher(tid)); 
--插入数据
insert into Course values('01' , '语文' , '02'); 
insert into Course values('02' , '数学' , '01'); 
insert into Course values('03' , '英语' , '03'); 
--创建SC[student course]
create table SC(sid varchar(10) ,cid varchar(10),score  decimal(18,1),
             --外键分别与Student,Course表相关联
             FOREIGN KEY(sid) REFERENCES Student(sid),
             FOREIGN KEY(cid) REFERENCES Course(cid));
--插入数据
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);

2.题目目录

1、查询“01”课程比“02”课程成绩高的所有学生的学号

2、查询平均成绩大于60分的同学的学号和平均成绩

3、查询所有同学的学号、姓名、选课数、总成绩

4、查询姓“李”的老师的个数;

5、查询没学过“张三”老师课的同学的学号、姓名

6、查询学过编号“01”并且也学过编号“02”课程的同学的学号、姓名

7、查询学过“张三”老师所教的课的同学的学号、姓名

8、查询课程编号“01”的成绩比课程编号“02”课程低的所有同学的学号、姓名

9、查询所有课程成绩小于60分的同学的学号、姓名

10、查询没有学全所有课的同学的学号、姓名

11、查询至少有一门课与学号为“01”的同学所学相同的同学的学号和姓名

12、查询和"01"号的同学学习的课程完全相同的其他同学的学号和姓名

13、把“SC”表中“张三”老师教的课的成绩都更改为此课程的平均成绩

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

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

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

17、按平均成绩从高到低显示所有学生的平均成绩

18、查询各科成绩最高分、最低分和平均分:以如下形式显示:课程ID,课程name,最高分,最低分,平均分,及格率

19、按各科平均成绩从低到高和及格率的百分数从高到低顺序

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

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

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

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

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

26、查询每门课程被选修的学生数
27、查询出只选修了一门课程的全部学生的学号和姓名
28、查询男生、女生人数
29、查询名字中含有"风"字的学生信息
30、查询同名同性学生名单,并统计同名人数
31、查询1990年出生的学生名单(注:Student表中Sage列的类型是datetime)
32、查询每门课程的平均成绩,结果按平均成绩升序排列,平均成绩相同时,按课程号降序排列
37、查询不及格的课程,并按课程号从大到小排列
38、查询课程编号为"01"且课程成绩在60分以上的学生的学号和姓名
40、查询选修“张三”老师所授课程的学生中,成绩最高的学生姓名及其成绩
42、查询每门功课成绩最好的前两名
43、统计每门课程的学生选修人数(超过5人的课程才统计)。要求输出课程号和选修人数,查询结果按人数降序排列,若人数相同,按课程号升序排列
44、检索至少选修两门课程的学生学号
45、查询选修了全部课程的学生信息
46、查询各学生的年龄
47、查询本周过生日的学生
48、查询下周过生日的学生
49、查询本月过生日的学生
50、查询下月过生日的学生


1、查询“01”课程比“02”课程成绩高的所有学生的学号
--查询SC表,且满足S01.score > S02.score
--使用JOIN自联结
--条件:s1.sid = s2.sid AND s1.cid = '01' AND s2.cid = '02' 
--WHERE s1.score > s2.score
SELECT s1.sid
FROM SC AS s1 JOIN SC AS s2 
ON s1.sid = s2.sid AND s1.cid = '01' AND s2.cid = '02'
WHERE s1.score > s2.score;
2、查询平均成绩大于60分的同学的学号和平均成绩
--从SC表中查询,可以根据学号分组,使用AVG()求平均值
--条件:AVG(score)
SELECT sid, AVG(score)
FROM SC
GROUP BY sid
HAVING AVG(score) > 60;
3、查询所有同学的学号、姓名、选课数、总成绩
--从Student表中获取sid,name
--JOIN,并根据sid对SC表进行分组,用COUNT(*)计算选课数,SUM(score)计算总成绩
SELECT s.sid, s.Sname, COUNT(sc.cid) AS Courses, sum(sc.score) AS TotalScore
FROM student AS s 
LEFT JOIN SC AS sc
ON s.sid = sc.sid
GROUP BY s.sid;
4、查询姓“李”的老师的个数
--从Teacher表中查询Tname = '李%',需要使用通配符进行模糊查询
SELECT COUNT(*) AS 'numofli'
FROM Teacher
WHERE Tname LIKE '李%';
5、查询没学过“张三”老师课的同学的学号、姓名;
--使用嵌套查询
--在子查询中使用外联结,Teacher, SC, Course表
--T.Tname = '张三', 找出上了张老师课程的学生号
--sid NOT IN (these who are in the course)
SELECT sid, Sname 
FROM Student
WHERE sid not in (  
    SELECT SC.sid
    FROM SC 
    LEFT JOIN Course AS C ON SC.cid = C.cid
    LEFT JOIN Teacher AS T ON C.tid = T.tid
    WHERE T.Tname = '张三'
    );

6、查询学过编号“01”并且也学过编号“02”课程的同学的学号、姓名
--嵌套查询
--子查询中自联结SC表,条件为:SC1.sid = SC2.sid AND SC1.cid = '01' 
--AND SC2.cid = '02'
--find sid sname in (subsearch)
SELECT sid, sname 
FROM Student
WHERE sid in (
    SELECT SC1.sid
    FROM SC AS SC1 
    JOIN SC AS SC2
    ON SC1.sid = SC2.sid AND SC1.cid = '01' AND SC2.cid = '02'
);

7、查询学过“张三”老师所教的的同学的学号、姓名

回看题五

--和题五思路相似
--使用外联结,Teacher, SC, Course表
--T.Tname = '张三', 找出上了张老师课程的学生号
SELECT S.sid, S.Sname
FROM SC 
LEFT JOIN Course AS C ON SC.cid = C.cid
LEFT JOIN Teacher AS T ON C.tid = T.tid
LEFT JOIN Student AS S ON SC.sid = S.sid
WHERE T.Tname = '张三';

8、查询课程编号“01”的成绩比课程编号“02”课程低的所有同学的学号、姓名

回看题一

--和题一类似考察联结
SELECT st.sid,st.sname
FROM SC AS s1 JOIN SC AS s2 
ON s1.sid = s2.sid AND s1.cid = '01' AND s2.cid = '02'
LEFT JOIN Student AS st ON s1.sid = st.sid
WHERE s1.score < s2.score;

tip:根据联结条件是筛选出同时有这两门成绩的行进行比较,不知道需不需要考虑’02‘为null的情况。

9、查询所有课程成绩小于60分的同学的学号、姓名;

回看题二

--从SC表中查询,可以根据学号分组,使用AVG()求平均值
--条件:AVG(score)
SELECT s.sid, s.sname
FROM Student AS s
LEFT JOIN SC ON s.sid = SC.sid
GROUP BY s.sid
HAVING AVG(score) < 60;
10、查询没有学全所有课的同学的学号、姓名;
--先C1=COUNT(*)从Course中获取课程数
--查询SC,根据sid分组,条件COUNT(sid)< C1
--联结Student获取SC.sid = Student.sid
SELECT s.sid, s.sname 
FROM Student AS s
LEFT JOIN SC ON SC.sid = s.sid
GROUP BY s.sid
HAVING COUNT(*) < (
    SELECT COUNT(cid)
    FROM Course   
);
11、查询至少有一门课与学号为“01”的同学所学相同的同学的学号和姓名
--子查询出01的课程,再联结SC筛选满足条件的行,再到Student获取学生信息
SELECT DISTINCT s.sid, s.sname
FROM (
        SELECT cid
        FROM sc
        where sid='01'
    ) AS t1
LEFT JOIN SC
ON t1.cid=sc.cid
LEFT JOIN Student AS s
ON s.sid = SC.sid
WHERE s.sid != '01';
12、查询和"01"号的同学学习的课程完全相同的其他同学的学号和姓名
--思路如题11
SELECT DISTINCT s.sid, s.sname
FROM SC AS t1
LEFT JOIN SC
ON t1.cid=sc.cid AND t1.sid = '01'
LEFT JOIN Student AS s
ON s.sid = SC.sid
WHERE s.sid != '01'
--前面筛选出满足课程相同的行(这里指单科相同),并排除01
--按照学号分组,查看选课程数是否和01的同学相同
GROUP BY SC.sid
HAVING COUNT(*) = (
        SELECT COUNT(cid) AS num
        FROM sc
        where sid='01'
    );
13、把“SC”表中“张三”老师教的课的成绩都更改为此课程的平均成绩;
--两个子查询,一个计算出AVG(张老师课所有的成绩)作为替换值
--一个查出张三课程cid为筛选条件
--替换所有cid属于张老师的score
UPDATE SC
SET score = (   SELECT AVG(SC.score) AS avgz FROM SC
    LEFT JOIN Course AS c
    ON SC.cid = C.cid
    LEFT JOIN Teacher AS t
    ON t.tname = '张三' AND C.tid = t.tid 
)
WHERE SC.cid = (    SELECT SC.cid FROM SC
    LEFT JOIN Course AS c
    ON SC.cid = C.cid
    LEFT JOIN Teacher AS t
    ON t.tname = '张三' AND C.tid = t.tid 
) ;
14、查询没学过"张三"老师讲授的任一门课程的学生姓名
--先找出“张三”的所有课程cid,联结SC
--使用NOT IN
SELECT DISTINCT s.sid 
FROM Student AS s
LEFT JOIN SC
ON s.sid = SC.sid
WHERE s.sid NOT IN(
    SELECT t.sid
    FROM 
    (SELECT SC.sid 
    FROM Teacher AS t
    LEFT JOIN Course AS c
    ON t.tid = c.tid
    LEFT JOIN SC
    ON c.cid = SC.cid
    --也可以这里只留下张三的行
    WHERE t.zhi = '张三') AS t
    --除去结果集中的空值,防止子查询不返回任何值
    WHERE t.sid IS NOT NULL
);
15、查询两门及其以上不及格课程的同学的学号,姓名及其平均成绩
--联结student和sc
--通过学号分组,筛选出score<60 & count(score) >= 2
SELECT s.sid, s.sname, AVG(SC.score) AS avg_score
FROM Student AS s
LEFT JOIN SC 
ON s.sid = SC.sid
WHERE SC.score < 60
GROUP BY s.sid
HAVING COUNT(SC.score) >= 2;
16、检索"03"课程分数小于60,按分数降序排列的学生信息
--联结Student和SC表做
--使用ORDER BY DESC排序
SELECT s.sid, s.sname, SC.score 
FROM Student AS s
LEFT JOIN SC
ON s.sid = SC.sid AND SC.cid = '03'
WHERE SC.score < 60
ORDER BY SC.score DESC;
17、按平均成绩从高到低显示所有学生的平均成绩
SELECT s.sid, s.Sname, AVG(sc.score) AS AVGScore
FROM student AS s 
LEFT JOIN SC AS sc
ON s.sid = sc.sid
GROUP BY s.sid
ORDER BY AVGScore DESC;
18、查询各科成绩最高分、最低分和平均分:以如下形式显示:课程ID,课程name,最高分,最低分,平均分,及格率
--子查询获取及格人数
--按照课程cid分组
--使用ROUND函数调整小数点位数
--在子查询中的及格人数*1.00保证计算passrate时进行浮点运算,不然被四舍五入为0
SELECT SC.cid, C.cname, MAX(SC.score) AS topscore, MIN(SC.score) lowscore,
        AVG(SC.Score) AVGScore, ROUND(t1.pass_num / COUNT(*),2) AS pass_rate
FROM SC
LEFT JOIN Course c
ON SC.cid = c.cid
LEFT JOIN (
    SELECT cid, COUNT(score)*1.00 AS pass_num
    FROM SC
    WHERE score >= 60
    GROUP BY cid
) AS t1
ON t1.cid = SC.cid
GROUP BY SC.cid
19、按各科平均成绩从低到高和及格率的百分数从高到低顺序
--同18题,这题考察一个ORDER BY的用法
--使用CASE语句代替上面的子查询
SELECT SC.cid, C.cname, MAX(SC.score) AS topscore, MIN(SC.score) lowscore,
        AVG(SC.Score) AVGScore, 
        ROUND(
            COUNT(
                CASE WHEN SC.score >=60 
                THEN sid 
                ELSE null 
                END 
            )*1.00 / COUNT(*),
            2) AS pass_rate
FROM SC
LEFT JOIN Course c
ON SC.cid = c.cid
GROUP BY SC.cid
ORDER BY AVGScore, pass_rate DESC; 
20、查询学生的总成绩并进行排名
--从Student表中获取sid,name
--JOIN,并根据sid对SC表进行分组,SUM(score)计算总成绩
--使用ROW_Number() OVER( ORDER BY  )新增一个自增列
SELECT s.sid, s.Sname, sum(sc.score) AS TotalScore,
--这里排序条件好像不支持别名TotalScore
    ROW_Number() OVER( ORDER BY sum(sc.score) DESC ) AS rank
FROM student AS s 
LEFT JOIN SC AS sc
ON s.sid = sc.sid
GROUP BY s.sid
ORDER BY TotalScore DESC;
21、查询不同老师所教不同课程平均分从高到低显示
--三个表:course,teacher , sc
--先找出每门课对应的老师和平均分
SELECT sc.cid , c.cname, t.tname, AVG(sc.score) AS avgc
FROM sc 
LEFT JOIN Course AS c
ON sc.cid = c.cid
LEFT JOIN Teacher AS t 
ON t.tid = c.tid
GROUP BY sc.cid 
ORDER BY avgc 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
    ,ROUND(COUNT(CASE WHEN SC.score  BETWEEN 85 AND 100 
                THEN sid ELSE null END 
           )*1.00 / COUNT(sid), 2) AS '[85,100]'
    ,ROUND(COUNT(CASE WHEN SC.score  BETWEEN 70 AND 85 
                THEN sid ELSE null END 
           )*1.00 / COUNT(sid), 2) AS '[70, 85]'
    ,ROUND(COUNT(CASE WHEN SC.score  BETWEEN 60 AND 70 
                THEN sid ELSE null END 
           )*1.00 / COUNT(sid), 2) AS '[60, 70]'
    ,ROUND(COUNT(CASE WHEN SC.score  BETWEEN 0 AND 60 
                THEN sid ELSE null END 
           )*1.00 / COUNT(sid), 2) AS '[0, 60]'
from sc
left join course
    on sc.cid=course.cid
group by sc.cid,cname;
24、查询学生平均成绩及其名次
--子查询得出包含学生id和平均成绩的结果集
--使用rank函数进行排序
select
    sid
    ,avg_score
    ,rank() over (order by avg_score desc) AS rank
from 
    (
        select
            sid
            ,avg(score) as avg_score
        from sc
        group by sid
    )t;
25、查询各科成绩前三名的记录
--和题22类似
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 <= 3;
26、查询每门课程被选修的学生数
SELECT cid, COUNT(sid) AS s_num
FROM sc
GROUP BY cid;
27、查询出只选修了一门课程的全部学生的学号和姓名
SELECT s.sid, s.sname
FROM Student s
LEFT JOIN SC
ON s.sid = SC.sid
GROUP BY s.sid
HAVING COUNT(SC.cid) = 1;
28、查询男生、女生人数
SELECT ssex, COUNT(*)
FROM Student
GROUP BY ssex;
29、查询名字中含有"风"字的学生信息
SELECT sid, sname, ssex 
FROM Student
WHERE sname LIKE '%风%';
30、查询同名同性学生名单,并统计同名人数
SELECT sname,ssex, COUNT(sid) AS num
FROM Student
GROUP BY sname, ssex
HAVING COUNT(*) > 1;
31、查询1990年出生的学生名单(注:Student表中Sage列的类型是datetime)

SELECT sid, sname, sage
FROM Student
--WHERE sage BETWEEN '1990-01-01' AND '1990-12-31';
--使用strftime函数的做法
WHERE strftime('%Y',sage) = '1990';
32、查询每门课程的平均成绩,结果按平均成绩升序排列,平均成绩相同时,按课程号降序排列
SELECT cid, AVG(score) AS avgs
FROM SC
GROUP BY cid
ORDER BY avgs, cid DESC;
37、查询不及格的课程,并按课程号从大到小排列
--题目有问题啊,课程里不一定每个学生都及格了。
SELECT cid, score
FROM SC
WHERE score < 60
ORDER BY cid DESC, sid;
38、查询课程编号为"01"且课程成绩在60分以上的学生的学号和姓名;
SELECT s.sid, s.sname 
FROM Student s
LEFT JOIN SC
ON s.sid = SC.sid
WHERE SC.cid = '01' AND SC.score > 60;
40、查询选修“张三”老师所授课程的学生中,成绩最高的学生姓名及其成绩
SELECT s.sid, s.sname, SC.score
FROM Student s
LEFT JOIN SC
ON s.sid = SC.sid
LEFT JOIN Course c
ON SC.cid = c.cid
LEFT JOIN Teacher t
ON c.tid = t.tid
WHERE t.tname = '张三' 
ORDER BY SC.score DESC
LIMIT 1;
42、查询每门功课成绩最好的前两名
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 < 3;
43、统计每门课程的学生选修人数(超过5人的课程才统计)。要求输出课程号和选修人数,查询结果按人数降序排列,若人数相同,按课程号升序排列
SELECT
    cid
    ,count(sid) as cnt
FROM sc
GROUP BY cid
HAVING cnt>=5
ORDER BY COUNT(sid) DESC, cid;
44、检索至少选修两门课程的学生学号
SELECT sid
FROM SC
GROUP BY sid
HAVING COUNT(cid) >= 2;
45、查询选修了全部课程的学生信息
SELECT sid
FROM SC
GROUP BY sid
HAVING COUNT(cid) = (
    SELECT COUNT(cid)
    FROM Course
);
46、查询各学生的年龄
--MYSQL可以使用DATEDIFF(),这里不行
--还是用回strftime()
SELECT sid, sname, (strftime('%Y','now') - strftime('%Y', sage)) as age
FROM Student;
47、查询本周过生日的学生
--查询一年第几周,只要在这周内的生日就筛选出来
--先获取当前周数
SELECT sid, sname 
FROM Student
WHERE strftime('%W', sage) = strftime('%W', 'now');
48、查询下周过生日的学生
--同上题,使用关键字star of week, +1 week,变成下周
--查询一年第几周,只要在这周内的生日就筛选出来
--先获取当前周数
SELECT sid, sname 
FROM Student
WHERE strftime('%W', sage) = strftime('%W', 'now')+1;
49、查询本月过生日的学生
SELECT sid, sname 
FROM Student
WHERE strftime('%m', sage) = strftime('%m', 'now');
50、查询下月过生日的学生
SELECT sid, sname 
FROM Student
WHERE strftime('%m', sage) = strftime('%m', 'now','+1 month');

相关文章

  • 限制数据和对数据排序

    Mysql 课后习题 sql

  • SQL习题

    SQL习题 tips:简书不支持页内跳转,页内跳转链接都是参照markdown语法书写且题目来源于知乎作者:TOM...

  • SQL习题

    表信息 1.统计不同月份的下单人数 2.统计用户三月份的复购率和回购率 回购率:本月买,下月继续购买复购率:一个月...

  • SQL 资源汇总

    1.SQL习题练习网站,可以在线练习sql https://sqlzoo.net/ 2.一个可以在线编辑SQL的编...

  • SQL习题总结

    复用表格进行比较排名 对所有员工的薪水按照salary进行按照1-N的排名 对所有员工的当前(to_date='9...

  • MySQL 练习题

    01第一天20180703 【SQL练习】经典SQL练习题 02第二天20180704 sql语句练习50题(My...

  • 【SQL笔记】sql 练习题

    1.用一条SQL 语句 查询出每门课都大于80 分的学生姓名 name kecheng fenshu张三 ...

  • bWAPP学习笔记 - A1 Injection (二)

    SQL Injection (GET/Search) 手注练习题 (^_^) Level: Low 先输入单引号'...

  • LeetCode-SQL-nine

    Leetcode-sql-nine 本文中主要是介绍LeetCode中关于SQL的练习题,从易到难,循序渐进。文中...

  • LeetCode-SQL-five

    LeetCode-SQL-five 本文中主要是介绍LeetCode中关于SQL的练习题,从易到难,循序渐进。文中...

网友评论

      本文标题:SQL习题

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