• MySQL练习


    1、组合两个表

    • 表1: Person
    +-------------+---------+
    | 列名         | 类型     |
    +-------------+---------+
    | PersonId    | int     |
    | FirstName   | varchar |
    | LastName    | varchar |
    +-------------+---------+
    PersonId 是上表主键
    
    • 表2: Address
    +-------------+---------+
    | 列名         | 类型    |
    +-------------+---------+
    | AddressId   | int     |
    | PersonId    | int     |
    | City        | varchar |
    | State       | varchar |
    +-------------+---------+
    AddressId 是上表主键
    

    编写一个 SQL 查询,满足条件:无论 person 是否有地址信息,都需要基于上述两表提供 person 的以下信息:

    FirstName, LastName, City, State
    

    Sql如下:

    select p.FirstName, p.LastName, a.City, a.State 
    from 
    Person p left join Address a on p.PersonId=a.PersonId;
    

    2、第二高的薪水

    编写一个 SQL 查询,获取 Employee 表中第二高的薪水(Salary) 。

    +----+--------+
    | Id | Salary |
    +----+--------+
    | 1  | 100    |
    | 2  | 200    |
    | 3  | 300    |
    +----+--------+
    

    例如上述 Employee 表,SQL查询应该返回 200 作为第二高的薪水。如果不存在第二高的薪水,那么查询应返回 null。

    +---------------------+
    | SecondHighestSalary |
    +---------------------+
    | 200                 |
    +---------------------+
    

    Sql如下:

    select 
    (select distinct Salary 
    from 
    employee order by Salary desc
    limit 1 offset 1) as SecondHighestSalary;
    

    备注分析:

    用到升序 order by col desc
    接着是limit 1,1  其中第一个1表示跳过数,第二个1表示输出多少数
    可能考虑多个并列第二,用distinct去重
    

    3、超过经理收入的员工

    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      |
    +----------+
    

    sql如下:

    select a.Name as Employee
    from 
    Employee a,
    Employee b where 
    a.ManagerId=b.Id and a.Salary>b.Salary;
    

    4、查找重复的电子邮箱

    编写一个 SQL 查询,查找 Person 表中所有重复的电子邮箱。

    +----+---------+
    | Id | Email   |
    +----+---------+
    | 1  | a@b.com |
    | 2  | c@d.com |
    | 3  | a@b.com |
    +----+---------+
    
    

    根据以上输入,你的查询应返回以下结果:

    +---------+
    | Email   |
    +---------+
    | a@b.com |
    +---------+
    

    sql如下:

    #select a.Email from (select Email,count(Email) c from Person group by Email having c>1) a;
    
    select Email from Person group by Email having count(Email)>1;
    

    备注分析:

    用group by 统计Email 重复次数,过滤掉大于1的行,再查询单独列
    

    5、从不订购的客户

    某网站包含两个表,Customers 表和 Orders 表。编写一个 SQL 查询,找出所有从不订购任何东西的客户。

    • Customers 表:
    +----+-------+
    | Id | Name  |
    +----+-------+
    | 1  | Joe   |
    | 2  | Henry |
    | 3  | Sam   |
    | 4  | Max   |
    +----+-------+
    
    • Orders 表:
    +----+------------+
    | Id | CustomerId |
    +----+------------+
    | 1  | 3          |
    | 2  | 1          |
    +----+------------+
    

    例如给定上述表格,你的查询应返回:

    +-----------+
    | Customers |
    +-----------+
    | Henry     |
    | Max       |
    +-----------+
    

    sql如下:

    select Name as Customers 
    from Customers 
    where Id not in (select CustomerId from Orders);
    

    备注分析:

    查询客户表的id不在订单表CustomerId的行
    

    6、部门工资最高的员工

    Employee 表包含所有员工信息,每个员工有其对应的 Id, salary 和 department Id。

    +----+-------+--------+--------------+
    | Id | Name  | Salary | DepartmentId |
    +----+-------+--------+--------------+
    | 1  | Joe   | 70000  | 1            |
    | 2  | Jim   | 90000  | 1            |
    | 3  | Henry | 80000  | 2            |
    | 4  | Sam   | 60000  | 2            |
    | 5  | Max   | 90000  | 1            |
    +----+-------+--------+--------------+
    

    Department 表包含公司所有部门的信息。

    +----+----------+
    | Id | Name     |
    +----+----------+
    | 1  | IT       |
    | 2  | Sales    |
    +----+----------+
    

    编写一个 SQL 查询,找出每个部门工资最高的员工。对于上述表,您的 SQL 查询应返回以下行(行的顺序无关紧要)。

    +------------+----------+--------+
    | Department | Employee | Salary |
    +------------+----------+--------+
    | IT         | Max      | 90000  |
    | IT         | Jim      | 90000  |
    | Sales      | Henry    | 80000  |
    +------------+----------+--------+
    

    sql如下:

    select  d.Name as Department,e.Name as Employee,e.Salary 
    from Employee e
    join Department d on e.DepartmentId=d.Id
    where 
    (e.DepartmentId,e.Salary) in 
    (select  DepartmentId,Max(Salary) from Employee group by DepartmentId)
    

    备注分析:

    用到Max()函数取最大值,并对部门id进行分组,
    join两表,where判断部门id和薪水 是否在最大值的分组表中存在
    

    7、上升的温度

    • 表 Weather
    +---------------+---------+
    | Column Name   | Type    |
    +---------------+---------+
    | id            | int     |
    | recordDate    | date    |
    | temperature   | int     |
    +---------------+---------+
    id 是这个表的主键
    该表包含特定日期的温度信息
    

    编写一个 SQL 查询,来查找与之前(昨天的)日期相比温度更高的所有日期的 id 。返回结果 不要求顺序 。
    查询结果格式如下例:

    Weather
    +----+------------+-------------+
    | id | recordDate | Temperature |
    +----+------------+-------------+
    | 1  | 2015-01-01 | 10          |
    | 2  | 2015-01-02 | 25          |
    | 3  | 2015-01-03 | 20          |
    | 4  | 2015-01-04 | 30          |
    +----+------------+-------------+
    
    Result table:
    +----+
    | id |
    +----+
    | 2  |
    | 4  |
    +----+
    2015-01-02 的温度比前一天高(10 -> 25)
    2015-01-04 的温度比前一天高(20 -> 30)
    

    sql如下:

    select w1.id from Weather w1
    join Weather w2 on datediff(w1.recordDate,w2.recordDate)=1
    where w1.Temperature>w2.Temperature
    

    备注分析:

    利用datediff(date1,date2)函数,返回date1-date2的天数做join判断,
    再用where判断date1的温度大于date2的温度
    

    8、大的国家

    这里有张 World 表

    +-----------------+------------+------------+--------------+---------------+
    | name            | continent  | area       | population   | gdp           |
    +-----------------+------------+------------+--------------+---------------+
    | Afghanistan     | Asia       | 652230     | 25500100     | 20343000      |
    | Albania         | Europe     | 28748      | 2831741      | 12960000      |
    | Algeria         | Africa     | 2381741    | 37100000     | 188681000     |
    | Andorra         | Europe     | 468        | 78115        | 3712000       |
    | Angola          | Africa     | 1246700    | 20609294     | 100990000     |
    +-----------------+------------+------------+--------------+---------------+
    

    如果一个国家的面积超过 300 万平方公里,或者人口超过 2500 万,那么这个国家就是大国家。

    编写一个 SQL 查询,输出表中所有大国家的名称、人口和面积。

    例如,根据上表,我们应该输出:

    +--------------+-------------+--------------+
    | name         | population  | area         |
    +--------------+-------------+--------------+
    | Afghanistan  | 25500100    | 652230       |
    | Algeria      | 37100000    | 2381741      |
    +--------------+-------------+--------------+
    

    sql如下:

    select name,population,area from World
    where area>3000000 or population>25000000
    

    9、超过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    |
    +---------+
    

    sql如下:

    select class
    from courses group by class
    having count(DISTINCT student)>=5
    

    备注分析:

    利用group by 分组,过滤count(student)大于等于5的,在having 中用distinct过滤同名学生
    

    10、有趣的电影

    某城市开了一家新的电影院,吸引了很多人过来看电影。该电影院特别注意用户体验,专门有个 LED显示板做电影推荐,上面公布着影评和相关电影描述。

    作为该电影院的信息部主管,您需要编写一个 SQL查询,找出所有影片描述为非 boring (不无聊) 的并且 id 为奇数 的影片,结果请按等级 rating 排列。

    例如,下表 cinema:

    +---------+-----------+--------------+-----------+
    |   id    | movie     |  description |  rating   |
    +---------+-----------+--------------+-----------+
    |   1     | War       |   great 3D   |   8.9     |
    |   2     | Science   |   fiction    |   8.5     |
    |   3     | irish     |   boring     |   6.2     |
    |   4     | Ice song  |   Fantacy    |   8.6     |
    |   5     | House card|   Interesting|   9.1     |
    +---------+-----------+--------------+-----------+
    

    对于上面的例子,则正确的输出是为:

    +---------+-----------+--------------+-----------+
    |   id    | movie     |  description |  rating   |
    +---------+-----------+--------------+-----------+
    |   5     | House card|   Interesting|   9.1     |
    |   1     | War       |   great 3D   |   8.9     |
    +---------+-----------+--------------+-----------+
    

    sql如下:

    select  id,movie,description,rating  from cinema
    where description!="boring" 
    and id%2=1 
    order by rating desc
    

    备注分析:

    where的条件判断!=(或者<>,sql2000中是不支持 != 的) 和 n%2=1(或者mod(id,2)=1),以及order by
    

    11、性别更变

    给定一个 salary 表,如下所示,有 m = 男性 和 f = 女性 的值。交换所有的 f 和 m 值(例如,将所有 f 值更改为 m,反之亦然)。要求只使用一个更新(Update)语句,并且没有中间的临时表。

    注意,您必只能写一个 Update 语句,请不要编写任何 Select 语句。

    例如:

    | id | name | sex | salary |
    |----|------|-----|--------|
    | 1  | A    | m   | 2500   |
    | 2  | B    | f   | 1500   |
    | 3  | C    | m   | 5500   |
    | 4  | D    | f   | 500    |
    

    运行你所编写的更新语句之后,将会得到以下表:

    | id | name | sex | salary |
    |----|------|-----|--------|
    | 1  | A    | f   | 2500   |
    | 2  | B    | m   | 1500   |
    | 3  | C    | f   | 5500   |
    | 4  | D    | m   | 500    |
    

    sql如下:

    update salary 
    set sex= 
    case sex
    when 'm' then 'f' else 'm' end;
    

    备注分析:

    用到case x  when expr1  then expr2   else expr1  end
    

    12、重新格式化部门表

    部门表 Department:

    +---------------+---------+
    | Column Name   | Type    |
    +---------------+---------+
    | id            | int     |
    | revenue       | int     |
    | month         | varchar |
    +---------------+---------+
    (id, month) 是表的联合主键。
    这个表格有关于每个部门每月收入的信息。
    月份(month)可以取下列值 ["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"]。
    

    编写一个 SQL 查询来重新格式化表,使得新的表中有一个部门 id 列和一些对应 每个月 的收入(revenue)列。

    查询结果格式如下面的示例所示:

    Department 表:
    +------+---------+-------+
    | id   | revenue | month |
    +------+---------+-------+
    | 1    | 8000    | Jan   |
    | 2    | 9000    | Jan   |
    | 3    | 10000   | Feb   |
    | 1    | 7000    | Feb   |
    | 1    | 6000    | Mar   |
    +------+---------+-------+
    
    查询得到的结果表:
    +------+-------------+-------------+-------------+-----+-------------+
    | id   | Jan_Revenue | Feb_Revenue | Mar_Revenue | ... | Dec_Revenue |
    +------+-------------+-------------+-------------+-----+-------------+
    | 1    | 8000        | 7000        | 6000        | ... | null        |
    | 2    | 9000        | null        | null        | ... | null        |
    | 3    | null        | 10000       | null        | ... | null        |
    +------+-------------+-------------+-------------+-----+-------------+
    
    注意,结果表有 13 列 (1个部门 id 列 + 12个月份的收入列)。
    

    sql如下:

    select id,
    sum(case month when "Jan" then revenue end) as Jan_Revenue,
    sum(case month when "Feb" then revenue end) as Feb_Revenue,
    sum(case month when "Mar" then revenue end) as Mar_Revenue,
    sum(case month when "Apr" then revenue end) as Apr_Revenue,
    sum(case month when "May" then revenue end) as May_Revenue,
    sum(case month when "Jun" then revenue end) as Jun_Revenue,
    sum(case month when "Jul" then revenue end) as Jul_Revenue,
    sum(case month when "Aug" then revenue end) as Aug_Revenue,
    sum(case month when "Sep" then revenue end) as Sep_Revenue,
    sum(case month when "Oct" then revenue end) as Oct_Revenue,
    sum(case month when "Nov" then revenue end) as Nov_Revenue,
    sum(case month when "Dec" then revenue end) as Dec_Revenue
    from Department
    group by id
    

    备注分析:

    要统计每个部门的薪资,会用到对部门id进行 group by
    之后会对每个月的薪资做展示,在select时对每个月的薪资进行sum,
    并且在sum()中进行case 判断,返回当前月的薪资,无则返回空
    

    13、第N高的薪水

    编写一个 SQL 查询,获取 Employee 表中第 n 高的薪水(Salary)。

    +----+--------+
    | Id | Salary |
    +----+--------+
    | 1  | 100    |
    | 2  | 200    |
    | 3  | 300    |
    +----+--------+
    

    例如上述 Employee 表,n = 2 时,应返回第二高的薪水 200。如果不存在第 n 高的薪水,那么查询应返回 null。

    +------------------------+
    | getNthHighestSalary(2) |
    +------------------------+
    | 200                    |
    +------------------------+
    

    sql如下:

    CREATE FUNCTION getNthHighestSalary(N INT) RETURNS INT
    BEGIN
        declare m int;
        set m = N -1;
      RETURN (
          # Write your MySQL query statement below.
          ifnull((select Salary from Employee group by Salary order by Salary desc limit m,1),null)
      );
    END
    

    备注分析:

    本题涉及到mysql的自定义函数语法问题
    1、没有第二高的就为空,用ifnull(expr,null)
    2、用order by 排序,limit 输出N-1,1即跳过N-1个输出一个。
    3、由于limit 后不能直接跟 N-1,所以一开始吧N-1赋值给m
    4、由于考虑到只有两条数据,并且并列第一的情况,所以用group by对salary进行去重
    

    14、分数排名

    编写一个 SQL 查询来实现分数排名。

    如果两个分数相同,则两个分数排名(Rank)相同。请注意,平分后的下一个名次应该是下一个连续的整数值。换句话说,名次之间不应该有“间隔”。

    +----+-------+
    | Id | Score |
    +----+-------+
    | 1  | 3.50  |
    | 2  | 3.65  |
    | 3  | 4.00  |
    | 4  | 3.85  |
    | 5  | 4.00  |
    | 6  | 3.65  |
    +----+-------+
    

    例如,根据上述给定的 Scores 表,你的查询应该返回(按分数从高到低排列):

    +-------+------+
    | Score | Rank |
    +-------+------+
    | 4.00  | 1    |
    | 4.00  | 1    |
    | 3.85  | 2    |
    | 3.65  | 3    |
    | 3.65  | 3    |
    | 3.50  | 4    |
    +-------+------+
    

    重要提示:对于 MySQL 解决方案,如果要转义用作列名的保留字,可以在关键字之前和之后使用撇号。例如 Rank

    sql如下:

    select *,dense_rank() OVER(order by Score desc) as Rank 
    from Scores 
    

    备注分析:

    值得注意的三个窗口函数,现在给定五个成绩:99,99,85,80,75。
    DENSE_RANK()  如果使用 DENSE_RANK() 进行排名会得到:1,1,2,3,4。
    RANK()  如果使用 RANK() 进行排名会得到:1,1,3,4,5。
    ROW_NUMBER()  如果使用 ROW_NUMBER() 进行排名会得到:1,2,3,4,5。
    
    • 第二种解法
    select a.Score as Score,
    (select count(distinct b.Score) 
        from Scores b 
        where b.Score >= a.Score) as `Rank`
    from Scores a
    order by a.Score DESC
    

    备注分析:

    where b.Score >= a.Score 时,才执行一次count(distinct b.Score) 
    也就是说当b表的分数大于a表的分数,才计算一次count
    也就是说,当b表的分数大于a表的分数时,计算b表分数时的个数,即为此分数的排名
    
    即大于等于自己成绩的且去重的成绩个数就是自己排名
    
    作者:落花桂
             
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
  • 相关阅读:
    在windwos创建的脚本文件在linux环境中无法执行的问题
    shell的文件锁操作
    systemd target
    算法-排序数组
    算法-存在重复元素
    算法-移除元素
    算法-两数之和
    touch事件详解
    小程序 打包太大
    taro/vue 左滑删除购物车
  • 原文地址:https://www.cnblogs.com/nthforsth/p/14939582.html
Copyright © 2020-2023  润新知