MySQL之经典50道题

MySQL之经典50道题

一、创建数据表并插入数据

  • 1、学生表
    Student(s_id,s_name,s_birth,s_sex) :学生编号、姓名、年月、性别
-- 1、学生表
-- Student(s_id,s_name,s_birth,s_sex) :学生编号、姓名、年月、性别
CREATE TABLE
IF NOT EXISTS `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`)
) ENGINE = INNODB DEFAULT CHARSET = utf8;
-- 插入数据
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', '女');

   
   
    • 2、课程表
      Course(c_id,c_name,t_id) :课程编号、 课程名称、 教师编号
    -- 2、课程表
    -- Course(c_id,c_name,t_id) :课程编号、 课程名称、 教师编号
    CREATE TABLE
    IF NOT EXISTS `Course` (
    	`c_id` VARCHAR (20),
    	`c_name` VARCHAR (20) NOT NULL DEFAULT '',
    	`t_id` VARCHAR (20) NOT NULL,
    	PRIMARY KEY (`c_id`)
    ) ENGINE = INNODB DEFAULT CHARSET = utf8;
    -- 插入数据
    INSERT INTO Course VALUES ('01', '语文', '02');
    INSERT INTO Course VALUES ('02', '数学', '01');
    INSERT INTO Course VALUES ('03', '英语', '03');
    
         
         
      • 3、教师表
        Teacher(t_id,t_name) :教师编号、教师姓名
      -- 3、教师表
      -- Teacher(t_id,t_name) :教师编号、教师姓名
      CREATE TABLE
      IF NOT EXISTS `Teacher` (
      	`t_id` VARCHAR (20),
      	`t_name` VARCHAR (20) NOT NULL DEFAULT '',
      	PRIMARY KEY (`t_id`)
      ) ENGINE = INNODB DEFAULT CHARSET = utf8;
      -- 插入数据
      INSERT INTO Teacher VALUES ('01', '张三');
      INSERT INTO Teacher VALUES ('02', '李四');
      INSERT INTO Teacher VALUES ('03', '王五');
      
             
             
        • 4、成绩表
          Score(s_id,c_id,s_score) :学生编号、课程编号、分数
        -- 4、成绩表
        -- Score(s_id,c_id,s_score) :学生编号、课程编号、分数
        CREATE TABLE
        IF NOT EXISTS `Score` (
        	`s_id` VARCHAR (20),
        	`c_id` VARCHAR (20),
        	`s_score` INT (3),
        	PRIMARY KEY (`s_id`, `c_id`)
        ) ENGINE = INNODB DEFAULT CHARSET = utf8;
        -- 插入数据
        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);
        
                 
                 
        • 在这里插入图片描述

          二、开始解题

          2.1 题目1:查询"01"课程比"02"课程成绩高的学生的信息、课程分数

          • 需要输出Student表的全部信息和Score表中的s_score;
          -- 方法一:使用join连接
          SELECT
          	a.*, 
              b.s_score,
          	c.s_score
          FROM
          	Student a
          JOIN Score b ON a.s_id = b.s_id
          AND b.c_id = '01'
          JOIN Score c ON a.s_id = c.s_id
          AND c.c_id = '02'
          WHERE
          	b.s_score > c.s_score;
          

