文章目录

  • MySQL配置
  • 数据库准备
  • 1. 大国
  • 2. 换座位
    • 2.1 solution-1
    • 2.2 solution-2
  • 3. 交换工资
    • solution-1
  • 4. 有趣的电影
    • solution
  • 5. 超过5名学生的课
    • solution-1 group by + having
    • solution-2 group by + 子查询
  • 6. 查找重复的电子邮箱
  • 7. 删除重复的电子邮箱
    • solutionn-1 子查询
    • solution-2 自连接
  • 8. 组合两个表
  • 9. 超过经理收入的员工
  • 10. 从不订购的客户
    • solution1 子查询
    • solution2 左连接 + null值判断
  • 11. 部门工资最高的员工
  • 12. 第二高的薪水
  • 13. 编写一个 SQL 查询,获取 Employee 表中第 n 高的薪水(Salary)。
  • 14. 分数排名
  • 15. 补充-1 分段统计 贝壳面试题

MySQL配置

  1. 关闭safe updates模式,该模式下非键条件(wehre字段不是key)无法执行update和delete
    show variables like ‘sql_safe_updates’;
    set sql_safe_updates = ‘off’;

  2. only_full_group_by
    5.7默认开启,该模式下,select和order by等所涉及的字段必须在group by中出现过。查询字段含有聚合函数除外,例如select count(xx).
    谨慎使用select any_value(xx),
    例如 select any_value(a), b from table gorup by b;
    该查询只会返回一个分组结果,对于若b分组内有多个a,其只会随机返回一个,而不是返回该分组下的所有记录。

数据库准备

  1. 创建干净的数据库
    drop database if exists leetcode;
    create database leetcode;
    use leetcode;

1. 大国

如果一个国家的面积超过300万平方公里,或者人口超过2500万,那么这个国家就是大国家。
编写一个SQL查询,输出表中所有大国家的名称、人口和面积。
schema

drop table if exists World;
CREATE TABLE World (name VARCHAR(255),continent VARCHAR(255),area INT,population INT,gdp INT
);
insert into World (name, continent, area, population, gdp)
values ('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');

solution

SELECT name, population, area
FROMWorld
WHEREarea > 3000000 OR population > 25000000;

2. 换座位

小美是一所中学的信息科技老师,她有一张 seat 座位表,平时用来储存学生名字和与他们相对应的座位 id。
其中纵列的 id 是连续递增的
小美想改变相邻俩学生的座位。
如果学生人数是奇数,则不需要改变最后一个同学的座位。

ps:调换1-2,3-4…的座位上的学生。

schema

create table if not exists seat (id int unique,student varchar(255)
);
truncate table seat;
insert into seat (id, student) values('1', 'Abbot'),('2', 'Doris'),('3', 'Emerson'), ('4', 'Green'),('5', 'Jeames');

2.1 solution-1

使用case when

CASE WHEN THEN ELSE END语法
Case具有两种格式。简单Case函数和Case搜索函数。

--简单Case函数
CASE sexWHEN '1' THEN '男'WHEN '2' THEN '女'
ELSE '其他' END
--Case搜索函数
CASE WHEN sex = '1' THEN '男'WHEN sex = '2' THEN '女'
ELSE '其他' END

Case会返回第一个符合条件的值,需要注意的是,需要使用AS指定CASE语句的列名,否则该列的名称将会为CASE语句本身。

