21. 寻找用户推荐人

需求:写一个查询语句,返回一个编号列表,列表中编号的推荐人的编号都 不是 2

展示效果:

name
Will
Jane
Bill
Zack
  1. CREATE TABLE IF NOT EXISTS 21_customer (id INT,name VARCHAR(25),referee_id INT);
  2. Truncate table 21_customer;
  3. insert into 21_customer (id, name, referee_id) values (1, 'Will', null);
  4. insert into 21_customer (id, name, referee_id) values (2, 'Jane', null);
  5. insert into 21_customer (id, name, referee_id) values (3, 'Alex', 2);
  6. insert into 21_customer (id, name, referee_id) values (4, 'Bill', null);
  7. insert into 21_customer (id, name, referee_id) values (5, 'Zack', 1);
  8. insert into 21_customer (id, name, referee_id) values (6, 'Mark', 2);

最终SQL:

  1. SELECT
  2. name
  3. FROM
  4. 21_customer
  5. WHERE
  6. referee_id <> 2 OR referee_id IS NULL;

22. 2016年的投资

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

展示效果:

TIV_2016
45.00
  1. CREATE TABLE IF NOT EXISTS 22_insurance (PID INTEGER(11), TIV_2015 NUMERIC(15,2), TIV_2016 NUMERIC(15,2), LAT NUMERIC(5,2), LON NUMERIC(5,2) );
  2. Truncate table 22_insurance;
  3. insert into 22_insurance (PID, TIV_2015, TIV_2016, LAT, LON) values (1, 10, 5, 10, 10);
  4. insert into 22_insurance (PID, TIV_2015, TIV_2016, LAT, LON) values (2, 20, 20, 20, 20);
  5. insert into 22_insurance (PID, TIV_2015, TIV_2016, LAT, LON) values (3, 10, 30, 20, 20);
  6. insert into 22_insurance (PID, TIV_2015, TIV_2016, LAT, LON) values (4, 10, 40, 40, 40);

提示:

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

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

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

  1. 他在 2015 年的投保金额 TIV_2015 为 10 ,与第三个和第四个投保人在 2015 年的投保金额相同。
  2. 他所在城市的经纬度是独一无二的。

第二个投保人两个条件都不满足。他在 2015 年的投资 TIV_2015 与其他任何投保人都不相同。
且他所在城市的经纬度与第三个投保人相同。基于同样的原因,第三个投保人投资失败。

最终SQL:

  1. SELECT
  2. SUM(i.TIV_2016) AS TIV_2016
  3. FROM
  4. 22_insurance as i
  5. WHERE
  6. i.TIV_2015 IN(
  7. SELECT
  8. TIV_2015
  9. FROM
  10. 22_insurance
  11. GROUP BY
  12. TIV_2015
  13. HAVING
  14. COUNT(*) > 1
  15. )
  16. AND
  17. CONCAT(LAT, LON) IN(
  18. SELECT
  19. CONCAT(LAT, LON)
  20. FROM
  21. 22_insurance
  22. GROUP BY
  23. LAT , LON
  24. HAVING COUNT(*) = 1
  25. );

23. 订单最多的客户

需求:在表 orders 中找到订单数最多客户对应的 customer_number 。

展示效果:

customer_number
3
  1. Create table If Not Exists 23_orders (order_number int, customer_number int, order_date date, required_date date, shipped_date date, status char(15), comment char(200), key(order_number));
  2. Truncate table 23_orders;
  3. insert into 23_orders (order_number, customer_number, order_date, required_date, shipped_date, status) values (1, 1, '2017-04-09', '2017-04-13', '2017-04-12', 'Closed');
  4. insert into 23_orders (order_number, customer_number, order_date, required_date, shipped_date, status) values (2, 2, '2017-04-15', '2017-04-20', '2017-04-18', 'Closed');
  5. insert into 23_orders (order_number, customer_number, order_date, required_date, shipped_date, status) values (3, 3, '2017-04-16', '2017-04-25', '2017-04-20', 'Closed');
  6. insert into 23_orders (order_number, customer_number, order_date, required_date, shipped_date, status) values (4, 3, '2017-04-18', '2017-04-28', '2017-04-25', 'Closed');

