Mysql 场景题一 完整版

题目一

小美是一所中学的信息科技老师,她有一张 seat 座位表,平时用来储存学生名字和与他们相对应的座位 id。

其中纵列的 id 是连续递增的

小美想改变相邻俩学生的座位。

你能不能帮她写一个 SQL query 来输出小美想要的结果呢?

示例:

±--------±--------+

| id | student |

±--------±--------+

| 1 | Abbot |

| 2 | Doris |

| 3 | Emerson |

| 4 | Green |

| 5 | Jeames |

±--------±--------+

假如数据输入的是上表,则输出结果如下:

±--------±--------+

| id | student |

±--------±--------+

| 1 | Doris |

| 2 | Abbot |

| 3 | Green |

| 4 | Emerson |

| 5 | Jeames |

±--------±--------+

注意:

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

SELECT if(id%2=1,
        if(id=@a,
        id,
        id+1),
        id-1) id,
        student
FROM seat s,
  (SELECT @a:=count(id)
  FROM seat) ret
ORDER BY  id;

题目二

在 Facebook 或者 Twitter 这样的社交应用中,人们经常会发好友申请也会收到其他人的好友申请。

表 request_accepted 存储了所有好友申请通过的数据记录,其中, requester_id 和 accepter_id 都是用户的编号。

| requester_id | accepter_id | accept_date|

|--------------|-------------|------------|

| 1 | 2 | 2016_06-03 |

| 1 | 3 | 2016-06-08 |

| 2 | 3 | 2016-06-08 |

| 3 | 4 | 2016-06-09 |

写一个查询语句,求出谁拥有最多的好友和他拥有的好友数目。对于上面的样例数据,结果为:

| id | num |

|----|-----|

| 3 | 3 |

注意:

保证拥有最多好友数目的只有 1 个人。

好友申请只会被接受一次,所以不会有 requester_id 和 accepter_id 值都相同的重复记录。

解释:

编号为 ‘3’ 的人是编号为 ‘1’,‘2’ 和 ‘4’ 的好友,所以他总共有 3 个好友,比其他人都多。

进阶:

在真实世界里,可能会有多个人拥有好友数相同且最多,你能找到所有这些人吗?

SELECT id AS id,
         ucnt AS num
FROM 
  (SELECT id,
         count(1) AS ucnt
  FROM 
    (SELECT requester_id AS id
    FROM request_accepted
    UNION
    allSELECT accepter_id AS id
    FROM request_accepted )
    GROUP BY  id
    ORDER BY  ucnt DESC )
  WHERE rownum = 1

题目三

表 point_2d 保存了所有点(多于 2 个点)的坐标 (x,y) ,这些点在平面上两两不重合。

写一个查询语句找到两点之间的最近距离,保留 2 位小数。

| x | y |

|----|----|

| -1 | -1 |

| 0 | 0 |

| -1 | -2 |

最近距离在点 (-1,-1) 和(-1,2) 之间,距离为 1.00 。所以输出应该为:

| shortest |

|----------|

| 1.00 |

注意:任意点之间的最远距离小于 10000 。

SELECT ROUND(MIN(shortest),
        2) shortest FROM
  (SELECT POWER(POWER((p1.x-p2.x),
        2)+POWER((p1.y-p2.y),
        2),
        0.5) shortest
  FROM point_2d p1,point_2d p2
  WHERE p1.x !=p2.x
          OR p1.y != p2.y )a

题目四

编写一个 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 |

±------±-----+

SELECT a.Score,
         sum(case
    WHEN b.Score>=a.Score THEN
    1 end) AS Rank
FROM Scores a, 
  (SELECT DISTINCT Score
  FROM Scores ) b
GROUP BY  a.id
ORDER BY  a.Score desc; 

题目五

给定一个表 tree,id 是树节点的编号, p_id 是它父节点的 id 。

±—±-----+

| id | p_id |

±—±-----+

| 1 | null |

| 2 | 1 |

| 3 | 1 |

| 4 | 2 |

| 5 | 2 |

±—±-----+

树中每个节点属于以下三种类型之一:

叶子:如果这个节点没有任何孩子节点。