– 方法二:采用where语句
SELECT
a.*,
b.s_score,
c.s_score
FROM
Student a,
Score b,
Score c
WHERE
a.s_id = b.s_id
AND a.s_id = c.s_id
AND b.c_id = ‘01’
AND c.c_id = ‘02’
AND b.s_score > c.s_score;

  • 在这里插入图片描述

    2.2 题目2:查询平均成绩大于等于60分且总分大于200分的同学且必须考3门的学生编号和学生姓名和平均成绩

    SELECT
    	a.s_id,
    	a.s_name,
    	ROUND(AVG(b.s_score), 2) AS avg_score,
    	-- 求均值并保留2位小数
    	ROUND(SUM(b.s_score), 0) AS sum_score
      -- 求和并保留0位小数
    FROM
    	Student a
    JOIN Score b ON a.s_id = b.s_id
    GROUP BY
    	a.s_id
    HAVING
    	avg_score >= 60
    AND sum_score > 200
    AND COUNT(b.s_score)=3;
    
      
      
    • 在这里插入图片描述

      2.3 题目3:查询平均成绩小于60分的同学的学生编号、学生姓名、平均成绩(包括有成绩的和无成绩)

      SELECT
      	a.s_id,
      	a.s_name,
      	ROUND(AVG(b.s_score), 2) AS avg_score
      FROM
      	Student a
      LEFT JOIN Score b ON a.s_id = b.s_id
      GROUP BY
      	a.s_id
      HAVING
      	avg_score < 60;
      
          
          
      • 在这里插入图片描述

        • 上表所示的结果中没有"王菊",因为王菊没有成绩;
        • 以下代码筛选出没有成绩的同学王菊;
        SELECT
        	a.s_id,
        	a.s_name,
        	0 AS avg_score -- 将avg_score的值置为0
        FROM
        	Student a
        WHERE
        	a.s_id NOT IN (
        		-- 学生的学号不在给给定表的学号中
        		SELECT DISTINCT
        			s_id -- 查询出全部的学号
        		FROM
        			Score
        	);
        
              
              
        • 在这里插入图片描述

          • 可以将上述2个表进行合并,采用union函数,但表的数据列必须一致,上下合并数据表的函数有union和union all两个,区别在于union可以对数据进行去重,而union all则不去重;
          -- 方法1:采用union函数进行合并
          SELECT
          	a.s_id,
          	a.s_name,
          	ROUND(AVG(b.s_score), 2) AS avg_score
          FROM
          	Student a
          LEFT JOIN Score b ON a.s_id = b.s_id
          GROUP BY
          	a.s_id
          HAVING
          	avg_score < 60
          UNION
          SELECT
          	a.s_id,
          	a.s_name,
          	0 AS avg_score
          FROM
          	Student a
          WHERE
          	a.s_id NOT IN (
          		-- 学生的学号不在给给定表的学号中
          		SELECT DISTINCT
          			s_id -- 查询出全部的学号
          		FROM
          			Score
          	);
          
                  
                  
          • 在这里插入图片描述

            • 不采用union函数,采用ifnull和null函数进行筛选计算;
            -- 方法2:采用ifnull函数
            SELECT
            	S.s_id,
            	S.s_name,
            	ROUND(AVG(IFNULL(C.s_score, 0)), 2) AS avg_score -- ifnull 函数:第一个参数存在则取它本身,不存在取第二个值0
            FROM
            	Student S
            LEFT JOIN Score C ON S.s_id = C.s_id -- 一定要采用左连接
            GROUP BY
            	s_id
            HAVING
            	avg_score < 60;
            
                      
                      
            • 在这里插入图片描述

              -- 方法3:采用null函数
              SELECT
              	a.s_id,
              	a.s_name,
              	ROUND(AVG(b.s_score), 2) AS avg_score
              FROM
              	Student a
              LEFT JOIN Score b ON a.s_id = b.s_id
              GROUP BY
              	a.s_id
              HAVING
              	avg_score < 60
              OR avg_score IS NULL; -- 最后的NULL判断
              
                          
                          
              • 在这里插入图片描述

                2.4 题目4:查询所有同学的学生编号、学生姓名、选课总数、所有课程的总成绩

                SELECT
                	a.s_id,
                	a.s_name,
                	COUNT(b.c_id) AS count_course,
                	SUM(b.s_score) AS sum_socre
                FROM
                	Student a
                LEFT JOIN Score b ON a.s_id = b.s_id -- 采用left join,所以对于没有成绩的学生也可以筛选出来。
                GROUP BY
                	a.s_id;
                
                              
                              
                • 在这里插入图片描述

                  2.5 题目5:查询“李”姓老师的数量

                  • 采用通配符%和like关键字来解决。
                  SELECT
                  	COUNT(t_name) 
                  FROM
                  	Teacher 
                  WHERE
                  	t_name LIKE '李%'; -- 以李字开头的名字
                  
                                  
                                  
                  • 在这里插入图片描述

                    2.6 题目6:查询学过张三老师授课的同学信息

                    -- 方法1:通过筛选出张三的id,并匹配相应的课程id,最后将学生的成绩与课程id进行匹配,最后筛选出符合条件的学生。
                    SELECT
                    	a.* 
                    FROM
                    	Student a
                    	JOIN Score b ON a.s_id = b.s_id 
                    	AND b.c_id =(
                    	SELECT
                    		c_id 
                    	FROM
                    		Course 
                    	WHERE
                    		t_id =(
                    		SELECT
                    			t_id 
                    		FROM
                    			Teacher 
                    		WHERE
                    		t_name = '张三' 
                    	));
                    
                                      
                                      
                    • -- 方法2:通过left join进行匹配
                      SELECT
                      	a.* 
                      FROM
                      	Student a
                      	JOIN Score b ON a.s_id = b.s_id
                      	JOIN Course c ON b.c_id = c.c_id
                      	JOIN Teacher d ON c.t_id = d.t_id
                      	WHERE d.t_name='张三';
                      
                                          
                                          
                      • 在这里插入图片描述

                        2.7 题目7:找出没有学过张三老师课程的学生

                        • 和上面👆的题目是互补的,考虑取反操作。
                        -- 方法1:通过筛选出张三的id,并匹配相应的课程id,然后将学生的成绩与张三老师课程id进行匹配,最后筛选不在次学生id范围内的学生信息。
                        SELECT
                        	t3.*
                        FROM
                        	Student t3
                        WHERE
                        	t3.s_id NOT IN (
                        		SELECT
                        			t1.s_id
                        		FROM
                        			Score t1
                        		JOIN Course t2 ON t1.c_id = t2.c_id
                        		WHERE
                        			t_id = (
                        				SELECT
                        					t_id
                        				FROM
                        					Teacher
                        				WHERE
                        					t_name = '张三'
                        			)
                        	);
                        

– 方法2:使用join
SELECT
a.*
FROM
Student a
WHERE
a.s_id NOT IN (
SELECT
s_id
FROM
Score a
JOIN Course b ON a.c_id = b.c_id
JOIN Teacher c ON b.t_id = c.t_id
WHERE
c.t_name = ‘张三’
);

  • 在这里插入图片描述

    2.8 题目8:查询学过编号为01,并且学过编号为02课程的学生信息

    -- 方法1:通过自连接实现
    SELECT
    	a.*
    FROM
    	Student a
    WHERE
    	a.s_id IN (
    		SELECT
    			b.s_id
    		FROM
    			Score b
    		JOIN Score c ON b.s_id = c.s_id
    		WHERE
    			b.c_id = '01'
    		AND c.c_id = '02'
    	);
    