# 交换操作 = 偶数id自减,奇数id自增(最后一个除外)
SELECT (CASEWHEN id % 2 != 0 AND seat_counts.counts != id THEN id + 1WHEN MOD(id, 2) != 0 AND counts = id THEN idELSE id - 1END) AS id,student
FROMseat,(SELECT # 内联视图(SELECT产生的临时表),SELECT结果作为seat_counts 表COUNT(*) AS counts # COUNT函数结果作为counts列值FROMseat) AS seat_counts
ORDER BY id ASC;

2.2 solution-2

使用union
UNION语法
UNION用于合并多个SELECT执行结果,SELECT的列数相同、列数据类型相似。结果集的列名等于第一个SELECT中的列名。UNION会剔除相同的值,UNION ALL允许有重复值。

SELECT column_name(s) FROM table1
UNION
SELECT column_name(s) FROM table2;

使用UNION合并多个情况的查询结果

SELECT id - 1 AS id, student FROM seat WHERE id % 2 = 0
UNION SELECT id + 1, student FROM seat WHERE id % 2 != 0AND id != (SELECT MAX(id) FROM seat)
UNION SELECT id, student FROM seat WHERE id % 2 != 0AND id = (SELECT MAX(id) FROM seat)
ORDER BY id ASC;

3. 交换工资

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

schema

create table if not exists salary (id int,name varchar(255),sex char(1),salary int
);
truncate table salary;
insert into salary (id, name, sex, salary) values(1, 'A', 'm', 2500),(2, 'B', 'f', 1500),(3, 'C', 'm', 5500),(4, 'D', 'f', 500);

solution-1

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

4. 有趣的电影

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

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

schema

create table if not exists cinema (id int8 primary key, # int 有 1 2 4 8字节movie varchar(255),description varchar(255),rating float(2, 1) # 浮点数可指定精度,(2,1)表示小数点后一位共两位,例如1.3
);
truncate table cinema;
insert into cinema (id, movie, description, rating) values ('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');

solution

SELECT id, movie, description, rating
FROMcinema
WHEREdescription != 'boring' AND id % 2 != 0
ORDER BY rating DESC;

5. 超过5名学生的课

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

schema

create table if not exists courses (student varchar(255),class varchar(255)
);
truncate table courses;
insert into courses (student, class) values ('A', 'Math'),('B', 'English'),('C', 'Math'),('D', 'Biology'),('E', 'Math'),('F', 'Computer'),('G', 'Math'),('H', 'Math'),('I', 'Math');

列出每门课的学生(已去除重复记录)

SELECT class, COUNT(DISTINCT student) AS stu_count # count计数,sum累加
FROMcourses
GROUP BY class; # group by用于对结果集进行分组,将相同值的列放在同一组中。若无,则COUNT列统计所有列。

solution-1 group by + having

SELECT class
FROMcourses
GROUP BY class
HAVING COUNT(DISTINCT student) >= 5; # where过滤行,having过滤分组

solution-2 group by + 子查询

SELECT class
FROM(SELECT class, COUNT(DISTINCT student) AS stu_countFROMcoursesGROUP BY class) AS temp # 使用子查询统计每门课的学生数量
WHEREstu_count >= 5;

6. 查找重复的电子邮箱

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

create table if not exists Person (Id int8 primary key,Email varchar(255)
);
truncate table Person;
insert into Person (Id, Email) values ('1', 'a@b.com'),('2', 'c@d.com'),('3', 'a@b.com');

**solution **

# 分组统计每个Email的ID数,找出大于1的。
SELECT Email
FROMPerson
GROUP BY Email
HAVING COUNT(Id) >= 2;

7. 删除重复的电子邮箱

编写一个 SQL 查询,来删除 Person 表中所有重复的电子邮箱,
重复的邮箱里只保留 Id 最小 的那个。

schema

create table if not exists Person (Id int8 primary key,Email varchar(255)
);
truncate table Person;
insert into Person (Id, Email) values ('1', 'john@example.com'),('2', 'bob@example.com'),('3', 'john@example.com');

solutionn-1 子查询

先按照Email分组,查询min(id),然后删除非min(id)的记录。

/**
错误写法
You can't specify target table 'Person' for update in FROM clause
在MySQL中,不能先select出同一表中的某些值,再更新这个表(在同一语句中) **/
DELETE FROM Person
WHEREId NOT IN (SELECT MIN(Id) FROM Person GROUP BY Email);/**
正确写法,在嵌套一个子查询
**/
DELETE FROM Person
WHEREId NOT IN (SELECT Id FROM (SELECT MIN(id) AS Id FROM Person GROUP BY Email) AS temp);

solution-2 自连接

/**
隐式连接“,”等同于内连接inner join(简写join)。
内连接扫描左表的每一行,将其与右表的每一行比较,
符合连接条件时,返回由这两行组成的新行。
**/
DELETE p1
FROMPerson p1,Person p2
WHEREp1.Email = p2.Email AND p1.Id > p2.Id; # Email相等的行中(分组效果),ID较大者。

8. 组合两个表

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

schema

drop table Person;
create table Person (PersonId int8 primary key,FirstName varchar(255),LastName varchar(255)
);
drop table Address;
create table Address (AddressId int8 primary key,PersonId int,City varchar(255),State varchar(255)
);
insert into Person (PersonId, LastName, FirstName) values ('1', 'Wang', 'Allen');
insert into Address (AddressId, PersonId, City, State) values ('1', '2', 'New York City', 'New York');

solution 左连接,返回左表所有数据。

SELECT FirstName, LastName, City, State
FROMPerson pLEFT JOINAddress a ON p.PersonId = a.PersonId;

9. 超过经理收入的员工

Employee 表包含所有员工,他们的经理也属于员工。每个员工都有一个 Id,
此外还有一列对应员工的经理的 Id。
给定 Employee 表,编写一个 SQL 查询,该查询可以获取收入超过他们经理的员工的姓名。

schema

create table if not exists Employee (Id int8 primary key,Name varchar(255),Salary varchar(255),ManagerId int
);
truncate table Employee;
insert into Employee (Id, Name, Salary, ManagerId) values ('1', 'Joe', '70000', '3'),('2', 'Henry', '80000', '4'),('3', 'Sam', '60000', null),('4', 'Max', '90000', null);

solution 自连接

SELECT e1.Name AS Employee
FROMEmployee AS e1INNER JOINEmployee e2 ON e1.ManagerId = e2.IdAND e1.Salary > e2.Salary;

10. 从不订购的客户

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

shcema

create table if not exists Customers (Id int8 primary key,Name varchar(255)
);
truncate table Customers;
create table if not exists Orders (Id int8 primary key,CustomerId int
);
truncate table Orders;
insert into Customers (Id, Name) values ('1', 'Joe');
insert into Customers (Id, Name) values ('2', 'Henry');
insert into Customers (Id, Name) values ('3', 'Sam');
insert into Customers (Id, Name) values ('4', 'Max');
insert into Orders (Id, CustomerId) values ('1', '3');
insert into Orders (Id, CustomerId) values ('2', '1');

solution1 子查询

SELECT Name AS Customers
FROMCustomers
WHEREid NOT IN (SELECT CustomerId FROM Orders);

solution2 左连接 + null值判断

/**
on条件:生成临时表的条件
where条件:在生成的临时表中的过滤条件
null值判断:使用is或者is not,不能使用=。null与其它值均不相等,包括null。
**/
SELECT *
FROMCustomers cLEFT JOINOrders o ON c.Id = o.CustomerId
WHEREo.CustomerId IS NULL
;

11. 部门工资最高的员工

Employee 表包含所有员工信息,每个员工有其对应的 Id, salary 和 department Id。
Department 表包含公司所有部门的信息。
编写一个 SQL 查询,找出每个部门工资最高的员工。

schema

drop table if exists Employee;
create table Employee (Id int8 primary key,Name varchar(255),Salary int8,DepartmentId int8
);
drop table if exists Department;
Create table If Not Exists Department (Id int, Name varchar(255));
INSERT INTO Employee ( Id, NAME, Salary, DepartmentId )
VALUES( 1, 'Joe', 70000, 1 ),( 2, 'Henry', 80000, 2 ),( 3, 'Sam', 60000, 2 ),( 4, 'Max', 90000, 1 );
INSERT INTO Department ( Id, NAME )
VALUES( 1, 'IT' ),( 2, 'Sales' );

错误解法 包含非group by字段,返回结果不确定

select any_value(d.Name) as Department, any_value(e.Name) as Employee, max(e.Salary)
from Employee e
left join Department d on e.DepartmentId = d.Id
group by e.DepartmentId;

solution

# 创建一个临时表(内联视图),查询每个部门的最大薪资。之后在Employeee和Department的联合表中找到一名部门与薪资与
# 临时表中相符的记录。SELECT d.name AS Department, e.Name AS Employee, e.Salary AS Salary
FROMEmployee e,Department d,(SELECT DepartmentId, MAX(Salary) AS max_salary FROM Employee GROUP BY DepartmentId) AS temp
WHEREe.DepartmentId = d.IdAND e.Salary = temp.max_salaryAND e.DepartmentId = temp.DepartmentId;

solution -2

# 使用子查询+in操作(可以匹配多个列)
SELECT d.name Department, e.name Employee, e.Salary Salary
FROMEmployee e,Department d
WHEREe.DepartmentId = d.IdAND (e.DepartmentId , e.Salary) IN (SELECT DepartmentId, MAX(Salary) FROM Employee GROUP BY DepartmentId);

12. 第二高的薪水

编写一个 SQL 查询,获取 Employee 表中第二高的薪水(Salary)。
如果不存在第二高的薪水,那么查询应返回 null。

schema

drop table if exists Employee;
Create table Employee (Id int, Salary int);
insert into Employee (Id, Salary) values ('1', '100');
insert into Employee (Id, Salary) values ('2', '200');
insert into Employee (Id, Salary) values ('3', '300');

solution distinct + limit(从0开始的offset, 行数(-1表示末尾)) + 子查询

# 额外嵌套一个select以实现没有符合记录时返回null
SELECT (SELECT DISTINCTSalaryFROMEmployeeORDER BY Salary DESCLIMIT 1 , 1) AS SecondHighestSalary;

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

如果不存在第 n 高的薪水,那么查询应返回 null。

solution 自定义函数

/**
MySQL默认结束符是;,但函数声明中含有:,所以使用delimiter将
分隔符临时改成其它符号,例如$$;
**/
delimiter $$
create function getNthHighestSalary (N int) returns int
beginset N = N - 1;return (select (select distinct Salary from Employee order by Salary DESC limit N, 1));
end
$$
delimiter ;select getNthHighestSalary(1);

14. 分数排名

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

schema

/**
decimal:数字型,不存在精度损失
decimal(18, 9) 表示总共18位,小数部分9位。
**/
DROP TABLE IF EXISTS Scores;
CREATE TABLE Scores ( Id INT, Score DECIMAL ( 3, 2 ) );
INSERT INTO Scores ( Id, Score )
VALUES( 1, 3.5 ),( 2, 3.65 ),( 3, 4.0 ),( 4, 3.85 ),( 5, 4.0 ),( 6, 3.65 );

solution

select Score, temp.Rank from
(select s1.Id id, count(distinct s2.Score) Rank
from Scores s1 Inner join Scores s2 on s1.Score <= s2.Score group by
s1.Id) as temp, Scores
order by Rank DEsc;

15. 补充-1 分段统计 贝壳面试题

有person表,字段有ID、Age,统计每个年龄段的人数,10-20,20-30等等。
shcema

drop table person_beike;
create table if not exists person_beike (id int primary key auto_increment, age int1);
truncate table person_beike;
insert into person_beike (age) values
(1),
(12),
(21),
(31),
(41),
(51),
(52),
(90);

solution-1 利用union合并多个查询
SELECT “xxx” col可在结果集中添加col列,其列内容为xxx。

select "0-10" type, count(*) count from person_beike where age <= 10
union
select "10-20" type, count(*) count from person_beike where age > 10 and age <= 20;

LeetCode SQL 刷题相关推荐

  1. Leetcode SQL 刷题 Mysql【2】

    [11]595. 大的国家 select name,population,area from World where area > 3000000 or population > 2500 ...

  2. 牛客网SQL刷题笔记(MySQL)

    牛客网SQL刷题笔记(MySQL) 此博客集合LeetCode.牛客网常见的题型及其解法,侵删 目录 牛客网SQL刷题笔记(MySQL) 类型1:查找排名第几的数据 SQL2 查找入职员工时间排名倒数 ...

  3. 【Leetcode】 刷题之路1(python)

    leetcode 刷题之路1(python) 看到有大佬总结了一些相关题目,想着先刷一类. 1.两数之和 15.三数之和 16.最接近的三数之和 11.盛最多的水 18.四数之和 454.四数相加II ...

  4. leetcode每日刷题计划-简单篇day8

    leetcode每日刷题计划-简单篇day8 今天是纠结要不要新买手机的一天QAQ想了想还是算了吧,等自己赚钱买,加油 Num 70 爬楼梯 Climbing Stairs class Solutio ...

  5. 「数据库」sql刷题(No.11)

    喜欢就 关注 我们吧! 简介:  Hello 各位 ,我是公号「八点半技术站」的创作者 - Bruce.D (姓氏:豆). 感谢微信给予的个人认证,专注于PHP.Go.数据库技术领域知识经验分享. 技 ...

  6. LeetCode代码刷题(17~24)

    目录 17. 电话号码的字母组合 18. 四数之和 19. 删除链表的倒数第 N 个结点 20. 有效的括号 21. 合并两个有序链表 22. 括号生成 23. 合并K个升序链表 24. 两两交换链表 ...

  7. leetcode分类刷题笔记

    leetcode分类刷题笔记--基于python3 写在前面 1.做题如果实在想不出时间复杂度比较优的解法,可以先写出暴力解法,尝试在其基础上优化 2.排序.双指针.二分等--经常可以优化时间复杂度 ...

  8. SQL刷题记录(一)

    SQL刷题记录(一) 答主刚开始自学SQL,本专栏记录的是答主在牛客上刷题的过程.疑惑和部分思路都会写在习题下方. 题目来源:牛客网刷题网址 本文内容:T195-T225 T195. select * ...

  9. 【SQL刷题】DAY16----SQL高级联结专项练习

    博主昵称:跳楼梯企鹅 博主主页面链接:主页传送门 博主专栏页面连接:网络安全专栏传送么门 创作初心:本博客的初心为与技术朋友们相互交流,每个人的技术都存在短板,博主也是一样,虚心求教,希望各位技术友给 ...

最新文章

  1. 程序员工资为什么高?
  2. R语言警告:Cannot compute exact p-value with ties的处理方法
  3. Android最佳的开源库(四)
  4. Linux内核中的进程组及会话
  5. Scala模式匹配中的变量
  6. java源程序加密解决方案(基于Classloader解密)
  7. 微电子科学与工程要学计算机吗,微电子科学与工程专业就业前景如何 有前途吗...
  8. HDU 4722 Good Numbers 2013年四川省赛题
  9. 《C++编程——数据结构与程序设计方法》程序范例:影碟店(源代码)
  10. android sdk引入 微信分享_Android 微信SDK分享功能中的最全过程步骤分析
  11. java--Date时间
  12. Java基础002 Java9开发环境搭建(Win10平台)
  13. 去掉内容中的所有全部html标签。
  14. 做片子留着备用 超级游戏影视配乐音效库36套合集
  15. 如何使用gdb调试java虚拟机_Eclispe+qemu+gdb调试linux Kernel
  16. MarkDown 分割线
  17. MOOC创新创业学第十二章单元测试题及答案
  18. Google DFP广告管理系统简介:开始与您的网站进行广告集成
  19. qduoj 分辣条2
  20. java 葫芦娃.rmvb,课内资源 - 基于JAVA的葫芦娃 — 最终之战

热门文章

  1. 快速入手springboot
  2. 彻底理解 模拟频率、数字频率、模拟角频率
  3. 是到了更换项目管理工具的时候了吗? (转)
  4. HTML5调用摄像头录制视频
  5. GPUImageMovieWrite录制MP4视频出现can't write frame解决方法
  6. 『.NET Tools』在.Net Core中实现汉字转拼音
  7. 【绝对干货】2021年哔哩哔哩Java高级面试题及答案,完整版开放下载
  8. uni - app 的 pages.json 文件页面配置与全局配置
  9. java设置阴影边框_CSS边框阴影效果:box-shadow属性的使用解释
  10. B站上诉A站抢注商标被驳回,承担案件受理费100元