根:如果这个节点是整棵树的根,即没有父节点。

内部节点:如果这个节点既不是叶子节点也不是根节点。

写一个查询语句,输出所有节点的编号和节点的类型,并将结果按照节点编号排序。上面样例的结果为:

±—±-----+

| id | Type |

±—±-----+

| 1 | Root |

| 2 | Inner|

| 3 | Leaf |

| 4 | Leaf |

| 5 | Leaf |

±—±-----+

解释

节点 ‘1’ 是根节点,因为它的父节点是 NULL ,同时它有孩子节点 ‘2’ 和 ‘3’ 。

节点 ‘2’ 是内部节点,因为它有父节点 ‘1’ ,也有孩子节点 ‘4’ 和 ‘5’ 。

节点 ‘3’, ‘4’ 和 ‘5’ 都是叶子节点,因为它们都有父节点同时没有孩子节点。

样例中树的形态如下:

1

/ \

2 3

/ \

4 5

SELECT DISTINCT t1.id,
         (CASE
    WHEN t1.p_id IS NULL THEN
    'Root' ELSE
    CASE
    WHEN t2.id IS NULL THEN
    'Leaf'
    ELSE 'Inner'
    END END) AS Type
FROM tree t1
LEFT JOIN tree t2
    ON t1.id=t2.p_id

题目六

Employee 表包含所有员工和他们的经理。每个员工都有一个 Id,并且还有一列是经理的 Id。

±-----±---------±----------±---------+

|Id |Name |Department |ManagerId |

±-----±---------±----------±---------+

|101 |John |A |null |

|102 |Dan |A |101 |

|103 |James |A |101 |

|104 |Amy |A |101 |

|105 |Anne |A |101 |

|106 |Ron |B |101 |

±-----±---------±----------±---------+

给定 Employee 表,请编写一个SQL查询来查找至少有5名直接下属的经理。对于上表,您的SQL查询应该返回:

±------+

| Name |

±------+

| John |

±------+

SELECT b.Name
FROM employee a
INNER JOIN employee b
    ON a.managerid= b.id
GROUP BY  a.managerid
HAVING count(*)>=5; 

题目七

一所大学有 2 个数据表,分别是 student 和 department ,这两个表保存着每个专业的学生数据和院系数据。

写一个查询语句,查询 department 表中每个专业的学生人数 (即使没有学生的专业也需列出)。

将你的查询结果按照学生人数降序排列。 如果有两个或两个以上专业有相同的学生数目,将这些部门按照部门名字的字典序从小到大排列。

student 表格如下:

| Column Name | Type |

|--------------|-----------|

| student_id | Integer |

| student_name | String |

| gender | Character |

| dept_id | Integer |

其中, student_id 是学生的学号, student_name 是学生的姓名, gender 是学生的性别, dept_id 是学生所属专业的专业编号。

department 表格如下:

| Column Name | Type |

|-------------|---------|

| dept_id | Integer |

| dept_name | String |

dept_id 是专业编号, dept_name 是专业名字。

这里是一个示例输入:

student 表格:

| student_id | student_name | gender | dept_id |

|------------|--------------|--------|---------|

| 1 | Jack | M | 1 |

| 2 | Jane | F | 1 |

| 3 | Mark | M | 2 |

department 表格:

| dept_id | dept_name |

|---------|-------------|

| 1 | Engineering |

| 2 | Science |

| 3 | Law |

示例输出为:

| dept_name | student_number |

|-------------|----------------|

| Engineering | 2 |

| Science | 1 |

| Law | 0 |

SELECT dept_name,
        (case
    WHEN student_num is NULL THEN
    0
    ELSE student_num end) student_number
FROM 
  (SELECT dept_id,
        count(*) student_num
  FROM student
  GROUP BY  dept_id) t1
RIGHT JOIN department t2
    ON t1.dept_id=t2.dept_id
ORDER BY  student_number desc,dept_name asc

题目八

写一个查询语句,将 2016 年 (TIV_2016) 所有成功投资的金额加起来,保留 2 位小数。

对于一个投保人,他在 2016 年成功投资的条件是:

他在 2015 年的投保额 (TIV_2015) 至少跟一个其他投保人在 2015 年的投保额相同。