–方法2:通过where实现
SELECT
s1.*
FROM
Student s1,
Score s2,
Score s3
WHERE
s1.s_id = s2.s_id
AND s1.s_id = s3.s_id
AND s2.c_id = 01
AND s3.c_id = 02;

  • 在这里插入图片描述

    2.9 题目9:查询学过01课程,但是没有学过02课程的学生信息

    SELECT
    	s1.*
    FROM
    	Student s1
    WHERE
    	s1.s_id IN (
    		SELECT
    			s_id
    		FROM
    			Score
    		WHERE
    			c_id = '01'
    	) -- 修过01课程,要保留
    AND s1.s_id NOT IN (
    	SELECT
    		s_id
    	FROM
    		Score
    	WHERE
    		c_id = '02'
    );-- 哪些人修过02,需要排除
    
      
      
    • 在这里插入图片描述

      2.10 题目10:查询没有学完全部课程的同学的信息

      • 解题思路:在Course表中先计算总的课程数,后对学生进行分组,筛选出每组中课程数量少于总的课程数的学生。
      -- 方法1
      select s.* 
      from Student s  -- 学生表
      left join Score s1  -- 成绩表
      on s1.s_id = s.s_id
      group by s.s_id  -- 学号分组
      having count(s1.c_id) < (  -- 分组后学生的课程数<3
        select count(*) from Course  -- 全部课程数=3
      )
      -- 方法2
      select s.* 
      from Student s
      where s_id not in (
        select s_id 
        from Score s1
        group by s_id 
        having count(*) = (select count(*) from Course)
      );
      
          
          
      • 2.11 题目11:查询至少有一门课与学号为01的同学所学相同的同学的信息

        SELECT
        	b.* 
        FROM
        	student b
        	LEFT JOIN score c ON b.s_id = c.s_id 
        WHERE
        	c.c_id IN ( SELECT a.c_id FROM score a WHERE a.s_id = '01' ) 
        	AND b.s_id != '01' --排除01学生自己
        GROUP BY
        	b.s_id;
        
              
              
        • 在这里插入图片描述

          2.12 题目12:查询和01同学学习的课程完全相同的同学的信息

          • 方法1:因为总课程数3,而01号同学的课程数刚好是3,所以我们只要找出在Score表中课程也修满3门的同学即可。
          SELECT
          	b.* 
          FROM
          	student b
          	JOIN score c ON b.s_id = c.s_id 
          WHERE
          	b.s_id != '01' 
          GROUP BY
          	b.s_id 
          HAVING
          	COUNT( c.c_id )=(
          	SELECT
          		COUNT( c_id ) 
          	FROM
          		score 
          WHERE
          	s_id = '01')
          
                  
                  
          • 在这里插入图片描述

            • 方法2:使用group_concat函数(分组合并,同时排序)
              1)group_concat的使用方法为:
            group_concat([DISTINCT] 字段 [Order BY ASC/DESC 排序字段] [Separator '分隔符'])
            
                      
                      
            • SELECT
              	b.s_id,
              	b.s_name,
              	b.s_sex,
              	GROUP_CONCAT( c.c_id ORDER BY c.c_id ) AS concat_course 
              FROM
              	student b
              	JOIN score c ON b.s_id = c.s_id 
              GROUP BY
              	b.s_id 
              HAVING
              	GROUP_CONCAT( c.c_id ORDER BY c.c_id )=(
              	SELECT
              		GROUP_CONCAT( c_id ORDER BY c_id ) 
              	FROM
              		score 
              	WHERE
              		s_id = '01' 
              	);
              
                          
                          
              • 在这里插入图片描述

                2.13 题目13:查询没有修过张三老师讲授的任何一门课程的学生姓名

                -- 方法1
                SELECT
                	*
                FROM
                	student
                WHERE
                	s_id NOT IN (
                		SELECT DISTINCT
                			t1.s_id
                		FROM
                			score t1
                		JOIN course t2 ON t1.c_id = t2.c_id
                		WHERE
                			t2.t_id = (
                				SELECT
                					t_id
                				FROM
                					teacher
                				WHERE
                					t_name = '张三'
                			)
                	) 
                