最终SQL:

  1. SELECT
  2. customer_number
  3. FROM
  4. 23_orders
  5. GROUP BY
  6. customer_number
  7. ORDER BY
  8. COUNT(*) DESC
  9. LIMIT 1;

进阶: 如果有多位顾客订单数并列最多,你能找到他们所有的 customer_number 吗?

24. 大的国家

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

展示效果:

name population area
Afghanistan 25500100 652230
Algeria 37100000 2381741
  1. Create table If Not Exists 24_World (name varchar(255), continent varchar(255), area int, population int, gdp bigint);
  2. Truncate table 24_world;
  3. insert into 24_World (name, continent, area, population, gdp) values ('Afghanistan', 'Asia', 652230, 25500100, 20343000000);
  4. insert into 24_World (name, continent, area, population, gdp) values ('Albania', 'Europe', 28748, 2831741, 12960000000);
  5. insert into 24_World (name, continent, area, population, gdp) values ('Algeria', 'Africa', 2381741, 37100000, 188681000000);
  6. insert into 24_World (name, continent, area, population, gdp) values ('Andorra', 'Europe', 468, 78115, 3712000000);
  7. insert into 24_World (name, continent, area, population, gdp) values ('Angola', 'Africa', 1246700, 20609294, 100990000000);

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

最终SQL:

  1. -- 方法一:or
  2. select
  3. w.name,
  4. w.population,
  5. w.area
  6. from
  7. 24_World w
  8. where
  9. w.area >3000000 or w.population >25000000
  10. -- 方法二:union
  11. select
  12. w.name,
  13. w.population,
  14. w.area
  15. from
  16. 24_World w
  17. where
  18. w.area>3000000
  19. union
  20. select
  21. w.name,
  22. w.population,
  23. w.area
  24. from
  25. 24_World w
  26. where
  27. w.population>25000000

25. 超过五名学生的课

需求:编写一个 SQL 查询,列出所有超过或等于5名学生的课。

展示效果:

class
Math
  1. Create table If Not Exists 25_courses (student varchar(255), class varchar(255));
  2. Truncate table 25_courses;
  3. insert into 25_courses (student, class) values ('A', 'Math');
  4. insert into 25_courses (student, class) values ('B', 'English');
  5. insert into 25_courses (student, class) values ('C', 'Math');
  6. insert into 25_courses (student, class) values ('D', 'Biology');
  7. insert into 25_courses (student, class) values ('E', 'Math');
  8. insert into 25_courses (student, class) values ('F', 'Computer');
  9. insert into 25_courses (student, class) values ('G', 'Math');
  10. insert into 25_courses (student, class) values ('H', 'Math');
  11. insert into 25_courses (student, class) values ('I', 'Math');

最终SQL:

  1. select
  2. class
  3. from
  4. 25_courses
  5. group by
  6. class
  7. having
  8. count(distinct student)>=5 ;

26. 好友申请

需求一:写一个查询语句,求出好友申请的通过率,用 2 位小数表示。通过率由接受好友申请的数目除以申请总数。

展示效果:

accept_rate
0.80
  1. Create table If Not Exists 26_friend_request ( sender_id INT NOT NULL, send_to_id INT NULL, request_date DATE NULL);
  2. Create table If Not Exists 26_request_accepted ( requester_id INT NOT NULL, accepter_id INT NULL, accept_date DATE NULL);
  3. Truncate table 26_friend_request;
  4. insert into 26_friend_request (sender_id, send_to_id, request_date) values (1, 2, '2016/06/01');
  5. insert into 26_friend_request (sender_id, send_to_id, request_date) values (1, 3, '2016/06/01');
  6. insert into 26_friend_request (sender_id, send_to_id, request_date) values (1, 4, '2016/06/01');
  7. insert into 26_friend_request (sender_id, send_to_id, request_date) values (2, 3, '2016/06/02');
  8. insert into 26_friend_request (sender_id, send_to_id, request_date) values (3, 4, '2016/06/09');
  9. Truncate table 26_request_accepted;
  10. insert into 26_request_accepted (requester_id, accepter_id, accept_date) values (1, 2, '2016/06/03');
  11. insert into 26_request_accepted (requester_id, accepter_id, accept_date) values (1, 3, '2016/06/08');
  12. insert into 26_request_accepted (requester_id, accepter_id, accept_date) values (2, 3, '2016/06/08');
  13. insert into 26_request_accepted (requester_id, accepter_id, accept_date) values (3, 4, '2016/06/09');

