• 如何快速学会 SQL 数据库基础?


    作者:数据开发小胡同学
    链接:https://www.zhihu.com/question/486712700/answer/2424239325
    来源:知乎
    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
    
    /*
     * 复杂sql练习
     * 2022-04-01
     *author:Rabin
     *address:shanghai
     *题目来源:https://zhuanlan.zhihu.com/p/38354000,作者:猴子数据分析
      使用环境:sqlserver
     *
     *学生表:student(学号,学生姓名,出生年月,性别)
      成绩表:score(学号,课程号,成绩)
      课程表:course(课程号,课程名称,教师号)
      教师表:teacher(教师号,教师姓名)
     */
     
    -- 一、创建数据库和表
     
    -- 1、学生表
    CREATE table student (
     sid int,--学号
     sname varchar(20),--姓名
     sbirth varchar(20), --出生日期
     sgender varchar(20)--性别
    );
    INSERT into student values (0001,'猴子','1989-01-01','男'),(0002,'猴子','1990-12-21','女'),(0003,'马云','1991-12-21','男'),(0004,'王思聪','1990-05-20','男');
    SELECT * from student ;
     
    -- 2.创建学生成绩表
    create table score (
      sid int ,--学号
      scoure int,--课程号
      sscore int, --成绩
      primary key (sid,scoure) 
    );
     
    INSERT  into score values (0001,0001,80),(0001,0002,90),(0001,0003,99),(0002,0002,60),(0002,0003,80),(0003,0001,80),(0003,0002,80),(0003,0003,80);
    SELECT * from score ;
    -- 创建课程表
    create table course (
      scoure int ,--课程号
      cname varchar(20),--课程名称
      cteacher int 
    );
    INSERT  into course values (001,'语文',0002),(0002,'数学',0001),(0003,'英语',0003);
    SELECT * from course ;
     
    --创建教师表
    create table teacher(
     cteacher int,--教师号
     tname varchar (20)
    );
     
    INSERT into teacher values (0001,'孟扎扎'),(0002,'马化腾'),(0003,null),(0004,'');
    SELECT * from teacher ;
     
     
     
    -- 1、查询姓“猴”的学生名单
    SELECT * from student s where s.sname like '猴%';
    -- 1.1查询姓名中最后一个字是猴的学生名单
    SELECT * from student s where s.sname like '%猴';
    -- 1.2查询姓名中带猴的学生名单
    SELECT * from student s where s.sname like '%猴%';
    -- 1.3、查询姓“孟”老师的个数
    SELECT count(*) from student s where s.sname like '孟%';
     
    --2、查询课程编号为“0002”的总成绩
    SELECT sum(s.sscore) from course c join score s on c.scoure =s.scoure where c.scoure =002 ;
    -- 2.1、查询选了课程的学生人数
     
    SELECT count( DISCONNECT s.sid) from score s;
    -- 3、查询各科创建最高和最低分数
    SELECT scoure , max(sscore),min(sscore) from score group by scoure ;
    -- 3.1、查询每门课程被选修学生数
    SELECT * from course ; 
    SELECT s.scoure,count(*) from score s join course c on s.scoure =c.scoure  group by s.scoure ;
    -- 3.2、查询男生,女生人数
    SELECT sgender , count(*) from student group by sgender ;
    -- 4、查询平均成绩大于70分学生的学号和平均成绩
    SELECT s.sid ,AVG(s.sscore)  from score s group by s.sid HAVING AVG(s.sscore)>70 ;
    -- 4.1、查询至少选修两门课程的学生学好
    SELECT s.sid,count(s.scoure)from score s group by s.sid HAVING count(s.scoure)>=2;
    -- 4.2、查询同名同性学生名单并统计同名人数
    SELECT count(*),s2.sname  FROM  student s2 group by s2.sname HAVING count(*)>1;
    -- 4.3、查询不及格的课程并按课程号从大到小排列
    SELECT s.scoure,s.sscore  from score s where s.sscore <60 ORDER BY s.scoure  
    -- 4.4、查询每门课程的平均成绩,结果按平均成绩升序排序,平均成绩相同时,按课程号降序排列
    SELECT s2.scoure,AVG(s2.sscore) from score s2 group by s2.scoure ORDER by avg(s2.sscore),s2.scoure DESC ;
    SELECT * from score s ;
    -- 4.5、检索课程编号为“0004”且分数小于60的学生学号,结果按按分数降序排列
    SELECT s.sid ,s.sscore  from score s where s.sid =004 and s.sscore <60 ORDER BY s.sscore DESC ;
    SELECT  * from score s ;
    SELECT * from course c ;
    --4.6、统计每门课程的学生选修人数(超过2人的课程才统计)
    --要求输出课程号和选修人数,查询结果按人数降序排序,若人数相同,按课程号升序排序
    SELECT s.scoure ,count(s.sid) FROM  score s group by s.scoure HAVING count(s.sid)>2 ORDER BY count(s.sid) desc,s.scoure ;
    -- 4.7、查询两门以上不及格课程的同学的学号及其平均成绩
    SELECT s.sid , AVG(s.sscore)
           FROM score s 
           WHERE s.sscore<60
          group by s.sid 
          HAVING COUNT(s.scoure)>2;
    -- 5、查询学生的总成绩并进行排序
         SELECT s.sid , sum(s.sscore)
              FROM score s 
              group by s.sid
              ORDER by sum(s.sscore);
    -- 5.1、查询平均成绩大于60分的学生学号和平均成绩
             SELECT s.sid,AVG(s.sscore)
                  from score s 
                  group by s.sid 
                  HAVING AVG(s.sscore)>60
                  ORDER BY AVG(s.sscore) ;
     --复杂查询
     
    -- 6、查询所有课程成绩小于80分学生的学号、姓名
                 --法一
     SELECT s.sid,s2.sname
          from score s 
          join student s2
          on s.sid =s2.sid 
          WHERE s.sscore <80;
         --法二
         SELECT s2.sid ,s2.sname 
               FROM student s2
                where s2.sid in
               (SELECT s.sid
    	            from score s
    			where s.sscore<80);
         
    -- 6.1、查询没有学全所有课的学生的学号、姓名
    		SELECT s3.sid ,s3.sname from student s3 where s3.sid in (
    		-- 2.把学生id作为筛选条件葱student表中找到
    		SELECT s.sid -- 1.先把没有学全的学生id找到
    		    from score s  
    		    group by s.sid 
    		    HAVING count(*)<(SELECT count(*) from course c));
    --6.2、查询出只选修了两门课程的全部学生的学号和姓名
    		   --法一
    		   SELECT s2.sid ,s2.sname 
    		      FROM student s2 
    		      where s2.sid in
    		   (SELECT s.sid 
    		     from score s 
    		     group by s.sid 
    		     HAVING count(s.sid)=2)
    /*
    查找1990年出生的学生名单
    学生表中出生日期列的类型是datetime
    */
    		     
    SELECT * from student s where s.sbirth LIKE  '%1990%' ;	
    --按照学生id对score进行排序并输出前三条记录
    SELECT  top 3 * FROM  score order by sid;
    -- 查询各学生的年龄(精确到月份)
    SELECT SUBSTRING(s.sbirth,6,7)from student s
    -- 找出本月过生日的学生
    select * 
    from student 
    where month(SUBSTRING(s.sbirth,6,10) )= month(current_date);
    -- 7.查询所有学生的学号、姓名、选课数、总成绩
     
    SELECT s.sid,count(s2.scoure),SUM(s2.sscore) 
    from student s left join score s2
    on s.sid =s2.sid 
    group by s.sid 
    		    
     
    select a.sid,count(b.scoure),sum(b.sscore)
    from student as a left join score as b
    on a.sid = b.sid
    group by a.sid;
     
    -- 7.1、查询平均成绩大于85的所有学生的学号、姓名和平均成绩
    SELECT s2.sid , s2.sname
    from student s2  where s2.sid in-- 1
    (SELECT  s.sid
    from score s 
    group by s.sid 
    HAVING AVG(s.sscore)>85)
     
    select a.sid ,max(a.sname) ,avg(b.sscore)
    from student as a left join score as b
    on a.sid  = b.sid 
    group by a.sid 
    having avg(b.sscore)>85;
     
     
    -- 7.2、查询学生的选课情况:学号,姓名,课程号,课程名称
    SELECT  s.sid ,s.sname ,c.scoure ,c.cname 
    from student s  
    left  join score s2 on s.sid =s2.sid 
    LEFT  join course c on s2.scoure =c.scoure;
    -- 7.3、查询出每门课程的及格人数和不及格人数(***)
    SELECT 
    s.scoure 
    ,sum(case when s.sscore<60 then 1 else 0 end ) as '不及格人数'
    ,sum(case when s.sscore>=60 then 1 else 0 end ) as '及格人数'
    from score s 
    GROUP by s.scoure 
    -- 7.4、使用分段[100-85],[85-70],[70-60],[<60]来统计各科成绩,分别统计:各分数段人数,课程号和课程名称
    SELECT s2.scoure ,c.cname 
    ,sum(case when s2.sscore<60 then 1 else 0 end ) as '不及格人数'
    ,sum(case when s2.sscore between 60 and 70 then 1 ELSE 0 END) as '60-70分人数'
    ,sum(case when s2.sscore BETWEEN 70 and 80 then 1 ELSE 0 END) as '70-80分人数'
    ,sum(case when s2.sscore BETWEEN 85 and 100 then 1 ELSE 0 END) as '85-100分人数'
    from score s2
    left join course c on s2.scoure =c.scoure 
    group by s2.scoure ,c.cname ;
     
    -- 7.5、查询课程编号为0003且课程成绩在80分以上的学生的学号和姓名
    SELECT a.sid ,s2.sname,a.sscore  
    from student s2 join 
    (SELECT *
    from score s 
    where s.scoure =3 and s.sscore >80) a
    on s2.sid =a.sid 
     
     
    SELECT s.sid ,s.sname,s2.sscore  
    from student s inner join score s2 
    on s.sid =s2.sid 
    where s2.scoure =3 and s2.sscore >80
     
     
    -- 8.sql面试题:行列如何互换?(****)
    select s.sid  ,'课程号0001','课程号0002','课程号0003'
    from score s ;
     
    select s.sid
    ,MAX((case s.scoure  when 1 then s.sscore  else 0 end )) as '课程号0001'-- 当s.scoure =1时输出s.sscore 否则就为0
    ,max((case s.scoure when 2 then s.sscore else 0 end)) as '课程号0002'
    ,max((case s.scoure when 3 then s.sscore else 0 end))as '课程号0003'
    from score s 
    group by s.sid ;
    --9.多表连接
    --9.1、检索0001课程分数小于90,按照分数降序排列的学生信息
    SELECT s3.*,a.scoure ,a.sscore 
    from student s3 right join 
    (SELECT *
    from score s2 
    where s2.sscore <90 and s2.scoure =1 
    ) a
     on s3.sid =a.sid 
     ORDER BY a.sscore DESC 
     
    SELECT * from score s ;
     
     
    SELECT s.*,s2.sscore ,s2.scoure 
    from student s inner join score s2 
    on s.sid =s2.sid 
    where s2.sscore <90 and s2.scoure =1
    ORDER BY s2.sscore DESC ;
    -- 9.2、查询不同老师所教授不同课程平均分从高到低显示
    SELECT t.cteacher,avg(s.sscore)
    from score s
    join course c on s.scoure =c.scoure 
    join teacher t on t.cteacher =c.cteacher 
    GROUP by t.cteacher 
    ORDER BY  AVG(s.sscore) DESC  
     
     
    SELECT * from teacher t ;
    -- 9.3 查询课程名称为"数学",且分数低于60的学生姓名和分数
    SELECT s2.sname ,s.sscore,s.sid  
    from course c 
    inner join score s on c.scoure  =s.scoure 
    INNER join student s2 on s.sid =s2.sid 
    where c.cname ='数学' and s.sscore <90
    -- 9.4、查询任何一门课程成绩在70分以上的姓名、课程名称和分数(与上题类似)
    SELECT s3.sname ,c2.cname ,s4.sscore 
    from student s3
    join score s4 on s3.sid =s4.sid 
    join course c2 on c2.scoure =s4.scoure 
    WHERE s4.sscore >70
    -- 9.5、查询两门及其以上不及格课程的同学的学号,姓名及其平均成绩
    --法1⃣
    SELECT s.sid ,avg(s2.sscore)
    from student s 
    join score s2 on s.sid =s2.sid
    WHERE s2.sscore <90 --先整体过滤出不及格(先初步筛选后分组,再对分组进一步筛选)
    group by s.sid --再根据学生id进行分组
    HAVING count(s.sid)>=2;--每个学生里面的记录大于等于2就说明
     
    --法二
    SELECT s.sid ,avg(s2.sscore)
    from student s 
    join score s2 on s.sid =s2.sid
    group by s.sid --(先分组,后对每一组进行筛选)
    HAVING sum(case when s2.sscore<90 then 1 ELSE 0 end)>=2;
     
    -- 9.6、查询学生的总成绩并进行排名
    SELECT s.sid ,AVG(s.sscore) 
    from score s 
    group by s.sid 
    ORDER by sum(s.sscore) 
     
    --9.7、查询平均成绩大于60分学生的学号和平均成绩
    SELECT s.sid ,avg(s.sscore) 
    FROM score s
    group by s.sid 
    HAVING AVG(s.sscore)>60 
     
    -- 10.1、查询所有课程成绩小于60分学生的学号、姓名
    --法一
    SELECT s.sid ,s2.sname ,s.sscore 
    FROM score s 
    join student s2 on s.sid =s2.sid 
    WHERE s.sscore <90;
    --法二
    SELECT s2.sid ,s2.sname  
    FROM  student s2
    where s2.sid  IN 
    (SELECT s.sid 
    from score s 
    where s.sscore <90);
    -- 10.2、查询没有学全所有课的学生的学号、姓名
    SELECT s.sid ,s2.sname 
    from score s
    join student s2 on s.sid =s2.sid 
    GROUP BY s.sid,s2.sname  
    HAVING count(*)<(SELECT count(*) from course c );
     
    -- 10.3、查询出只选修了两门课程的全部学生的学号和姓名
    SELECT s.sid ,s2.sname 
    from score s
    join student s2 on s.sid =s2.sid 
    GROUP BY s.sid,s2.sname  
    HAVING count(*)=2;
    /*
     * CURRENT_DATE :2022-04-03
     * current_time:11:05:23
     * current_timestamp:2022-04-03 05:23
     * 
     * */
     SELECT YEAR ('2022-04-03')   --2022
     SELECT MONTH  ('2022-04-03')   --4
     SELECT day ('2022-04-03')   --3
     
    select * from score s 
     
    --11.1、查询所有学生的学号、姓名、选课数、总成绩
    select s.sid ,s.sname ,count(*),sum(s2.sscore)
    FROM student s 
    join score s2 on s.sid =s2.sid 
    GROUP BY s.sid ,s.sname; 
    --11.2、查询平均成绩大于85的所有学生的学号、姓名和平均成绩
    SELECT s.sid ,s.sname ,AVG(s2.sscore) 
    from student s 
    join score s2 on s.sid =s2.sid 
    GROUP BY s.sid,s.sname  
    HAVING AVG(s2.sscore)>85 ;
    --11.3、查询学生的选课情况:学号,姓名,课程号,课程名称
    SELECT s.sid ,s.sname ,s2.scoure ,c.cname
    FROM student s 
    join score s2 on s.sid =s2.sid 
    JOIN course c on s2.scoure =c.scoure ;
    --GROUP  by s.sid ,s.sname ,s2.scoure ,c.cname 
    --11.4、查询出每门课程的及格人数和不及格人数
    SELECT s.scoure as '课程号'
    ,SUM(CASE when s.sscore<60 then 1 else 0 end) as '不及格人数'
    ,SUM(case when s.sscore>60 then 1 else 0 end)  as '及格人数'
    from score s 
    group by s.scoure ;
    --11.5、使用分段[100-85],[85-70],[70-60],[<60]来统计各科成绩,分别统计:各分数段人数,课程号和课程名称
    --考察case when,between  小 and 大
    SELECT s.scoure ,c.cname 
    ,sum(case when s.sscore between 85 and 100 then 1 else 0 END ) as '100-85'
    ,sum(case when s.sscore BETWEEN 70 and 85 then 1 else 0 END ) as '85-70'
    ,sum(CASE WHEN s.sscore  BETWEEN 60 and 70 then 1 else 0 END ) as '70-60'
    ,sum(case when s.sscore<60 then 1 else 0 END ) as '小于60'
    from score s 
    join course c on s.scoure =c.scoure 
    GROUP by s.scoure ,c.cname ;
    --11.6、查询课程编号为3且课程成绩在80分以上的学生的学号和姓名
    SELECT * from score s2 
    select s3.sid ,s3.sname 
    FROM score s 
    join student s3 on s.sid =s3.sid  
    where s.scoure =3 and s.sscore  >80;
     
    --11.7、对score进行行转列
    SELECT * FROM  score s2 
    --第一步:
    SELECT s.sid ,'课程表001','课程表002','课程表003'
    FROM score s ;
    --第二步:
    SELECT s.sid --每一条记录都会走下面的3个case when
    --例如sid=1,source=1,sscore=80,
    --第一个case when 判断scoure是否为1,是的话就输出80,否则就输出0
    --第二个case when 判断scoure是否为2,不是话就输出0
    --第三个case when 判断scoure 是否为3,不是的话就输出0
    ,case s.scoure when 1 then s.sscore  else 0 end as '课程表001'
    ,case s.scoure when 2 then s.sscore  else 0 end as '课程表002'
    ,case s.scoure when 3 then s.sscore  else 0 end as '课程表003'
    FROM score s ;
     
    --第三步:
    SELECT s.sid 
    ,sum(case s.scoure when 1 then s.sscore  else 0 end) as '课程表001'
    ,sum(case s.scoure when 2 then s.sscore  else 0 end) as '课程表002'
    ,sum(case s.scoure when 3 then s.sscore  else 0 end) as '课程表003'
    FROM score s 
    group by  s.sid ;
     
    -- 12.1、-检索"0001"课程分数小于90,按分数降序排列的学生信息
    SELECT s2.*,s.*
    from score s 
    join student s2 on s.sid =s2.sid 
    where s.scoure =1 and s.sscore <90
    ORDER by s.sscore DESC ;
     
    --12.2、-查询不同老师所教不同课程平均分从高到低显示
     
    SELECT t.tname ,t.cteacher,AVG(s.sscore) 
    FROM score s 
    join course c on s.scoure =c.scoure 
    join teacher t on t.cteacher =c.cteacher 
    GROUP BY t.tname,t.cteacher  
    ORDER BY AVG(s.sscore) DESC;
     
    --12.3、查询课程名称为"数学",且分数低于90的学生姓名和分数
    SELECT s.sid,s.sname,s2.sscore 
    FROM student s 
    join score s2 on s.sid =s2.sid 
    join course c on s2.scoure =c.scoure 
    where c.cname ='数学' and s2.sscore <90;
     
    --12.4、查询任何一门课程成绩在70分以上的姓名、课程名称和分数
    SELECT s.sname ,c.cname ,s2.sscore 
    FROM student s
    join score s2 on s.sid =s2.sid
    join course c on s2.scoure =c.scoure 
    where s2.sscore >70;
     
    --12.5、查询两门及其以上不及格课程的同学的学号,姓名及其平均成绩
    SELECT s.sid ,s.sname ,avg(s2.sscore)
    FROM  student s 
    join score s2 on s.sid =s2.sid 
    where s2.sscore <90  --先过滤
    group by s.sid ,s.sname 
    HAVING count(*)>=2; --后对分组数据就行筛选
     
    -- 12.6、查询课程编号为“0001”的课程比“0002”的课程成绩等于或者低的所有学生的学号,成绩,和课程号
     
    --思路:把0001和0002课程的学生分别找出来然后对两个临时表进行join然后进行筛选
    --先把0001和0002课程的学生分别找出来
     
    SELECT a.* 
    FROM 
      (select * from score s where s.scoure=1) as a
      JOIN 
      (select * from score s where s.scoure=2) as b
    on a.sid =b.sid 
    where a.sscore <=b.sscore ;
    		     
    --12.7、查询学过“孟扎扎”老师所教的所有课的同学的学号、姓名
    SELECT s.sid,s.sname 
    from student s 
    join score s2 on s.sid =s2.sid 
    join course c on c.scoure =s2.scoure 
    join teacher t on t.cteacher =c.cteacher 
    where t.tname ='孟扎扎'
     
    -- 12.8、查询没学过"孟扎扎"老师讲授的任一门课程的学生姓名
    SELECT s3.sname 
    FROM student s3 
    where s3.sid not in 
    (
    SELECT s.sid  
    from student s 
    join score s2 on s.sid =s2.sid 
    join course c on c.scoure =s2.scoure 
    join teacher t on t.cteacher =c.cteacher 
    where t.tname ='孟扎扎'
    )
  • 相关阅读:
    SQL CREATE TABLE 语句
    SQL CREATE DATABASE 语句
    SQL INSERT INTO SELECT 语句
    SQL SELECT INTO 语句
    Why is chkconfig no longer available in Ubuntu?
    drag-html
    js利用offsetWidth和clientWidth来计算滚动条的宽度
    procomm plus
    很多shell命令后面的单横杠和双横杠,原来这个意思
    angular md-toast 颜色
  • 原文地址:https://www.cnblogs.com/karkash/p/16536576.html
Copyright © 2020-2023  润新知