他所在的城市必须与其他投保人都不同(也就是说维度和经度不能跟其他任何一个投保人完全相同)。

输入格式:

表 insurance 格式如下:

| Column Name | Type |

|-------------|---------------|

| PID | INTEGER(11) |

| TIV_2015 | NUMERIC(15,2) |

| TIV_2016 | NUMERIC(15,2) |

| LAT | NUMERIC(5,2) |

| LON | NUMERIC(5,2) |

PID 字段是投保人的投保编号, TIV_2015 是该投保人在2015年的总投保金额, TIV_2016 是该投保人在2016年的投保金额, LAT 是投保人所在城市的维度, LON 是投保人所在城市的经度。

样例输入

| PID | TIV_2015 | TIV_2016 | LAT | LON |

|-----|----------|----------|-----|-----|

| 1 | 10 | 5 | 10 | 10 |

| 2 | 20 | 20 | 20 | 20 |

| 3 | 10 | 30 | 20 | 20 |

| 4 | 10 | 40 | 40 | 40 |

样例输出

| TIV_2016 |

|----------|

| 45.00 |

解释

就如最后一个投保人,第一个投保人同时满足两个条件:

1. 他在 2015 年的投保金额 TIV_2015 为 ‘10’ ,与第三个和第四个投保人在 2015 年的投保金额相同。

2. 他所在城市的经纬度是独一无二的。

第二个投保人两个条件都不满足。他在 2015 年的投资 TIV_2015 与其他任何投保人都不相同。

且他所在城市的经纬度与第三个投保人相同。基于同样的原因,第三个投保人投资失败。

所以返回的结果是第一个投保人和最后一个投保人的 TIV_2016 之和,结果是 45 。

SELECT sum(case
    WHEN t3.TIV_2015 is NOT NULL THEN
    t2.TIV_2016
    ELSE 0 end) TIV_2016 from
  (SELECT TIV_2015
  FROM insurance
  GROUP BY  TIV_2015
  HAVING count(TIV_2015)>1)t3
RIGHT JOIN 
  (SELECT *
  FROM insurance
  GROUP BY  LAT, LON
  HAVING count(LAT) = 1
          AND count(LON) = 1) t2
    ON t2.TIV_2015=t3.TIV_2015

题目九

Customer 表:

±------------±--------+

| Column Name | Type |

±------------±--------+

| customer_id | int |

| product_key | int |

±------------±--------+

product_key 是 Product 表的外键。

Product 表:

±------------±--------+

| Column Name | Type |

±------------±--------+

| product_key | int |

±------------±--------+

product_key 是这张表的主键。

写一条 SQL 查询语句,从 Customer 表中查询购买了 Product 表中所有产品的客户的 id。

示例:

Customer 表:

±------------±------------+

| customer_id | product_key |

±------------±------------+

| 1 | 5 |

| 2 | 6 |

| 3 | 5 |

| 3 | 6 |

| 1 | 6 |

±------------±------------+

Product 表:

±------------+

| product_key |

±------------+

| 5 |

| 6 |

±------------+

Result 表:

±------------+

| customer_id |

±------------+

| 1 |

| 3 |

±------------+

购买了所有产品(5 和 6)的客户的 id 是 1 和 3 。

SELECT customer_id
FROM 
  (SELECT DISTINCT c.customer_id,
         c.product_key AS cpk,
         p.product_key AS ppk
  FROM customer c
  LEFT JOIN product p
      ON c.product_key=p.product_key) tmp
GROUP BY  customer_id
HAVING COUNT(cpk) = 
  (SELECT COUNT(product_key)
  FROM product)
        AND COUNT(ppk) = 
  (SELECT COUNT(product_key)
  FROM product) 

题目十

编写一个 SQL 查询,查找所有至少连续出现三次的数字。

±—±----+

| Id | Num |

±—±----+

| 1 | 1 |

| 2 | 1 |

| 3 | 1 |

| 4 | 2 |

| 5 | 1 |

| 6 | 2 |

| 7 | 2 |

±—±----+

例如,给定上面的 Logs 表, 1 是唯一连续出现至少三次的数字。