注意:

  1. 通过的好友申请不一定都在表 friend_request 中。在这种情况下,你只需要统计总的被通过的申请数(不管它们在不在原来的申请中),并将它除以申请总数,得到通过率<br />

一个好友申请发送者有可能会给接受者发几条好友申请,也有可能一个好友申请会被通过好几次。这种情况下,重复的好友申请只统计一次。
如果一个好友申请都没有,通过率为 0.00 。

解释: 总共有 5 个申请,其中 4 个是不重复且被通过的好友申请,所以成功率是 0.80 。

最终SQL:

  1. select
  2. round(
  3. ifnull(
  4. (select count(*) from (select distinct requester_id, accepter_id from 26_request_accepted) as A)
  5. /
  6. (select count(*) from (select distinct sender_id, send_to_id from 26_friend_request) as B)
  7. , 0)
  8. , 2) as accept_rate;

需求二:写一个查询语句,求出谁拥有最多的好友和他拥有的好友数目。

展示效果:

id num
3 3

注意:

  • 保证拥有最多好友数目的只有 1 个人。
  • 好友申请只会被接受一次,所以不会有 requester_idaccepter_id 值都相同的重复记录。

最终SQL:

  1. select
  2. ids as id,
  3. cnt as num
  4. from
  5. (select
  6. ids,
  7. count(*) as cnt
  8. from
  9. (select
  10. requester_id as ids
  11. from
  12. 26_request_accepted
  13. union all
  14. select
  15. accepter_id
  16. from
  17. 26_request_accepted
  18. ) as tbl1
  19. group by ids
  20. ) as tbl2
  21. order by
  22. cnt desc
  23. limit 1;

27. 体育馆人流量

需求:请编写一个查询语句,找出人流量的高峰期。高峰期定义,至少连续三行记录中的人流量不少于100。

展示效果:

id visit_date people
5 2017-01-05 145
6 2017-01-06 1455
7 2017-01-07 199
8 2017-01-08 188
  1. Create table If Not Exists 27_stadium (id int, visit_date DATE NULL, people int);
  2. Truncate table 27_stadium;
  3. insert into 27_stadium (id, visit_date, people) values (1, '2017-01-01', 10);
  4. insert into 27_stadium (id, visit_date, people) values (2, '2017-01-02', 109);
  5. insert into 27_stadium (id, visit_date, people) values (3, '2017-01-03', 150);
  6. insert into 27_stadium (id, visit_date, people) values (4, '2017-01-04', 99);
  7. insert into 27_stadium (id, visit_date, people) values (5, '2017-01-05', 145);
  8. insert into 27_stadium (id, visit_date, people) values (6, '2017-01-06', 1455);
  9. insert into 27_stadium (id, visit_date, people) values (7, '2017-01-07', 199);
  10. insert into 27_stadium (id, visit_date, people) values (8, '2017-01-08', 188);

最终SQL:

  1. SELECT
  2. distinct a.*
  3. FROM
  4. 27_stadium as a,
  5. 27_stadium as b,
  6. 27_stadium as c
  7. where
  8. ((a.id = b.id-1 and b.id+1 = c.id) or(a.id-1 = b.id and a.id+1 = c.id) or(a.id-1 = c.id and c.id-1 = b.id))
  9. and
  10. (a.people>=100 and b.people>=100 and c.people>=100)
  11. order by
  12. a.id;

28. 连续空余座位

需求:编写一个 SQL 查询,获取所有空余座位,并将它们按照 seat_id 排序

展示效果:

