这篇文章主要是为了学习查询的 sql 语句~
主要是《MySQL必知必会》的笔记,也可能会加入其他额外查询的知识
结合 leetcode 的 sql 例题理解
数据库表名唯一
主键(一列、或一组列):唯一区分表中各行,需要满足条件:
主键的好习惯:(主要就是保持主键值稳定啦)
为什么用 MySQL?
安装、开启 MySQL 之类的内容,可以去其他博客看看,我这里就不造轮子了= =
USE databaseName;
SHOW DATABASES;
SHOW TABLES;
tips:自动增量 auto_increment,用于订单编号、用户ID等地方。这个属性会让 MySQL 自动地为每个行分配下一个可用编号。
SELECT id, name, price FROM products;
SELECT * FROM products;
SELECT DISTINCT id FROM products;
SELECT DISTINCT id, price; # (1,100)和 (1,200)都会显示,即使 id 一样
SELECT name FROM products LIMIT 5; # 只要前 5 行
SELECT name FROM products LIMIT 3, 5; # 从行 3 开始的 5 行
# 行数不够时,有几行返几行
SELECT product.name FROM products;
SELECT name FROM products ORDER BY id; # 默认升序
SELECT name FROM products ORDER BY price, id; # 按多个列排序,从左到右(后面的可能用不到)
SELECT name FROM products ORDER BY id DESC; # 变成降序
SELECT name FROM products ORDER BY price DESC, id; # 可以部分降序,在需要降序的列后面加 DESC 即可
注意:ORDER BY 子句必须在 FROM 子句之后
# = != < <= > >= 等于、不等于、大于小于
SELECT name FROM products WHERE name = 'fuses'; # 字符串用单引号
# BETWEEN 指定值,双闭区间
SELECT name FROM products WHERE price BETWEEN 5 AND 10 # 用 AND,范围[5, 10]
SELECT name FROM products WHERE name != NULL # 无效
SELECT name FROM products WHERE name IS NOT NULL # 有效
SELECT id FROM products WHERE id > 5 AND id < 10;
SELECT id FROM products WHERE id > 5 OR id % 2 = 0;
SELECT id FROM products WHERE (id = 2 OR id = 3) AND price >= 100; # 括号优先级最高
SELECT id FROM products WHERE id = 2 OR id = 3 AND price >= 100; # 不加括号,则等同于 id = 2 OR (id = 3 AND price >= 100),意义不同了
SELECT id FROM products WHERE id IN (1, 2, 5);
SELECT id FROM products WHERE id = 1 OR id = 2 OR id = 5; # 等同
SELECT id FROM products WHERE id NOT IN (1, 2, 5);
这块感觉用得不多,简单写写吧
SELECT id FROM products WHERE name LIKE 'jet%'; # 寻找 jet 开头的产品
SELECT id FROM products WHERE name LIKE '%jet%'; # 可以在任意位置使用多个
# 可以修改配置,选择【区分大小写】。不能匹配 NULL
SELECT id FROM products WHERE name LIKE '_ jojo';
# 得到 '1 jojo' 和 '2 jojo',以此类推
# 用 REGEXP 关键字开头(regular expression),不区分大小写
# 和 LIKE 的重要区别:匹配整个列(LIKE),还是匹配部分列值 (REGEXP)
# . 任一字符
SELECT id FROM products WHERE name REGEXP '.000'; # 得到 JetPack 1000 和 JetPack 2000
# | 或
SELECT id FROM products WHERE name REGEXP '1000|2000'; # 得到 JetPack 1000 和 JetPack
# [123] 括号内的任一字符
SELECT id FROM products WHERE name REGEXP '[123] Ton'; # 得到 '1 Ton a' 和 '2 Ton b'
# 可以用 [0-9] 来代替 [0123456789],字母同理
# // 匹配特殊字符,如 //.
SELECT id FROM products WHERE name REGEXP '\\.'; # 得到 'Ball.'
# 也用来引用元字符,如 //f(换页)、//n(换行)等
# 匹配多个实例
SELECT id FROM products WHERE name REGEXP '\\([0-9] sticks?\\)'; # 得到'(1 sticks)'、'(9 stick)'等内容,?使得前一个字符可选(此处为 s)
# AVG:只能用于单个列(获取多个列,则需多个AVG函数),忽略列值为 NULL 的行
SELECT AVG(price) AS avg_price # 用 AS 来重命名获取的新列
FROM products WHERE id = 3;
# COUNT():不一定忽略 NULL 值
SELECT COUNT(*) FROM customers; # 不忽略 NULL 值
SELECT COUNT(name) FROM customers; # 忽略 NULL 值
# MAX()、MIN():忽略 NULL 值,允许对非数值数据使用(如文本等)
# SUM() 忽略 NULL 值
# 聚集不同值:通过 DISTINCT 实现(必须用列名)
SELECT AVG(DISTINCT price) FROM products # 忽略重复价格,计算平均值
注意 GROUP BY 和 HAVING 的作用区别噢!
SELECT id, COUNT(*) FROM products
GROUP BY id; # 通过供应商 id 分组,获取各个供应商提供的商品种类数量
SELECT id, COUNT(*) FROM products GROUP BY id
HAVING COUNT(*) >= 2; # 过滤种类小于 2 的分组
ORDER BY | GROUP BY | |
---|---|---|
作用 | 排序产生的输出 | 分组行,但输出可能不是分组的顺序 |
不一定 | 必须使用每个选择列表达式 |
一般来说子查询更好理解,联结效率更高
SELECT order_num FROM orderitems WHERE prod_id = 'TNT2'; # 得到 5、7
SELECT cust_id FROM orders WHERE order_num IN (5, 7) # 由上面查询得到的5、7继续检索
# 其实上面的两个 sql 语句,可以通过一个子查询完成
SELECT cust_id FROM orders WHERE order_num IN (
SELECT order_num FROM orderitems WHERE prod_id = 'TNT2'
);
可伸缩性:能够适应不断增加的工作量而不失败(资本家狂喜)
SELECT vend_name, prod_name, prod_price
FROM vendors, products
WHERE vendors.vend_id = products.vend_id
ORDER BY vend_name, prod_name;
# 和上面的句子效果相同,规范首选 INNER JOIN ... ON
SELECT vend_name, prod_name, prod_price
FROM vendors INNER JOIN products
ON vendors.vend_id = products.vend_id
SELECT cust_name, cust_contact
FROM customers AS c, orders AS o, orderitems AS oi
WHERE c.cust_id = o.cust_id
AND oi.order_num = o.order_num
AND prod_id = 'TNT2';
# 子查询
SELECT id, name FROM products WHERE v_id = (
SELECT v_id FROM products WHERE id = 'DTNTR'
);
# 自联结
SELECT p1.id, p1.name FROM products p1, products p2
WHERE p1.v_id = p2.v_id # 保证每行的供应商都相同
AND p2.id = 'DTNTP'
SELECT customers.cust_id, orders.order_num
FROM customers LEFT OUTER JOIN orders # OUTER 应该是可以省略的
ON customers.cust_id = orders.cust_id;
没咋用过,简单写写= =
SELECT vend_id, prod_id, prod_price
FROM products WHERE prod_price <= 5
UNION # 来了!联结起来!!
SELECT vend_id, prod_id, prod_price
FROM products WHERE vend_id IN (1001, 1002);
175. 组合两个表
SELECT FirstName, LastName, City, State
FROM Person p LEFT JOIN Address a # 因为无论 person 是否有地址信息,都要提供
ON p.PersonID = a.PersonID; # 因此使用 LEFT JOIN ON 外联结,可以包括相关表中没有关联行的行
176. 第二高的薪水
# Write your MySQL query statement below
SELECT MAX(Salary) AS SecondHighestSalary FROM Employee
WHERE Salary < (SELECT MAX(Salary) FROM Employee) # 先找最高值
181.超过经理收入的员工
# 自联结
SELECT e1.Name AS Employee
FROM Employee e1, Employee e2
WHERE e2.ID = e1.ManagerID
AND e2.Salary < e1.Salary;
182. 查找重复的电子邮箱
# 先按照 Email 分组,然后找出所有 COUNT > 1 的分组即可
SELECT Email FROM Person
GROUP BY Email Having COUNT(ID) > 1;
183. 从不订购的客户
SELECT Name AS Customers
FROM Customers c LEFT JOIN Orders o ON c.ID = o.CustomerID # 外联结,保留 NULL
WHERE o.ID IS NULL; # 通过 IS NULL 进行筛选
184. 部门工资最高的员工
# 总体思路:先找到 <部门 - 部门最多工资>,然后再进行 部门&&工资 的匹配即可
SELECT
d.name AS Department,
e.name AS Employee,
e.Salary
FROM
Employee e, Department d # 两个表之间的内联结,获取部门名
WHERE
e.departmentID = d.ID
AND
(e.salary, e.departmentID) IN # 这边需要加上部门ID,限定不同部门的 MAX_salary
(SELECT MAX(salary), departmentID FROM Employee GROUP BY DepartmentID);
# 通过部门ID进行数据分组,然后再通过 MAX 选取出分组的 MAX 值
596. 超过5名学生的课
SELECT class FROM courses
GROUP BY class # 通过 class 进行分组
Having COUNT(DISTINCT student) >= 5; # 通过 DISTINCT 进行去重
620. 有趣的电影
SELECT * FROM cinema
WHERE description != 'boring' AND id % 2 = 1
ORDER BY rating DESC; # 排序,用到 ORDER BY; 降序,用到 DESC.
结尾:
爆肝了属于是…没想到一边看一边写笔记,还是花了一天的时间才整完这篇博客= =
sql 语句得好好记得用法呀~