几个不错的在线学习+练习网站
SQL动物园https://sqlzoo.net/wiki/
SQL机器人https://sqlbolt.com/
学SQL(SQL机器人的中文版,recommended)http://xuesql.cn/
比较丰富但基础的练习题可以看,适合实践巩固:
https://www.w3resource.com/sql-exercises/
另外,leetcode也有SQL的练习题
知识小结,以MySQL为例
1.SQL基础
SQL是一种statement声明式语言,它仅仅是声明了一个你想从原始数据中获得某种样式的结果范例,而不像编程那样需要明确指示计算机如何操作
基本语法
# 创建数据库
CREATE DATABASE <数据库名>;
CREATE SCHEMA <数据库名>;
说明:CREATE SCHEMA is a synonym for CREATE DATABASE# 删除数据库
DROP DATABASE <数据库名>;# 切换数据库
USE <数据库名>;# 创建基本表
CREATE TABLE <表名>
(列名称1 数据类型,
列名称2 数据类型,
列名称3 数据类型);# 删除基本表
DROP TABLE <表名>;# 增
INSERT INTO <表名> (COL1, COL2, ...) VALUES (V1, V2, ...);# 删
DELETE FROM <表名> WHERE ...;# 改
UPDATE <表名> SET COL1=V1, COL2=V2 WHERE ...;# 查
SELECT COL1, COL2, ... FROM <表名> WHERE ...;说明:MySQL默认打开safe update mode。当safe update mode打开时,如果需要改动且存在WHERE子句,那么WHERE的筛选必须基于主键。即DELETE和UPDATE的WHERE条件必须基于主键,否则报错Error Code: 1175. You are using safe update mode and you tried to update a table without a WHERE that uses a KEY column.
关闭MySQL的safe update mode,可以通过命令SET SQL_SAFE_UPDATES = 0;
2.SQL进阶
DISTINCT
返回目标字段中不重复的值,只能在select语句中使用
SELECT DISTINCT col1, col2, ... FROM <表名> [WHERE conditions];
- DISTINCT多对单列使用;对多列操作时,表示选取多列都不重复的数据,即多列拼接成一条记录,返回不重复的记录
- DISTINCT返回的结果中不会过滤NULL,也就是可以包含NULL值
In most cases, a DISTINCT clause can be considered as a special case of GROUP BY. For example, the following two queries are equivalent:
SELECT DISTINCT c1, c2, c3 FROM t1 WHERE c1 > const; SELECT c1, c2, c3 FROM t1 WHERE c1 > const GROUP BY c1, c2, c3;
Due to this equivalence, the optimizations applicable to GROUP BY queries can be also applied to queries with a DISTINCT clause. Thus, for more details on the optimization possibilities for DISTINCT queries
JOIN ON
JOIN ON = 按笛卡尔积【A×B={(x,y)|x∈A∧y∈B}】拼接多张表. The SQL JOIN clause is used whenever we have to select data from 2 or more tables.
JOIN分为INNER JOIN / LEFT JOIN / RIGHT JOIN / FULL JOIN
直接上表说明
person表
name | age | gender |
---|---|---|
Alice | 23 | 0 |
Bob | 24 | 1 |
job表
name | job |
---|---|
Alice | Engineer |
Alice | Officer |
Clark | Manager |
下面开始JOIN
- SELECT * FROM person INNER JOIN job ON person.name = job.name
person.name | age | gender | job.name | job |
---|---|---|---|---|
Alice | 23 | 0 | Alice | Engineer |
Alice | 23 | 0 | Alice | Officer |
INNER JOIN:person表与job表满足ON条件的记录进行笛卡尔乘积
- SELECT * FROM person LEFT JOIN job ON person.name = job.name
person.name | age | gender | job.name | job |
---|---|---|---|---|
Alice | 23 | 0 | Alice | Engineer |
Alice | 23 | 0 | Alice | Officer |
Bob | 24 | 1 | NULL | NULL |
LEFT JOIN: 即使右表中没有匹配,也从左表返回所有的行
- SELECT * FROM person RIGHT JOIN job ON person.name = job.name
person.name | age | gender | job.name | job |
---|---|---|---|---|
Alice | 23 | 0 | Alice | Engineer |
Alice | 23 | 0 | Alice | Officer |
NULL | NULL | NULL | Clark | Manager |
RIGHT JOIN: 即使左表中没有匹配,也从右表返回所有的行
- SELECT * FROM person FULL JOIN job ON person.name = job.name
person.name | age | gender | job.name | job |
---|---|---|---|---|
Alice | 23 | 0 | Alice | Engineer |
Alice | 23 | 0 | Alice | Officer |
Bob | 24 | 1 | NULL | NULL |
NULL | NULL | NULL | Clark | Manager |
FULL JOIN: 返回两表的全部记录,不满足ON条件的就置NULL
SQL的执行顺序8步走——从FROM来,到ORDER BY去
在执行过程中,每个步骤都会为下一个步骤生成一个虚拟表,这个虚拟表将作为下一个执行步骤的输入FROM——加载原始表格
SQL执行顺序(来源网络)
WHERE——通过where筛选器挑出原始表中满足条件的子表,但无法与聚合函数一起使用;同时,不可使用select中的别名
GROUP BY——分组。如果应用了group by,那么只为每个组保留一行记录
HAVING——筛选分组。HAVING的出现就是为了解决WHERE无法与聚合函数一起使用的不足,几乎都与GROUP BY连用以实现记录分组+筛选出目标组。如先按国家分组,然后对每个国家计算gdp总量,筛选大于1000的:GROUP BY country HAVING SUM(gdp) > 1000
--上面4步负责获取满足各种筛选条件后的记录,更重要
--下面4步负责处理显示给人看的结果
SELECT——挑拣需要的列
DISTINCT——显示去重
UNION——合并两个或多个 SELECT 语句的结果集。注意是上下合并而不是左右拼接
ORDER BY——调整显示顺序
sql执行流程图(来源网络)
根据SQL的执行顺序,字段/表达式的别名在WHERE子句和GROUP BY子句都不能使用,因为此时别名还没有生效;而在order by中不仅可以使用别名,还可以直接使用字段的下标来进行排序,如:order by 1 desc
条件判断CASE WHEN THEN ELSE END
CASE WHEN就是编程中的if else, 在实际工作环境中,CASE WHEN的使用频率和SELECT差不多case when condition1 then result1 when condition2 then result2 ... else default end
condition是待求值的表达式,如果它的返回值是真,则返回对应result
例如:
SELECT
CASE
WHEN salary <= 500 THEN '1'
WHEN salary > 500 AND salary <= 600 THEN '2'
WHEN salary > 600 AND salary <= 800 THEN '3'
WHEN salary > 800 AND salary <= 1000 THEN '4'
ELSE NULL END salary_class, -- 别名命名
COUNT(*)
FROM Table_A;
分组排序row_number() over() or rank() over()
- row_number() over(partition by col1 order by col2)
很好理解,字面意思,按col1分组,组内按col2排序,返回行号
row_number() over()- rank() over(partition by col1 order by col2)
也很好理解,字面意思,按col1分组,组内按col2排序,返回排名 rank() over()
行号是绝对顺序的,而排名是可以并列的
查看mysql变量
show variables [like "%variable_name%"]
show variables like "%innodb_deadlock_detect%"
查看mysql当前实时状态
show status [like "%status_name%"]
网友评论