– 方法2
SELECT
* – 4、学号取反找到学生信息
FROM
Student
WHERE
s_id NOT IN (
SELECT DISTINCT
(s_id) – 3、课程号找到对应的学号
FROM
Score
WHERE
c_id = (
SELECT
c_id – 2、教师编号找到对应的课程号
FROM
Course
WHERE
t_id = (
SELECT
t_id – 1、姓名找到教师编号
FROM
Teacher
WHERE
t_name = ‘张三’
)
)
);

  • 在这里插入图片描述

    2.14 题目14:查询两门及其以上不及格课程的同学的学号,姓名及其平均成绩

    SELECT
    	s.s_id,
    	s.s_name,
    	t.avg_score
    FROM
    	Student s
    JOIN (
    	SELECT
    		s_id,
    		ROUND(AVG(s_score)) avg_score  --求均值再取整
    	FROM
    		Score
    	WHERE
    		s_score < 60
    	GROUP BY
    		s_id
    	HAVING
    		COUNT(s_score) >= 2
    ) t ON s.s_id = t.s_id
    
      
      
    • 在这里插入图片描述

      2.15 题目15:LeetCode-for-SQL的第二题:第二高的薪水

      编写一个 SQL 查询,获取 Employee 表中第二高的薪水(Salary) 。
      ±—±-------+
      | Id | Salary |
      ±—±-------+
      | 1 | 100 |
      | 2 | 200 |
      | 3 | 300 |
      ±—±-------+
      例如上述 Employee 表,SQL查询应该返回 200 作为第二高的薪水。如果不存在第二高的薪水,那么查询应返回 null。
      ±--------------------+
      | SecondHighestSalary |
      ±--------------------+
      | 200 |
      ±--------------------+

      • 方法1:嵌套
      
      -- 第二高的薪水,除去最高薪水之后,在剩下的薪水中找最高的
      select 
          max(Salary) as SecondHighestSalary  -- 2、排除原数据中最高薪水之后,剩下的最大值就是第二高
      from Employee 
      where  Salary < (select max(Salary) from Employee);  -- 1、这个select是找到原始数据中的最高薪水
      
          
          
      • 缺点:当求第二高薪水的时候,只需要嵌套一层;如果求的是第3高,那么需要将第一高、第二高的同时排除,需要排除两次

        -- 嵌套方法:找出第三高的薪水
        select 
         max(Salary) as ThirdHighestSalary  -- 3、确定第3高
        from Employee 
        where Salary < ( 
            select 
              max(Salary) as SecondHighestSalary  -- 2、找到第二高
            from Employee 
            where  Salary < (select max(Salary) from Employee);  -- 1、找到第一高
        );
        
              
              
          • 方法1:使用 limit 关键字来实现翻页处理
            1)使用limit m,n的形式:m 表示从第 m 行数据之后,不包含第 m 行,之后的 n 行数据
            在这里插入图片描述
            1)使用limit m offset n形式:表示查询结果跳过 n 条数据,读取前 m 条数据
            在这里插入图片描述
          select
           distinct Salary  -- 去重
          from Employee
          order by Salary desc   -- 薪水降序
          limit 1 offset 1   -- 从第1行数据之后显示一行:除去最高的薪水之后再显示一行,也就是第二高的薪水
          
                  
                  
          • 如果原数据中只存在一个最高值,也就说不存在第二高薪水的时候,需要显示为null,我们对上面的结果使用ifnull函数来实现

            select ifnull((select distinct Salary   -- 如果不存在则赋值为null
                          from Employee
                          order by Salary desc   
                          limit 1 offset 1), null) as SecondHighestSalary
            
                      
                      
              • IFNULL() 函数用于判断第一个表达式是否为 NULL,如果为 NULL 则返回第二个参数的值,如果不为 NULL 则返回第一个参数的值。

              2.16 题目16:求出第n高的成绩(找出语文科目第2高的成绩和学号)

              SELECT DISTINCT
              	s.s_score --  分数去重
              FROM
              	Score s
              	LEFT JOIN Course c ON s.c_id = c.c_id 
              WHERE
              	c.c_name = '语文' -- 指定科目
              ORDER BY
              	s.s_score DESC -- 降序
              	LIMIT 1 OFFSET 1;-- limit和offset实现翻页功能
              
                          
                          
              • 在这里插入图片描述

                2.17 题目17:LeetCode-SQL-596-超过5名学生的课程

                有一个 courses 表 ,有 student (学生) 和 class (课程)。请列出所有超过或等于5名学生的课。例如,表:

                ±--------±-----------+
                | student | class |
                ±--------±-----------+
                | A | Math |
                | B | English |
                | C | Math |
                | D | Biology |
                | E | Math |
                | F | Computer |
                | G | Math |
                | H | Math |
                | I | Math |
                ±--------±-----------+
                最终的结果输出为:

                ±--------+
                | class |
                ±--------+
                | Math |
                ±--------+
                在最下面有个提示:学生在每个课中不应被重复计算。即如果A同学重修了Math课程,则不应该被计算在内。

                -- 方法1
                select
                 class
                from courses
                group by class
                having count(distinct student) >=5;   -- distinct去重关键
                

– 方法2
select
class
from(
select
distinct *
from courses) t – 临时表
group by class
having count(class) >= 5;

  • 本题中最大的陷阱就是有重修课程的同学,但是给出的数据中没有展现出来,所以上面的方法中都会出现去重的操作

    2.18 题目18:LeetCode-SQL-181-超过经理收入的员工

    Employee 表包含所有员工,他们的经理也属于员工。每个员工都有一个 Id,此外还有一列对应员工的经理的 Id。

    ±—±------±-------±----------+
    | Id | Name | Salary | ManagerId |
    ±—±------±-------±----------+
    | 1 | Joe | 70000 | 3 |
    | 2 | Henry | 80000 | 4 |
    | 3 | Sam | 60000 | NULL |
    | 4 | Max | 90000 | NULL |
    ±—±------±-------±----------+
    给定 Employee 表,编写一个 SQL 查询,该查询可以获取收入超过他们经理的员工的姓名。在上面的表格中,Joe 是唯一一个收入超过他的经理的员工。

    ±---------+
    | Employee |
    ±---------+
    | Joe |
    ±---------+
    题目利用如下的图形解释:Joe是员工,工资是70000,经理是编号3,也就是Sam,但是Sam工资只有60000
    在这里插入图片描述

    -- 方法1:自连接
    select
        e1.Name as Employee
    from Employee e1  -- 表的自连接
    left join Employee e2
    on e1.ManagerId = e2.Id  -- 连接条件
    where e1.Salary > e2.Salary
    