seat_id
3
4
5
  1. Create table If Not Exists 28_cinema (seat_id int primary key auto_increment, free bool);
  2. Truncate table 28_cinema;
  3. insert into 28_cinema (seat_id, free) values (1, 1);
  4. insert into 28_cinema (seat_id, free) values (2, 0);
  5. insert into 28_cinema (seat_id, free) values (3, 1);
  6. insert into 28_cinema (seat_id, free) values (4, 1);
  7. insert into 28_cinema (seat_id, free) values (5, 1);

注意:

  • seat_id 字段是一个自增的整数,free 字段是布尔类型(’1’ 表示空余, ‘0’ 表示已被占据)。
  • 连续空余座位的定义是大于等于 2 个连续空余的座位。

最终SQL:

  1. select
  2. distinct a.seat_id
  3. from
  4. 28_cinema a
  5. join
  6. 28_cinema b
  7. on
  8. abs(a.seat_id - b.seat_id) = 1 and a.free = true and b.free = true
  9. order by
  10. a.seat_id;

29. 销售员

需求:输出所有表 salesperson中,没有向公司 ‘RED’ 销售任何东西的销售员。

展示效果:

name
Amy
Mark
Alex
  1. Create table If Not Exists 29_salesperson (sales_id int, name varchar(255), salary int,commission_rate int, hire_date varchar(255));
  2. Create table If Not Exists 29_company (com_id int, name varchar(255), city varchar(255));
  3. Create table If Not Exists 29_orders (order_id int, order_date varchar(255), com_id int, sales_id int, amount int);
  4. Truncate table 29_salesperson;
  5. insert into 29_salesperson (sales_id, name, salary, commission_rate, hire_date) values (1,'John',100000, 6, '4/1/2006');
  6. insert into 29_salesperson (sales_id, name, salary, commission_rate, hire_date) values (2,'Amy', 12000, 5, '5/1/2010');
  7. insert into 29_salesperson (sales_id, name, salary, commission_rate, hire_date) values (3,'Mark',65000, 12, '12/25/2008');
  8. insert into 29_salesperson (sales_id, name, salary, commission_rate, hire_date) values (4,'Pam', 25000, 25, '1/1/2005');
  9. insert into 29_salesperson (sales_id, name, salary, commission_rate, hire_date) values (5,'Alex', 5000, 10, '2/3/2007');
  10. Truncate table 29_company;
  11. insert into 29_company (com_id, name, city) values (1, 'RED', 'Boston');
  12. insert into 29_company (com_id, name, city) values (2, 'ORANGE', 'New York');
  13. insert into 29_company (com_id, name, city) values (3, 'YELLOW', 'Boston');
  14. insert into 29_company (com_id, name, city) values (4, 'GREEN', 'Austin');
  15. Truncate table 29_orders;
  16. insert into 29_orders (order_id, order_date, com_id, sales_id, amount) values (1, '1/1/2014', 3, 4, 10000);
  17. insert into 29_orders (order_id, order_date, com_id, sales_id, amount) values (2, '2/1/2014', 4, 5, 5000);
  18. insert into 29_orders (order_id, order_date, com_id, sales_id, amount) values (3, '3/1/2014', 1, 1, 50000);
  19. insert into 29_orders (order_id, order_date, com_id, sales_id, amount) values (4, '4/1/2014', 1, 4, 25000);

最终SQL:

  1. SELECT
  2. s.name
  3. FROM
  4. 29_salesperson s
  5. WHERE
  6. s.sales_id NOT IN (
  7. SELECT
  8. o.sales_id
  9. FROM
  10. 29_orders o
  11. LEFT JOIN
  12. 29_company c
  13. ON
  14. o.com_id = c.com_id
  15. WHERE
  16. c.name = 'RED'
  17. );

30. 节点树

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

表 tree,id 是树节点的编号, p_id 是它父节点的 id 。

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

  1. 叶子:如果这个节点没有任何孩子节点。
  2. 根:如果这个节点是整棵树的根,即没有父节点。
  3. 内部节点:如果这个节点既不是叶子节点也不是根节点。
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. Create table If Not Exists 30_tree (id int, p_id int);
  2. Truncate table 30_tree;
  3. insert into 30_tree (id, p_id) values (1, null);
  4. insert into 30_tree (id, p_id) values (2, 1);
  5. insert into 30_tree (id, p_id) values (3, 1);
  6. insert into 30_tree (id, p_id) values (4, 2);
  7. insert into 30_tree (id, p_id) values (5, 2);