±----------------+

| ConsecutiveNums |

±----------------+

| 1 |

±----------------+

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 ;

题目十一

表: Candidate

±----±--------+

| id | Name |

±----±--------+

| 1 | A |

| 2 | B |

| 3 | C |

| 4 | D |

| 5 | E |

±----±--------+

表: Vote

±----±-------------+

| id | CandidateId |

±----±-------------+

| 1 | 2 |

| 2 | 4 |

| 3 | 3 |

| 4 | 2 |

| 5 | 5 |

±----±-------------+

id 是自动递增的主键,

CandidateId 是 Candidate 表中的 id.

请编写 sql 语句来找到当选者的名字,上面的例子将返回当选者 B.

±-----+

| Name |

±-----+

| B |

±-----+

注意:

你可以假设没有平局,换言之,最多只有一位当选者。

elect t3.name Name
FROM Candidate t3, 
  (SELECT t1.CandidateId CandidateId
  FROM Vote t1
  GROUP BY  t1.CandidateId
  ORDER BY  count(*) DESC limit 1)t2
WHERE t3.id=t2.CandidateId 

题目十二

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 |

±—±------±-------±-------------+

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

±—±---------+

| Id | Name |

±—±---------+

| 1 | IT |

| 2 | Sales |

±—±---------+

编写一个 SQL 查询,找出每个部门工资最高的员工。例如,根据上述给定的表格,Max 在 IT 部门有最高工资,Henry 在 Sales 部门有最高工资。

±-----------±---------±-------+

| Department | Employee | Salary |

±-----------±---------±-------+

| IT | Max | 90000 |

| Sales | Henry | 80000 |

±-----------±---------±-------+

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 ) ; 

题目十三

从 survey_log 表中获得回答率最高的问题,survey_log 表包含这些列:uid, action, question_id, answer_id, q_num, timestamp。

uid 表示用户 id;action 有以下几种值:“show”,“answer”,“skip”;当 action 值为 “answer” 时 answer_id 非空,而 action 值为 “show” 或者 “skip” 时 answer_id 为空;q_num 表示当前会话中问题的编号。

请编写SQL查询来找到具有最高回答率的问题。

示例:

输入:

±-----±----------±-------------±-----------±----------±-----------+

| uid | action | question_id | answer_id | q_num | timestamp |

±-----±----------±-------------±-----------±----------±-----------+

| 5 | show | 285 | null | 1 | 123 |

| 5 | answer | 285 | 124124 | 1 | 124 |

| 5 | show | 369 | null | 2 | 125 |

| 5 | skip | 369 | null | 2 | 126 |

±-----±----------±-------------±-----------±----------±-----------+

输出:

±------------+

| survey_log |

±------------+

| 285 |

±------------+

解释:

问题285的回答率为 1/1,而问题369回答率为 0/1,因此输出285。

注意: 回答率最高的含义是:同一问题编号中回答数占显示数的比例。

SELECT question_id AS survey_log
FROM survey_log
GROUP BY  question_id
ORDER BY  ( ifnull( count( answer_id ), 0 ) / count( * ) ) DESC LIMIT 1

题目十四

在 facebook 中,表 follow 会有 2 个字段: followee, follower ,分别表示被关注者和关注者。

请写一个 sql 查询语句,对每一个关注者,查询他的关注者数目。

比方说:

±------------±-----------+

| followee | follower |

±------------±-----------+

| A | B |

| B | C |

| B | D |

| D | E |

±------------±-----------+

应该输出:

±------------±-----------+

| follower | num |

±------------±-----------+

| B | 2 |

| D | 1 |

±------------±-----------+

解释:

B 和 D 都在在 follower 字段中出现,作为被关注者,B 被 C 和 D 关注,D 被 E 关注。A 不在 follower 字段内,所以A不在输出列表中。

注意:

被关注者永远不会被他 / 她自己关注。

将结果按照字典序返回。

SELECT f1.follower AS follower,
         count(distinct f2.follower) AS num
FROM follow f1, follow f2
WHERE f1.follower = f2.followee
GROUP BY  f1.follower
ORDER BY  f1.follower

你可能感兴趣的:(mysql)