– 方法2:where条件过滤
select
a.Name as Employee
from Employee as a,Employee as b -
where a.ManagerId = b.Id
and a.Salary > b.Salary;

  • 2.19 题目19:检索01课程分数小于60,按分数降序排列的学生信息

    SELECT
    	t1.s_id
    	,t1.s_name
    	,t1.s_birth
    	,t1.s_sex
    	,t2.s_score
    FROM
    	student t1
    	JOIN score t2 ON t1.s_id = t2.s_id 
    WHERE
    	t2.c_id = 01 
    	AND t2.s_score < 60
    	ORDER BY t2.s_score DESC;
    
      
      
    • 在这里插入图片描述

      2.20 题目20:按平均成绩从高到低(降序)显示所有学生的所有课程的成绩以及平均成绩

      -- 方法1
      SELECT
      	t1.s_id,
      	t1.c_id,
      	t1.s_score,
      	t2.avg_score
      FROM
      	score t1
      JOIN ( -- 创建临时表,并进行连接
      	SELECT
      		s_id,
      		ROUND(AVG(s_score), 2) avg_score
      	FROM
      		score
      	GROUP BY
      		s_id
      ) t2 ON t1.s_id = t2.s_id
      ORDER BY
      	4 DESC; -- 按照select中的第4列进行降序排列
      
          
          
      • 在这里插入图片描述
        为何采用聚合函数MAX

        -- 方法2:采用case when then end语句
        SELECT
        	s.s_id,
        	MAX(CASE s.c_id WHEN '01' THEN s.s_score END) 语文,
        	MAX(CASE s.c_id WHEN '02' THEN s.s_score END) 数学,
        	MAX(CASE s.c_id WHEN '03' THEN s.s_score END) 英语,
        	ROUND(AVG(s.s_score), 2) avg_score
        FROM
        	score s
        GROUP BY
        	s.s_id
        ORDER BY
        	5 DESC;
        
              
              
        • 在这里插入图片描述

          • 注意的点:对于下面的例子而言
          select 
           s.s_id
           ,max(case s.c_id when '01' then s.s_score end) 语文
           ,max(case s.c_id when '02' then s.s_score end) 数学
           ,max(case s.c_id when '03' then s.s_score end) 英语
           ,avg(s.s_score)
           ,b.s_name  -- 没有出现在group by子句中,导致报错
          from score s
          join Student b
          on s.s_id = b.s_id
          group by s.s_id
          order by 5 desc;
          
                  
                  
            • 严格模式的报错
              ERROR 1055 (42000): Expression #6 of SELECT list is not in GROUP BY clause and contains nonaggregated column ‘test.b.s_name’ which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by
            • 原因在于MySQL语句模式为only_full_group_by,即对于在SELECT中的列,除了采用聚合函数的列以外,其他的列必须出现在GROUP BY中,否则认为SQL语句是不合法的。
            • 上述的MySQL语句应修改为
            select 
             s.s_id
             ,max(case s.c_id when '01' then s.s_score end) 语文 -- 由于有些数据是空值,所以必须采用聚合函数,才能将真实值取出
             ,max(case s.c_id when '02' then s.s_score end) 数学
             ,max(case s.c_id when '03' then s.s_score end) 英语
             ,avg(s.s_score)
             ,b.s_name  -- 没有出现在group by子句中,导致报错
            from score s
            join Student b
            on s.s_id = b.s_id
            group by s.s_id, b.s_name
            order by 5 desc;
            
                      
                      
            • 2.21 题目21:查询各科成绩最高分、最低分和平均分:以如下形式显示:课程ID,课程name,最高分,最低分,平均分,及格率(及格:>=60),中等率(中等为:70-80),优良率(优良为:80-90),优秀率(优秀为:>=90);—比较综合,多看!

              • 一道比较综合的题目
              SELECT
              	t1.c_id,
              	t2.c_name
                  ,MAX(t1.s_score) max_score
              	,MIN(t1.s_score) min_score
              	,ROUND(AVG(t1.s_score),2) avg_score
              	,ROUND(100*(SUM(CASE WHEN t1.s_score>=60 THEN 1 ELSE 0 END)/sum(CASE WHEN t1.s_score THEN 1 ELSE 0 END)),2) AS '及格率'
              	,ROUND(100*(SUM(CASE WHEN t1.s_score>=70 AND t1.s_score<=80 THEN 1 ELSE 0 END)/sum(CASE WHEN t1.s_score THEN 1 ELSE 0 END)),2) AS '中等率'
              	,ROUND(100*(SUM(CASE WHEN t1.s_score>=80 AND t1.s_score<=90 THEN 1 ELSE 0 END)/sum(CASE WHEN t1.s_score THEN 1 ELSE 0 END)),2) AS '优良率'
              	,ROUND(100*(SUM(CASE WHEN t1.s_score>=90 THEN 1 ELSE 0 END)/sum(CASE WHEN t1.s_score THEN 1 ELSE 0 END)),2) AS '优秀率'
              FROM
              	score t1
              JOIN course t2 ON t1.c_id = t2.c_id
              GROUP BY
              	t1.c_id,
              	t2.c_name;
              
                          
                          
              • 在这里插入图片描述

                2.22 题目22:按照各科成绩进行排序,并且显示排名—比较综合,多看!

                • MySQL进行排序、排名方式
                select * from (select 
                                t1.c_id,
                                t1.s_score,
                                (select count(distinct t2.s_score) 
                                 from Score t2 
                                 where t2.s_score>=t1.s_score and t2.c_id='01') rank
                              from Score t1 where t1.c_id='01'
                              order by t1.s_score desc) t1
                

union
select * from (select
t1.c_id
,t1.s_score
,(select count(distinct t2.s_score)
from Score t2
where t2.s_score>=t1.s_score and t2.c_id=‘02’) rank
from Score t1 where t1.c_id=‘02’
order by t1.s_score desc) t2

union
select * from (select
t1.c_id,
t1.s_score,
(select count(distinct t2.s_score) from Score t2 where t2.s_score>=t1.s_score and t2.c_id=‘03’) rank
from Score t1 where t1.c_id=‘03’
order by t1.s_score desc) t3

  • 在这里插入图片描述

    2.23 题目23:查询学生的总成绩,并进行排名—比较综合,多看!

    select 
     t1.s_id ,t1.s_name, t1.score
     ,(select count(t2.score)
        from(select s.s_id, s.s_name, sum(sc.s_score) score
             from Student s
             join Score sc
             on s.s_id = sc.s_id
             group by s.s_id
             order by 3 desc)t2   -- t2和t1相同
        where t2.score >= t1.score) as rank
    from(
      select s.s_id ,s.s_name ,sum(sc.s_score) score
      from Student s
      join Score sc
      on s.s_id = sc.s_id
      group by s.s_id
      order by 3 desc)t1   -- t1
    order by 3 desc;
    
      
      
    • 在这里插入图片描述

      2.24 题目24:LeetCode-SQL-182-查找重复的电子邮箱,从给定的表Person中找出重复的电子邮箱

      在这里插入图片描述

      -- 方法1
      select 
          Email
      from Person 
      group by Email
      having count(Email) > 1;  -- 过滤条件
      