最终SQL:

  1. -- 方法一:
  2. SELECT
  3. id, 'Root' AS Type
  4. FROM
  5. 30_tree
  6. WHERE
  7. p_id IS NULL
  8. UNION
  9. SELECT
  10. id, 'Leaf' AS Type
  11. FROM
  12. 30_tree
  13. WHERE
  14. id NOT IN (SELECT
  15. DISTINCT p_id
  16. FROM
  17. 30_tree
  18. WHERE
  19. p_id IS NOT NULL)
  20. AND p_id IS NOT NULL
  21. UNION
  22. SELECT
  23. id, 'Inner' AS Type
  24. FROM
  25. 30_tree
  26. WHERE
  27. id IN (SELECT
  28. DISTINCT p_id
  29. FROM
  30. 30_tree
  31. WHERE
  32. p_id IS NOT NULL)
  33. AND p_id IS NOT NULL
  34. ORDER BY id;
  35. -- 方法二:
  36. SELECT
  37. id AS `Id`,
  38. CASE
  39. WHEN t1.id = (SELECT t2.id FROM 30_tree as t2 WHERE t2.p_id IS NULL) THEN 'Root'
  40. WHEN t1.id IN (SELECT t3.p_id FROM 30_tree t3) THEN 'Inner'
  41. ELSE 'Leaf'
  42. END AS Type
  43. FROM
  44. 30_tree t1
  45. ORDER BY `Id`;
  46. -- 方法三:
  47. SELECT
  48. t1.id,
  49. IF(ISNULL(t1.p_id),'Root', IF(t1.id IN (SELECT p_id FROM 30_tree), 'Inner','Leaf')) Type
  50. FROM
  51. 30_tree t1
  52. ORDER BY t1.id;

31. 判断是否是三角形

需求:编写一个 SQL 查询,判断三条线段是否能形成一个三角形。

展示效果:

x y z triangle
13 15 30 No
10 20 15 Yes
  1. Create table If Not Exists 31_triangle (x int, y int, z int);
  2. Truncate table 31_triangle;
  3. insert into 31_triangle (x, y, z) values (13, 15, 30);
  4. insert into 31_triangle (x, y, z) values (10, 20, 15);

最终SQL:

  1. select
  2. x,
  3. y,
  4. z,
  5. if((x + y <= z or x + z <= y or y + z <= x), "No", "Yes") as triangle
  6. from 31_triangle;

32. 平面上的最近距离

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

展示效果:

shortest
1.00
  1. CREATE TABLE If Not Exists 32_point_2d (x INT NOT NULL, y INT NOT NULL);
  2. Truncate table 32_point_2d;
  3. insert into 32_point_2d (x, y) values (-1, -1);
  4. insert into 32_point_2d (x, y) values (0, 0);
  5. insert into 32_point_2d (x, y) values (-1, -2);

最终SQL:

  1. -- 方法一:
  2. SELECT
  3. ROUND(SQRT(MIN((POW(p1.x - p2.x, 2) + POW(p1.y - p2.y, 2)))), 2) AS shortest
  4. FROM
  5. 32_point_2d p1
  6. JOIN
  7. 32_point_2d p2
  8. ON
  9. p1.x != p2.x OR p1.y != p2.y;
  10. -- 方法二:
  11. SELECT
  12. ROUND(SQRT(MIN((POW(p1.x - p2.x, 2) + POW(p1.y - p2.y, 2)))),2) AS shortest
  13. FROM
  14. 32_point_2d p1
  15. JOIN
  16. 32_point_2d p2
  17. ON (p1.x <= p2.x AND p1.y < p2.y) OR (p1.x <= p2.x AND p1.y > p2.y) OR (p1.x < p2.x AND p1.y = p2.y);

33. 直线上最近距离

需求:找到这些点中最近两个点之间的距离。

展示效果:

shortest
1
  1. CREATE TABLE If Not Exists 33_point (x INT NOT NULL, UNIQUE INDEX x_UNIQUE (x ASC));
  2. Truncate table 33_point;
  3. insert into 33_point (x) values (-1);
  4. insert into 33_point (x) values (0);
  5. insert into 33_point (x) values (2);

最终SQL:

  1. SELECT
  2. MIN(ABS(p1.x - p2.x)) AS shortest
  3. FROM
  4. 33_point p1
  5. JOIN
  6. 33_point p2
  7. ON p1.x != p2.x;

34. 二级关注者

需求:对每一个关注者(follower),查询他的关注者数目。

展示效果:

follower num
B 2
D 1
  1. Create table If Not Exists 34_follow (followee varchar(255), follower varchar(255));
  2. Truncate table 34_follow;
  3. insert into 34_follow (followee, follower) values ('A', 'B');
  4. insert into 34_follow (followee, follower) values ('B', 'C');
  5. insert into 34_follow (followee, follower) values ('B', 'D');
  6. insert into 34_follow (followee, follower) values ('D', 'E');

解释:

以A为主体,A为被关注者,B为被关注者,求出关注B的关注者。这里需要注意,被关注者永远不会被他 / 她自己关注。
将结果按照字典序返回。

最终SQL:

  1. select
  2. followee as 'follower',
  3. count(distinct follower) as num
  4. from
  5. 34_follow
  6. where
  7. followee in(select follower from 34_follow)
  8. group by 1
  9. order by 1;

说明:这里的group by 表示使用第一列作为分组依据,order by 同理。

35. 平均工资

需求:写一个查询语句,求出在每一个工资发放日,每个部门的平均工资与公司的平均工资的比较结果 (高 / 低 / 相同)

展示效果:

pay_month department_id comparison
2017-03 1 higher
2017-03 2 lower
2017-02 1 same
2017-02 2 same
  1. Create table If Not Exists 35_salary (id int, employee_id int, amount int, pay_date date);
  2. Create table If Not Exists 35_employee (employee_id int, department_id int);
  3. Truncate table 35_salary;
  4. insert into 35_salary (id, employee_id, amount, pay_date) values (1, 1, 9000, '2017/03/31');
  5. insert into 35_salary (id, employee_id, amount, pay_date) values (2, 2, 6000, '2017/03/31');
  6. insert into 35_salary (id, employee_id, amount, pay_date) values (3, 3, 10000, '2017/03/31');
  7. insert into 35_salary (id, employee_id, amount, pay_date) values (4, 1, 7000, '2017/02/28');
  8. insert into 35_salary (id, employee_id, amount, pay_date) values (5, 2, 6000, '2017/02/28');
  9. insert into 35_salary (id, employee_id, amount, pay_date) values (6, 3, 8000, '2017/02/28');
  10. Truncate table 35_employee;
  11. insert into 35_employee (employee_id, department_id) values (1, 1);
  12. insert into 35_employee (employee_id, department_id) values (2, 2);
  13. insert into 35_employee (employee_id, department_id) values (3, 2);

解释:

在三月,公司的平均工资是 (9000+6000+10000)/3 = 8333.33…

由于部门 1 里只有一个 employee_id 为 1 的员工,所以部门 1 的平均工资就是此人的工资 9000 。因为 9000 > 8333.33 ,所以比较结果是 ‘higher’。

第二个部门的平均工资为 employee_id 为 2 和 3 两个人的平均工资,为 (6000+10000)/2=8000 。因为 8000 < 8333.33 ,所以比较结果是 ‘lower’ 。

在二月用同样的公式求平均工资并比较,比较结果为 ‘same’ ,因为部门 1 和部门 2 的平均工资与公司的平均工资相同,都是 7000 。

