美文网首页
LeetCode数据库题目总结

LeetCode数据库题目总结

作者: los_pollos | 来源:发表于2018-09-30 20:31 被阅读0次

    596.超过5名学生的课

    pic1

    方法1.使用GROUP BY和子查询

    想法

    我们可以先获得每个课程的学生数,再选择超过五个学生的课程。

    算法

    为了获得每个课程的学生数,可以使用函数GROUP BY和COUNT:

    SELECT class, COUNT(DISTINCT student)
      FROM courses
    GROUP BY class
    ;
    
    pic2

    接着利用子查询挑选出符合条件的课程:

    SELECT class
      FROM 
          (SELECT class, COUNT(DISTINCT student) AS num
             FROM courses
           GROUP BY class) AS temp_table
     WHERE num >= 5
    ;
    

    方法2.使用GROUP BY和HAVING函数

    算法

    子查询是对GROUP BY进行条件限制的一个方法,另一种方法是用HAVING。

    MYSQL

    SELECT class
      FROM courses
    GROUP BY class
    HAVING COUNT(DISTINCT student) >= 5
    

    183.从不订购的客户

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


    pic3

    解答

    方法.子查询和NOT IN结合

    算法

    如果我们已知了一列有订单的客户,那么没有订单的客户就很清楚了。
    利用下面的语句可以选出有订单的客户:

    SELECT customerid FROM Orders;
    

    接着,用NOT IN语句来选出不在上面列表中的客户。

    MYSQL

    SELECT Customers.Name AS 'Customers'
      FROM Customers
     WHERE Customers.id NOT IN
    (
     SELECT CustomerId FROM orders
    );
    

    182.查找重复的电子邮箱

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


    pic4

    方法1.GROUP BY和临时表

    算法

    重复的电子邮箱出现大于等于两次,先计算每个邮箱出现的次数:

    SELECT Email, count(Email) AS num
      FROM Person
    GROUP BY Email;
    

    把上面的表作为临时表,最后的语句:

    SELECT Email FROM 
    (
      SELECT Email, count(Email) AS num
        FROM Person
      GROUP BY Email
    )AS statistic
    WHERE num > 1
    ;
    

    方法2.GROUP BY和HAVING

    对GROUP BY加条件的常用方法是HAVING,更简单且有效率

    MYSQL

    SELECT Email
      FROM Person
    GROUP BY Email
    HAVING count(Email) > 1;
    

    627.交换工资

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


    pic5

    方法:UPDATE和CASE...WHEN

    MYSQL

    UPDATE salary
    SET 
        sex = CASE sex
            WHEN 'm' THEN 'f'
            ELSE 'm'
        END;
    

    196.删除重复的电子邮箱

    pic6

    方法:DELETE和WHERE

    算法

    用Email来join这个表和它自身:

    SELECT p1.*
      FROM Person p1, Person p2
     WHERE p1.Email = p2.Email;
    

    然后我们查找出拥有相同Email的较大ID,用WHERE来实现:

    SELECT p1.*
      FROM Person p1, Person p2
     WHERE p1.Email = p2.Email
       AND p1.Id > p2.Id;
    

    现在已经得到了所有需要删除的记录,接下来只需要用DELETE函数。

    MYSQL

    DELETE p1
      FROM Person p1, Person p2
     WHERE p1.Email = p2.Email
       AND p1.Id > p2.Id
    

    197.上升的温度

    给定一个 Weather 表,编写一个 SQL 查询,来查找与之前(昨天的)日期相比温度更高的所有日期的 Id。


    pic7

    方法1:使用JOIN和DATEDIFF()

    算法

    MYSQL的DATEDIFF函数可以用来比较两个日期值,我们可以join这个表自身并使用DATEDIFF函数。

    MYSQL

    SELECT weather.id AS 'Id'
      FROM weather
           JOIN 
           weather w ON DATEDIFF(weather.date, w.date) = 1
            AND weather.Temperature > w.Temperature;
    

    方法2:使用JOIN和TO_DAYS

    算法

    对日期做差,也可以先对日期用TO_DAYS函数,再求差

    MYSQL

    SELECT a.Id
      FROM 
      Weather a 
     INNER JOIN Weather b
     ON TO_DAYS(a.RecordDate) = TO_DAYS(b.RecordDate) + 1
      AND a.Temperature > b.Temperature
    

    184.部门工资最高的员工

    pic8

    方法:使用JOIN和IN

    算法

    Employee表里包含工资和部门id,我们可以得到各部门里最高的工资。

    SELECT DepartmentId, MAX(Salary)
      FROM Employee
    GROUP BY DepartmentId
    

    可能存在不止一个员工有同样的最高的工资,所以不应该加上员工姓名。

    接着,把employee表和department表join起来,找出来(DepartmentId, Salary)与上面临时表相等的行

    SELECT Department.Name AS 'Department', Employee.Name AS 'Employee', Salary
      FROM Employee
      JOIN Department ON Employee.DepartmentId = Department.Id
     WHERE (Employee.DepartmentId, Salary) IN
           (SELECT DepartmentId, MAX(Salary)
              FROM Employee
            GROUP BY DepartmentId);
    

    626.换座位

    小美是一所中学的信息科技老师,她有一张 seat 座位表,平时用来储存学生名字和与他们相对应的座位 id。其中纵列的 id 是连续递增的,小美想改变相邻俩学生的座位。你能不能帮她写一个 SQL query 来输出小美想要的结果呢?


    pic9.png

    注意:如果学生人数是奇数,则不需要改变最后一个同学的座位。

    方法:CASE

    算法

    对于位置id是奇数的学生,除了最后一个奇数位置之外的学生新id是(id+1)。而位置id是偶数的学生,新id是(id-1)。我们可以用下面这个语句来获取全部的位置数:

    SELECT COUNT(*) AS counts
      FROM seat
    

    然后,用CASE语句和MOD()函数来改变每个学生的位置。

    MYSQL

    SELECT (CASE 
               WHEN MOD(id, 2) != 0 AND counts != id THEN id + 1
               WHEN MOD(id, 2) != 0 AND counts = id THEN id
               ELSE id - 1
            END) AS id,
            student
      FROM
            seat,
            (SELECT COUNT(*) AS counts
               FROM seat) AS seat_counts
    ORDER BY id ASC;
    

    180.连续出现的数字

    pic10.png

    方法:DISTINCT和WHERE

    算法

    连续出现意味着相同Num的Id是相邻的。需要查找出至少连续出现三次的数字,可以用三个Logs表,测试三个连续的id出现的数字是否相同。

    SELECT *
      FROM Logs l1,
           Logs l2,
           Logs l3
    WHERE l1.id = l2.id -1
          AND l2.id = l3.id -1
          AND l1.Num = l2.Num
          AND l2.Num = l3.Num
    ;
    

    上面的语句取出的表形式应该是:


    pic11.png

    然后选取上表中任意的Num列即可,注意需要加上DISTINCT关键字。

    MYSQL

     SELECT DISTINCT
        l1.Num AS ConsecutiveNums
    FROM
        Logs l1,
        Logs l2,
        Logs l3
    WHERE
        l1.Id = l2.Id - 1
        AND l2.Id = l3.Id - 1
        AND l1.Num = l2.Num
        AND l2.Num = l3.Num
    ;
    

    177.第N高的薪水

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

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

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

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

    方法:LIMIT,OFFSET

    MYSQL

    CREATE FUNCTION getNthHighestSalary(N INT) RETURNS INT
    BEGIN
      SET N = N-1;
      RETURN (
          SELECT DISTINCT Salary
            FROM Employee
          ORDER BY Salary DESC
          LIMIT 1 OFFSET N     
      );
    END
    

    185.部门工资前三高的员工

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

    +----+-------+--------+--------------+
    | Id | Name | Salary | DepartmentId |
    +----+-------+--------+--------------+
    | 1 | Joe | 70000 | 1 |
    | 2 | Henry | 80000 | 2 |
    | 3 | Sam | 60000 | 2 |
    | 4 | Max | 90000 | 1 |
    | 5 | Janet | 69000 | 1 |
    | 6 | Randy | 85000 | 1 |
    +----+-------+--------+--------------+

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

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

    编写一个 SQL 查询,找出每个部门工资前三高的员工。例如,根据上述给定的表格,查询结果应返回:

    +------------+----------+--------+
    | Department | Employee | Salary |
    +------------+----------+--------+
    | IT | Max | 90000 |
    | IT | Randy | 85000 |
    | IT | Joe | 70000 |
    | Sales | Henry | 80000 |
    | Sales | Sam | 60000 |
    +------------+----------+--------+

    方法1:JOIN和子查询

    算法

    top3的工资意味着没有3个salary比它更高了:

    SELECT e1.Name AS 'employee', e1.Salary
      FROM Employee e1
     WHERE 3 >
    (
         SELECT count(distinct e2.salary)
           FROM Employee e2
          WHERE e2.Salary > e1.Salary
    )
    ;
    

    上述语句返回的表如下:


    pic12.png

    然后需要join另一张表:

    SELECT 
         d.Name AS 'Department', e1.Name AS 'Employee', e1.Salary
    FROM 
        Employee e1
           JOIN
        Department d ON e1.DepartmentId = d.Id
    WHERE
        3 > (SELECT 
               COUNT(DISTINCT e2.Salary)
              FROM
             Employee e2
              WHERE
               e2.Salary > e1.Salary
                    AND e1.DepartmentId = e2.DepartmentId
            )
    ;
    

    方法二:DENSE_RANK

    MS SQL server

    SELECT department, employee, salary 
    FROM (
        
      SELECT b.name AS department, a.name AS employee, salary,
        dense_rank() over(partition by departmentid order by salary desc) AS rn
    FROM employee a 
    LEFT JOIN department b
    ON a.departmentid=b.id 
        WHERE b.name is not null) c
    WHERE rn <= 3 
    ORDER BY department,salary DESC
    

    601.体育馆的人流量

    X 市建了一个新的体育馆,每日人流量信息被记录在这三列信息中:序号 (id)、日期 (date)、 人流量 (people)。

    请编写一个查询语句,找出高峰期时段,要求连续三天及以上,并且每天人流量均不少于100。

    例如,表 stadium:

    +------+------------+-----------+
    | id | date | people |
    +------+------------+-----------+
    | 1 | 2017-01-01 | 10 |
    | 2 | 2017-01-02 | 109 |
    | 3 | 2017-01-03 | 150 |
    | 4 | 2017-01-04 | 99 |
    | 5 | 2017-01-05 | 145 |
    | 6 | 2017-01-06 | 1455 |
    | 7 | 2017-01-07 | 199 |
    | 8 | 2017-01-08 | 188 |
    +------+------------+-----------+
    对于上面的示例数据,输出为:

    +------+------------+-----------+
    | id | date | people |
    +------+------------+-----------+
    | 5 | 2017-01-05 | 145 |
    | 6 | 2017-01-06 | 1455 |
    | 7 | 2017-01-07 | 199 |
    | 8 | 2017-01-08 | 188 |
    +------+------------+-----------+
    Note:
    每天只有一行记录,日期随着 id 的增加而增加。

    方法:JOIN和WHERE

    想法

    先选出所有人数大于100的日期,再用这个临时的表JOIN它自身,最后用WHERE来找连续的日期

    算法

    第一步:选出所有人数大于100的日期,再用这个临时表JOIN它自身

    SELECT DISTINCT t1.*
      FROM stadium t1, stadium t2, stadium t3
     WHERE t1.people >= 100 AND t2.people >= 100 AND t3.people >= 100
    ;
    

    总共有六天的人数大于100,因此三个表JOIN的结果是6 * 6 * 6 = 216行。
    以t1为例,它可以是连续三天的第一天、第二天或者第三天,即:

    t1是第一天:(t1.id - t2.id = 1 and t1.id - t3.id = 2 and t2.id - t3.id = 1)
    -- t1, t2, t3
    t1是第二天:(t2.id - t1.id = 1 and t2.id - t.id = 2 and t1.id - t3.id = 1)
    -- t2, t1, t3
    t1是第三天:(t3.id - t2.id = 1 and t2.id - t1.id = 1 and t3.id - t1.id = 2)
    -- t3, t2, t1

    将上面的条件加入SQL:

    
    select t1.*
    from stadium t1, stadium t2, stadium t3
    where t1.people >= 100 and t2.people >= 100 and t3.people >= 100
    and
    (
        (t1.id - t2.id = 1 and t1.id - t3.id = 2 and t2.id - t3.id =1) 
        or
        (t2.id - t1.id = 1 and t2.id - t3.id = 2 and t1.id - t3.id =1)
        or
        (t3.id - t2.id = 1 and t2.id - t1.id =1 and t3.id - t1.id = 2) 
    )
    ;
    
    pic13.png

    结果里包含了重复列,因此还需要用DISTINCT来去重。

    MYSQL

    select distinct t1.*
    from stadium t1, stadium t2, stadium t3
    where t1.people >= 100 and t2.people >= 100 and t3.people >= 100
    and
    (
        (t1.id - t2.id = 1 and t1.id - t3.id = 2 and t2.id - t3.id =1) 
        or
        (t2.id - t1.id = 1 and t2.id - t3.id = 2 and t1.id - t3.id =1) 
        or
        (t3.id - t2.id = 1 and t2.id - t1.id =1 and t3.id - t1.id = 2)
    )
    order by t1.id
    ;
    

    相关文章

      网友评论

          本文标题:LeetCode数据库题目总结

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