– 方法2
select
distinct (p1.Email) – 去重统计邮箱
from Person p1
join Person p2 on p1.Email = p2.Email and p1.Id != p2.Id; – 指定连接条件

  • 2.25 题目25:LeetCode-SQL-595-大的国家

    在这里插入图片描述

    select 
        name
        ,population
        ,area
    from World 
    where area > 3000000
    or population > 25000000; 
    
      
      
    • 2.26 题目26:LeetCode-SQL-184-部门工资最高/N高的员工—多看

      在这里插入图片描述

      -- 方法1
      SELECT
          Department.name AS 'Department',
          Employee.name AS 'Employee',
          Salary
      FROM Employee 
      INNER JOIN Department ON Employee.DepartmentId = Department.Id
      WHERE (Employee.DepartmentId , Salary) IN (  -- 两个字段同时使用
        SELECT 
         DepartmentId, -- 部门分组找出部门号和薪水的最大值
         MAX(Salary)  
        FROM Employee 
        GROUP BY DepartmentId
      )
      

– 方法2:
select
d.Name Department
,e.Name Employee
,e.Salary Salary
from Employee e , Department d
where e.DepartmentId = d.Id – 在同一个部门中进行比计较
and e.Salary >= (select max(Salary) from Employee where DepartmentId=d.Id); – 找出每个部门的最高值;如果大于等于这个最高值,肯定是最高的

    • 寻找排名第一或者第三的员工
    • 窗口排名函数只有在hive和MySQL 8.X才有
    SELECT S.NAME, S.EMPLOYEE, S.SALARY
    FROM (SELECT 
            d.Name,
            e.Name Employee,
            e.Salary,
            dense_rank() OVER(PARTITION BY e.DepartmentId ORDER BY e.Salary DESC) number -- 根据部门分区,薪水排序
          FROM Employee e
          LEFT JOIN Department d
          ON e.DepartmentId = d.Id) S
     WHERE S.number = 1 or S.number =3;  -- 排名第一或者第三
    
      
      
    • 2.27 题目27:查询不同老师所教不同课程平均分从高到低显示

      SELECT
      	t2.t_name,
          t2.c_name,
      	ROUND(AVG(t1.s_score), 2) AS avg_score
      FROM
      	score t1
      JOIN (
      	SELECT
      		a.t_name,
      		b.c_id,
          b.c_name
      	FROM
      		teacher AS a,
      		course AS b
      	WHERE
      		a.t_id = b.t_id
      ) t2 ON t1.c_id = t2.c_id
      GROUP BY t2.t_name, t2.c_name
      ORDER BY ROUND(AVG(t1.s_score), 2) DESC;
      
          
          
      • 在这里插入图片描述

        • 注意:
          1)上题中,最好将在select语句中除聚合函数外的列全部放到group by语句后;
          2)上题中,由于select语句比order by语句先执行,所以在order by后必须使用ORDER BY ROUND(AVG(t1.s_score), 2) DESC,而不能采用别名avg_score;

        2.28 题目28:查询所有课程的成绩第2名到第3名的学生信息及该课程成绩

        • 该题目采用union函数进行合并,但合并的数据必须包含相同的列;
        SELECT
        	s.s_id,
        	s.s_name,
        	t.c_name,
        	t.s_score
        FROM
        	Student s
        JOIN (
        	-- union连接
        	(
        		SELECT
        			s.s_id,
        			s.s_score,
        			c.c_name
        		FROM
        			Score s
        		JOIN Course c ON s.c_id = c.c_id
        		WHERE
        			c.c_name = '语文'
        		ORDER BY
        			s.s_score DESC
        		LIMIT 1,2 -- 从第1行数据之后取2行,即取第2,3行数据
        	)
        	UNION
        		(
        			SELECT
        				s.s_id,
        				s.s_score,
        				c.c_name
        			FROM
        				Score s
        			JOIN Course c ON s.c_id = c.c_id
        			WHERE
        				c.c_name = '数学'
        			ORDER BY
        				s.s_score DESC
        			LIMIT 1, 2)
        	UNION
        			(
        				SELECT
        					s.s_id,
        					s.s_score,
        					c.c_name
        				FROM
        					Score s
        				JOIN Course c ON s.c_id = c.c_id
        				WHERE
        					c.c_name = '英语'
        				ORDER BY
        					s.s_score DESC
        				LIMIT 1, 2)
        ) t -- 临æ¶表t
        ON s.s_id = t.s_id
        GROUP BY
          t.c_name,
          s.s_id,
          s.s_name,
          t.s_score
        
              
              
        • 在这里插入图片描述

          • 注意:每一个子查询,即括号中的部分,不需要将查询结果组成的表重命名,否则会报错。

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

          SELECT
          	s.c_id,
          	c.c_name,
          	sum( CASE WHEN s_score > 85 AND s_score <= 100 THEN 1 ELSE 0 END ) AS '85-100',
          	round( 100 * ( sum( CASE WHEN s_score > 85 AND s_score <= 100 THEN 1 ELSE 0 END ) / count(*)), 2 ) '[85,100]占比',
          	sum( CASE WHEN s_score > 70 AND s_score <= 85 THEN 1 ELSE 0 END ) AS '70-85',
          	round( 100 * ( sum( CASE WHEN s_score > 70 AND s_score <= 85 THEN 1 ELSE 0 END ) / count(*)), 2 ) '[70,85]占比',
          	sum( CASE WHEN s_score > 60 AND s_score <= 70 THEN 1 ELSE 0 END ) AS '60-70',
          	round( 100 * ( sum( CASE WHEN s_score > 60 AND s_score <= 70 THEN 1 ELSE 0 END ) / count(*)), 2 ) '[60,70]占比',
          	sum( CASE WHEN s_score >= 0 AND s_score <= 60 THEN 1 ELSE 0 END ) AS '0-60',
          	round( 100 * ( sum( CASE WHEN s_score > 0 AND s_score <= 60 THEN 1 ELSE 0 END ) / count(*)), 2 ) '[0,60]占比' 
          FROM
          	Score s
          	LEFT JOIN Course c ON s.c_id = c.c_id 
          GROUP BY
          	s.c_id,
          	c.c_name;-- 分课程统计总数和占比
          
                  
                  
          • 在这里插入图片描述

            • 注意:本题目是将case when then end函数和聚合函数一起使用。

            2.30 题目30:查询学生的平均成绩及名次—比较综合,多看,定义变量,实现rank函数

            • 自定义变量实现rank排序
            select
             a.s_id  -- 学号
             ,@i:=@i+1 as '不保留空缺排名'   -- 直接i的自加,顺序一直变大,声明变量需加@
             ,@k:=(case when @avg_score=a.avg_s then @k else @i+1 end) as '保留空缺排名' -- 只有在前后二次排序值不同时才会使顺序号加1
             ,@avg_score:=avg_s as '平均分'  -- 表a中的值
            from (select 
                   s_id
                   ,round(avg(s_score), 2) as avg_s
                  from Score 
                  group by s_id
                  order by 2 desc)a    -- 表a:平均成绩的排序和学号
                  ,(select @avg_score:=0, @i:=0, @k:=0)b   -- 表b:进行变量初始化,固定写法。
            
                      
                      
            • 在这里插入图片描述

              • 另一种实现排序的方式
              select 
                t1.c_id, 
              	t1.s_score-- 成绩
               ,(select count(distinct t2.s_score) -- 排名从1开始
                  from Score t2
                  where t2.s_score >= t1.s_score) 排名   -- 在t2分数大的情况下,统计t2的去重个数
              from Score t1
              group by t1.c_id, t1.s_score
              order by t1.s_score desc;   -- 分数降序排列
              
                          
                          
              • 在这里插入图片描述

                2.31 题目31:查询各科成绩前三名的记录—比较综合,多看

                • 采用union可以实现,即将各科分别筛选出来再进行union合并,但是当科目特别多时,会比价耗时,所以采用自连接的方式进行筛选。
                select
                 a.s_id
                 ,a.c_id
                 ,a.s_score   -- a表的成绩
                from Score a
                join Score b
                on a.c_id = b.c_id
                and a.s_score <= b.s_score   -- 判断a的分数小于等于b的分数,要带上等号
                group by 1,2,3
                having count(b.s_id) <= 3   -- b中的个数至少有3个,应对分数相同的情形
                order by 2, 3 desc;   -- 课程(2)的升序,成绩(3)的降序
                
                              
                              
                • 在这里插入图片描述

                  2.32 题目32:查询每门课被选修的学生数

                  select 
                   c.c_id
                   ,c.c_name
                   ,count(s.s_id)
                  from Course c
                  join Score s
                  on c.c_id = s.c_id
                  group by 1,2;
                  
                                  
                                  
                  • 在这里插入图片描述

                    2.33 题目33:查询出只有两门课程的全部学生的学号和姓名

                    SELECT
                    t1.s_id
                    ,t1.s_name
                    FROM
                    student t1
                    JOIN score t2 ON t1.s_id=t2.s_id
                    GROUP BY 1,2
                    HAVING COUNT(t2.s_score)=2;
                    
                                      
                                      
                    • 在这里插入图片描述

                      2.34 题目34:查询男女生人数

                      select 
                       s_sex
                       ,count(s_sex) as `人数`
                      from Student
                      group by s_sex;
                      
                                          
                                          
                      • 在这里插入图片描述

                        2.35 题目35:查询名字中含有风字的学生信息

                        -- 模糊匹配:在两边都加上了%,考虑的是姓或者名字含有风
                        select * from Student where s_name like "%风%";
                        
                                              
                                              
                        • 在这里插入图片描述

                          2.36 题目36:查询同名同性的学生名单,并统计同名人数

                          select 
                           a.s_name
                           ,a.s_sex
                           ,count(*)
                          from Student a  -- 同一个表的自连接
                          join Student b
                          on a.s_id != b.s_id   -- 连接的时候不能是同一个人:学号保证,每个人的学号是唯一的,其他字段都可能重复
                          and a.s_sex = b.s_sex  -- 性别相同
                          and a.s_name = b.s_name -- 名字相同
                          group by 1,2;
                          
                                                  
                                                  
                          • 在这里插入图片描述

                            2.37 题目37:查询每门课程的平均成绩,结果按平均成绩降序排列;平均成绩相同时,按课程编号c_id升序排列

                            select 
                             c.c_id
                             ,c.c_name
                             ,round(avg(sc.s_score),2) avg_score
                            from Score sc
                            join Course c
                            on sc.c_id = c.c_id
                            group by 1,2
                            order by 3 desc, c.c_id;  -- 指定字段和排序方法
                            
                                                      
                                                      
                            • 在这里插入图片描述

                              2.38 题目38:查询平均成绩大于等于85的所有学生的学号、姓名和平均成绩

                              select 
                               sc.s_id
                               ,s.s_name
                               ,round(avg(sc.s_score),2) avg_score
                              from Score sc
                              join Student s
                              on sc.s_id = s.s_id
                              group by sc.s_id,s.s_name
                              having avg_score >= 85;
                              
                                                          
                                                          
                              • 在这里插入图片描述

                                2.39 题目39:查询所有学生的课程及分数(均分、总分)情况

                                select 
                                  s.s_id
                                 ,s.s_name
                                 ,sum(case c.c_name when '语文' then sc.s_score else 0 end) as '语文'  -- 语文分数
                                 ,sum(case c.c_name when '数学' then sc.s_score else 0 end) as '数学'
                                 ,sum(case c.c_name when '英语' then sc.s_score else 0 end) as '英语'
                                 ,round(avg(sc.s_score),2) as '平均分'  -- 每个人的平均分 
                                 ,sum(sc.s_score) as '总分'  -- 每个人的总分
                                from Student s
                                left join Score sc
                                on s.s_id = sc.s_id
                                left join Course c 
                                on sc.c_id = c.c_id
                                group by s.s_id, s.s_name;   -- 学号和姓名的分组
                                
                                                              
                                                              
                                • 在这里插入图片描述

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

                                  SELECT
                                  	t1.s_id,
                                  	t1.s_name,
                                  	t1.s_sex,
                                      t1.s_birth,
                                  	t3.c_name,
                                      t3.c_id,
                                  	MAX(t2.s_score)
                                  FROM
                                  	student t1
                                  JOIN score t2 ON t1.s_id = t2.s_id
                                  JOIN course t3 ON t2.c_id = t3.c_id
                                  JOIN teacher t4 ON t3.t_id = t4.t_id
                                  WHERE
                                  	t4.t_name = '张三';
                                  
                                                                  
                                                                  
                                  • 在这里插入图片描述

                                    2.41 题目41:查询不同课程成绩相同的学生的学生编号、课程编号、学生成绩—比较综合,多看!一个表自连

                                    • 3个字段同时在一个表中,所以我们可以通过一个表Score的自连接来实现查出。
                                    select
                                      a.s_id
                                     ,a.c_id
                                     ,a.s_score
                                    from Score a
                                    join Score b
                                    on a.c_id != b.c_id
                                    and a.s_score = b.s_score
                                    and a.s_id != b.s_id
                                    group by 1,2,3;
                                    
                                                                      
                                                                      
                                    • 在这里插入图片描述

                                      2.42 题目42:题目的要求就是找出每门课的前2名同学—多看,比较综合,解决前几名排序的问题

                                      • 解决前几名排序的问题,特别好的方法!
                                      SELECT
                                      	a.c_id,
                                      	a.s_id,
                                      	a.s_score 
                                      FROM
                                      	Score a 
                                      WHERE
                                      	( SELECT count( 1 ) -- count(1)类似count(*):统计表b中分数大的数量
                                      		FROM Score b WHERE b.c_id = a.c_id -- 课程相同
                                      	AND b.s_score >= a.s_score ) <= 2 -- 前2名
                                      ORDER BY
                                      	a.c_id;
                                      
                                                                          
                                                                          
                                      • 在这里插入图片描述

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

                                        SELECT
                                        	c_id,
                                        	COUNT( s_id ) num 
                                        FROM
                                        	score 
                                        GROUP BY
                                        	c_id 
                                        HAVING
                                        	COUNT( s_id ) > 5 
                                        ORDER BY
                                        	COUNT( s_id ) DESC, c_id;
                                        
                                                                              
                                                                              
                                        • 在这里插入图片描述

                                          2.44 题目44:检索至少选修两门课程的学生学号

                                          SELECT
                                          	s_id,
                                          	count(*) num 
                                          FROM
                                          	Score 
                                          GROUP BY
                                          	s_id 
                                          HAVING
                                          	count(*) >= 2;
                                          
                                                                                  
                                                                                  
                                          • 在这里插入图片描述

                                            2.45 题目45:查询选修了全部课程的学生信息

                                            select *   -- 3、s_id对应的学生信息
                                            from Student 
                                            where s_id in(select s_id -- 2、最大课程数对应的s_id
                                                          from Score 
                                                          group by s_id 
                                                          having count(*)=(select count(*) from Course)  -- 1、全部课程数
                                                         )
                                            
                                                                                      
                                                                                      
                                            • 在这里插入图片描述

                                              2.46 题目46:查询各学生的年龄:按照出生日期来算,当前月日 < 出生年月的月日则,年龄减1

                                              select
                                               s_name
                                               ,s_birth
                                               ,date_format(now(), '%Y') - date_format(s_birth, '%Y') - (case when date_format(now(), '%m%d') < date_format(s_birth, '%m%d') then 1 else 0 end) as age  -- 当前日期大,说明已经过生了,年龄正常;反之说明今年还没有到年龄-1
                                              from Student;
                                              
                                                                                          
                                                                                          
                                              • 在这里插入图片描述

                                                2.47 题目47:查询本周过生日的学生

                                                select * from Student where week(date_format(now(),'%Y%m%d')) = week(s_birth);  -- 方式1
                                                