最终SQL:

  1. select
  2. department_salary.pay_month,
  3. department_id,
  4. case
  5. when department_avg>company_avg then 'higher'
  6. when department_avg<company_avg then 'lower'
  7. else 'same'
  8. end as comparison
  9. from
  10. (select
  11. department_id,
  12. avg(amount) as department_avg,
  13. date_format(pay_date, '%Y-%m') as pay_month
  14. from
  15. 35_salary as s1
  16. join
  17. 35_employee as e1
  18. on
  19. s1.employee_id = e1.employee_id
  20. group by
  21. department_id, pay_month
  22. ) as department_salary
  23. join
  24. (select
  25. avg(amount) as company_avg,
  26. date_format(pay_date, '%Y-%m') as pay_month
  27. from
  28. 35_salary
  29. group by
  30. date_format(pay_date, '%Y-%m')
  31. ) as company_salary
  32. on
  33. department_salary.pay_month = company_salary.pay_month;

36. 学生地理信息报告

需求:写一个查询语句实现对大洲(continent)列的 透视表 操作,使得每个学生按照姓名的字母顺序依次排列在对应的大洲下面。输出的标题应依次为美洲(America)、亚洲(Asia)和欧洲(Europe)。数据保证来自美洲的学生不少于来自亚洲或者欧洲的学生。

展示效果:

America Asia Europe
Jack Xi Pascal
Jane
  1. Create table If Not Exists 36_student (name varchar(50), continent varchar(7));
  2. Truncate table 36_student;
  3. insert into 36_student (name, continent) values ('Jane', 'America');
  4. insert into 36_student (name, continent) values ('Pascal', 'Europe');
  5. insert into 36_student (name, continent) values ('Xi', 'Asia');
  6. insert into 36_student (name, continent) values ('Jack', 'America');

最终SQL:

  1. -- 方法一
  2. SELECT
  3. MAX(if(A.continent = 'America',A.NAME,NULL)) AS `America`,
  4. MAX(if(A.continent = 'Asia',A.NAME,NULL)) AS `Asia`,
  5. MAX(if(A.continent = 'Europe',A.NAME,NULL)) AS `Europe`
  6. FROM
  7. (SELECT
  8. S1.continent,
  9. S1.NAME,
  10. S1.row_id,
  11. COUNT(*) AS `trank`
  12. FROM
  13. (SELECT
  14. S.*,
  15. @row_id:=(@row_id + 1) AS `row_id`
  16. FROM
  17. 36_student AS S,
  18. (SELECT @row_id:=0) AS T
  19. ) AS S1
  20. JOIN
  21. (SELECT
  22. S.*,
  23. @n_row_id:=(@n_row_id + 1) AS `n_row_id`
  24. FROM
  25. 36_student AS S,
  26. (SELECT @n_row_id:=0) AS T
  27. ) AS S2
  28. ON
  29. (S1.continent = S2.continent AND (S1.NAME > S2.NAME OR (S1.NAME = S2.NAME AND S1.row_id >= S2.n_row_id)))
  30. group BY
  31. S1.continent,S1.NAME,S1.row_id
  32. order BY
  33. S1.continent,S1.NAME
  34. ) AS A
  35. GROUP BY
  36. A.trank;
  37. -- 方法二
  38. SELECT
  39. MAX(IF(continent = 'America', name, NULL)) America,
  40. MAX(IF(continent = 'Asia', name, NULL)) Asia,
  41. MAX(IF(continent = 'Europe', name, NULL)) Europe
  42. FROM
  43. (SELECT continent,name,ROW_NUMBER() OVER(PARTITION BY continent ORDER BY name) rn FROM 36_student) T
  44. GROUP BY rn

37. 只出现一次的最大数字

需求:编写一个 SQL 查询,找到只出现过一次的数字中,最大的一个数字。如果没有只出现一次的数字,输出 null 。

展示效果:

num
6
  1. Create table If Not Exists 37_my_numbers (num int);
  2. Truncate table 37_my_numbers;
  3. insert into 37_my_numbers (num) values (8);
  4. insert into 37_my_numbers (num) values (8);
  5. insert into 37_my_numbers (num) values (3);
  6. insert into 37_my_numbers (num) values (3);
  7. insert into 37_my_numbers (num) values (1);
  8. insert into 37_my_numbers (num) values (4);
  9. insert into 37_my_numbers (num) values (5);
  10. insert into 37_my_numbers (num) values (6);

最终SQL:

  1. select
  2. ifnull((SELECT
  3. num
  4. FROM
  5. 37_my_numbers
  6. group by
  7. num
  8. having
  9. count(*) = 1
  10. order by
  11. num desc
  12. limit 1), null) as num;

38. 有趣的电影

需求:编写一个 SQL 查询,找出所有影片描述为非 boring (不无聊) 的并且 id 为奇数 的影片,结果请按等级 rating 排列

展示效果:

id movie description rating
5 House card Interesting 9.1
1 War great 3D 8.9
  1. Create table If Not Exists 38_cinema (id int, movie varchar(255), description varchar(255), rating float(2, 1));
  2. Truncate table 38_cinema;
  3. insert into 38_cinema (id, movie, description, rating) values (1, 'War', 'great 3D', 8.9);
  4. insert into 38_cinema (id, movie, description, rating) values (2, 'Science', 'fiction', 8.5);
  5. insert into 38_cinema (id, movie, description, rating) values (3, 'irish', 'boring', 6.2);
  6. insert into 38_cinema (id, movie, description, rating) values (4, 'Ice song', 'Fantacy', 8.6);
  7. insert into 38_cinema (id, movie, description, rating) values (5, 'House card', 'Interesting', 9.1);

最终SQL:

  1. select
  2. id,
  3. movie,
  4. description,
  5. rating
  6. from
  7. 38_cinema
  8. where
  9. mod(id, 2) = 1 and description != 'boring'
  10. order by
  11. rating DESC;

说明:mod 函数求余数

39. 换座位

需求:编写一个 SQL 查询,对相邻的两位同学进行位置交换(例如:id=1 和id=2 的进行交换,id=3 和id=4 的进行交换)。如果学生人数是奇数,则不需要改变最后一个同学的座位。

展示效果:

id student
1 Doris
2 Abbot
3 Green
4 Emerson
5 Jeames
  1. Create table If Not Exists 39_seat(id int, student varchar(255));
  2. Truncate table 39_seat;
  3. insert into 39_seat (id, student) values (1, 'Abbot');
  4. insert into 39_seat (id, student) values (2, 'Doris');
  5. insert into 39_seat (id, student) values (3, 'Emerson');
  6. insert into 39_seat (id, student) values (4, 'Green');
  7. insert into 39_seat (id, student) values (5, 'Jeames');

最终SQL:

  1. -- 方法一
  2. select
  3. a.id,
  4. ifnull(b.student,a.student) as student
  5. from
  6. 39_seat as a
  7. left join
  8. 39_seat as b
  9. on
  10. (a.id%2=1 && a.id=b.id-1) || (a.id%2=0 && a.id=b.id+1)
  11. order by
  12. a.id;
  13. -- 方法二
  14. select
  15. if(id%2=0,id-1,if(id=cnt,id,id+1)) as id,
  16. student
  17. from
  18. (select
  19. count(*) as cnt
  20. from
  21. 39_seat
  22. )as a,
  23. 39_seat
  24. order by id;
  25. -- 方法三
  26. select
  27. b.id,
  28. a.student
  29. from
  30. 39_seat as a,
  31. 39_seat as b,
  32. (select
  33. count(*) as cnt
  34. from
  35. 39_seat
  36. ) as c
  37. where
  38. b.id=1^(a.id-1)+1 || (c.cnt%2 && b.id=c.cnt && a.id=c.cnt);

40. 交换性别

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

展示效果:

id name sex salary
1 A f 2500
2 B m 1500
3 C f 5500
4 D m 500
  1. create table if not exists 40_salary(id int, name varchar(100), sex char(1), salary int);
  2. Truncate table 40_salary;
  3. insert into 40_salary (id, name, sex, salary) values (1, 'A', 'm', 2500);
  4. insert into 40_salary (id, name, sex, salary) values (2, 'B', 'f', 1500);
  5. insert into 40_salary (id, name, sex, salary) values (3, 'C', 'm', 5500);
  6. insert into 40_salary (id, name, sex, salary) values (4, 'D', 'f', 500);

最终SQL:

  1. UPDATE 40_salary
  2. SET
  3. sex = CASE sex
  4. WHEN 'm' THEN 'f'
  5. ELSE 'm'
  6. END;