select * from student where yearweek(s_birth) = yearweek(date_format(now(),‘%Y%m%d’)); – 方式2

  • 在这里插入图片描述

    2.48 题目48:查询下周过生日的学生

    select * from Student where week(date_format(now(),'%Y%m%d')) + 1= week(s_birth); 
    
      
      
    • 在这里插入图片描述

      • 边界问题
        如果现在刚好的是今年的最后一个周,那么下周就是明年的第一个周,我们如何解决这个问题呢??改进后的脚本:
      select * from Student
      where mod(week(now()), 52) + 1 =  week(s_birth);
      
          
          
      • 当现在刚好是第52周,那么mod函数的结果是0,则说明出生的月份刚好是明年的第一周

        2.49 题目49:查询本月过生的同学

        select * from Student where month(date_format(now(), '%Y%m%d')) = month(s_birth);
        
              
              
        • 在这里插入图片描述

          2.50 题目50:查询下月过生的同学

          select * from Student
          where month(date_format(now(), '%Y%m%d')) + 1= month(s_birth);
          
                  
                  
          • 在这里插入图片描述

            • 边界问题
              假设现在是12月份,那么下个月就是明年的1月份,我们如何解决???将上面的代码进行改进:
            select * from Student
            where mod(month(now()),12)  + 1 =  month(s_birth);
            
                      
                      
              • 如果现在是12月份,则mod函数的结果是0,说明生日刚好是1月份
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值