SQL learning¶
约 2007 个字 20 行代码 预计阅读时间 10 分钟
Abstract
推荐大家在 B站 看 GeekHour 的 SQL 速成课程,讲的很清楚。
这里是我的学习笔记。
sql(structured query language) 是一种关系型数据库语言。
- 数据定义语言
CREATE、DROP、ALTER、TRUNCATE - 数据操作语言
INSERT、UPDATE、DELETE、CALL - 数据查询语言
SELECT - 数据控制语言
GRANT、REVOKE
MySQL 中的数据类型大致可以分为五个大的类别。包括数值类型、日期和时间类型、字符串类型、json类型和空间类型。
-
数值类型分为整数类型和浮点数类型
- 整数类型根据占用的存储空间的不同分为
TINYINTSMALLINT和BIGINT分别对应1-8个字节的存储空间,可以存储不同范围的整数。 - 浮点数类型分为
FLOAT和DOUBLE分别对应4个字节和8个字节的存储空间,可以存储不同范围的浮点数。
- 整数类型根据占用的存储空间的不同分为
-
日期和时间类型包括
DATE、TIME、DATETIME和TIMESTAMP,分别对应日期、时间、日期时间和时间戳。 - 字符串类型包括
CHAR、VARCHAR、TEXT和BLOB等等,分别对应定长字符串、变长字符串、文本以及二进制数据。 - 比较新版的 MySQL 还支持 json 类型和点线空间等几何类型。
一些基本操作¶
DESC player;用于查看表的结构,DESC是describe的缩写。ALTER TABLE player MODIFY COLUMN name VARCHAR(200);用于修改表中的列。ALTER TABLE player RENAME COLUMN name TO nick_name;用于修改列名。ALTER TABLE player ADD COLUMN last_login DATETIME;用于添加列。ALTER TABLE player DROP COLUMN last_login;用于删除列。DROP TABLE player;用于删除表。
数据的增删查改¶
INSERT INTO player(id, name, level, exp, gold) VALUES(1, '张三', 1,1,1); 用于插入数据。如果表名后面的括号中包括了所有的列,并且顺序也和表结构保持一致的话,那么这个括号以及它里面的列名就都可以省略掉,直接在表名后面加上 VALUES 关键字,然后加上要插入的数据即可。也可以写上部分列的名称,这样没有写出来的列会使用建表时设置的默认值。
SELECT * FROM player; 用于查询数据。SELECT 关键字后面可以跟一个星号,表示查询所有的列。也可以跟具体的列名,表示查询指定的列。
INSERT INTO player(id, name) VALUES(2, '李四'),(3, '王五'); 用于插入多条数据。
ALTER TABLE player MODIFY LEVEL INT DEFAULT 1; 用于设置默认值。
UPDATE player SET level = 1 WHERE name = '李四'; 用于更新数据。
DELETE FROM player WHERE name = '李四'; 用于删除数据。
数据的导入导出¶
mysqldump -u root -p game player > player.sql 用于导出数据。-u 后面跟的是用户名,-p 后面跟的是密码,game 是数据库名,player 是表名,player.sql 是导出的文件名。表的名称可以省略,这样会导出整个数据库。
mysql -u root -p game < player.sql 用于导入数据。-u 后面跟的是用户名,-p 后面跟的是密码,game 是数据库名,player.sql 是导入的文件名。
常用语句¶
SELECT¶
SELECT * FROM player WHERE level > 1 AND level < 5; 用于查询 level 大于 1 并且小于 5 的数据。
优先级顺序是 () > NOT > AND > OR。
IN¶
可以用 IN 指定多个值。
SELECT * FROM player WHERE level IN (1, 2, 3); 用于查询 level 在 1、2、3 中的数据。
BETWEEN¶
可以用 BETWEEN 和 AND 指定一个范围。
SELECT * FROM player WHERE level BETWEEN 1 AND 3; 用于查询 level 在 1 到 3 之间的数据。包括 1 和 3。
NOT¶
可以用 NOT 取反。
SELECT * FROM player WHERE level NOT BETWEEN 1 AND 3; 用于查询 level 不在 1 到 3 之间的数据。
LIKE and REGEXP¶
可以用 LIKE 模糊查询。
SELECT * FROM player WHERE name LIKE '李%'; 用于查询 name 以 李 开头的数据。百分号表示任意字符,下划线表示任意一个字符。
正则表达式中的常用通配符
.匹配任意单个字符^匹配字符串的开始$匹配字符串的结束[abc]匹配括号内的任意一个字符[a-z]范围内的任意一个字符A|B匹配 A 或 B
SELECT * FROM player WHERE name REGEXP '^李.$'; 用于查询 name 以 李 开头只有两个字的数据。
正则表达式中没有 % 和 _,这是在 LIKE 中的用法。
Question
-
查找邮件地址以 zhangsan 开头的玩家。
-
查找邮件地址以 a/b/c 开头的玩家。
-
查找邮件地址以 net 结尾的玩家。
answer
SELECT * FROM player WHERE email REGEXP '^zhangsan';
SELECT * FROM player WHERE email LIKE 'zhangsan%';
SELECT * FROM player WHERE email REGEXP '^[abc];
SELECT * FROM player WHERE email REGEXP '^[a-c];
SELECT * FROM player WHERE email REGEXP 'net$';
SELECT * FROM player WHERE email LIKE '%net';
IS NULL¶
可以用 IS NULL 查询空值。
SELECT * FROM player WHERE email IS NULL; 用于查询 email 为空的数据。
不能使用 = null,因为 null 是一个特殊的值,表示未知,与其本身也不相等。
ORDER BY¶
可以用 ORDER BY 排序。
SELECT * FROM player ORDER BY level; 用于查询 level 排序的数据。默认是升序,也可以显式地加上一个 ASC。
SELECT * FROM player ORDER BY level DESC; 用于查询 level 降序的数据。
SELECT * FROM player ORDER BY level DESC, exp ASC; 用于查询 level 降序,exp 升序的数据。
SELECT * FROM player ORDER BY 5 DESC; 用于查询第 5 列(也即 level 列)排序的数据。
聚合函数 and GROUP BY¶
常用的聚合函数
AVG()平均值COUNT()计数MAX()最大值MIN()最小值SUM()求和
可以用 GROUP BY 分组。
SELECT AVG(level) FROM player; 用于查询 level 的平均值。
SELECT sex, count(*) from player group by sex; 用于查询每个性别的数量。
HAVING¶
HAVING 可以用于对分组后的结果进行过滤。
SELECT level, count(level) FROM player GROUP BY level HAVING count(level) > 10; 用于查询 level 大于 10 的数量。
SELECT level, count(level) FROM player GROUP BY level HAVING count(level) > 10 ORDER BY count(level) DESC; 用于查询 level 大于 10 的数量,并按数量降序排序。
Question
统计每个姓氏玩家的数量,并将结果按照数量来降序排列,只显示数量大于等于 5 的姓氏。
answer
LIMIT¶
可以用 LIMIT 限制返回的行数。
SELECT SUBSTR(name, 1, 1) AS surname, COUNT(surname)
FROM player
GROUP BY surname
HAVING count(surname) >= 5
ORDER BY COUNT(*) DESC
LIMIT 3, 3;
- 如果只有一个 3 那么就是返回前 3 名。
- 如果是两个,那么第一个 3 是偏移量,表示从第 4 名开始。第二个 3 是返回的数量,所以这里是返回第 4 到第 6 名。
DISTINCT¶
可以用 DISTINCT 去重。
SELECT DISTINCT name FROM player; 用于查询所有不同的名字。
UNION¶
可以用 UNION 合并两个查询结果。
UNION 会自动去重,如果不想去重可以用 UNION ALL。
UNION 和 OR 有点类似,区别在于 UNION 是用来合并两个查询结果的,也即是取两个查询结果的并集。
INTERSECT¶
可以用 INTERSECT 查询两个查询结果的交集。
SELECT * FROM player WHERE level > 10
INTERSECT
SELECT * FROM player WHERE exp BETWEEN 10000 AND 20000;
EXCEPT¶
可以用 EXCEPT 查询两个查询结果的差集。
SELECT * FROM player WHERE level > 10
EXCEPT
SELECT * FROM player WHERE exp BETWEEN 10000 AND 20000;
子查询¶
SELECT * FROM player where level > SELECT AVG(level) FROM player;
CREATE TABLE new_player SELECT * FROM player WHERE level > 10;
SELECT * FROM new_player;
INSERT INTO new_player SELECT * FROM player WHERE level BETWEEN 1 AND 5;
SELECT EXISITS(SELECT * FROM player WHERE level > 10);
不存在时返回 0,存在时返回 1。
表关联¶
内连接只返回两个表中都有的数据。
左连接就是返回左表中所有数据和右表中匹配的数据,如果没有匹配的数据,右表中的数据为 NULL。
右连接就是返回右表中所有数据和左表中匹配的数据,如果没有匹配的数据,左表中的数据为 NULL。
索引¶
索引是一种用来提高查询效率的数据结构,可以帮助我们快速定位到想要的数据。如果没有索引就只能从头开始遍历,直到找到想要的数据。
CREATE [UNIQUE|FULLTEXT|SPATIAL] INDEX idx_player_level ON player(level);
一般来说,我们会为一张表的主键字段或者经常用来查询的字段用来索引。
DROP INDEX idx_player_level ON player;
ALTER TABLE index_player ADD INDEX idx_player_level(level);
视图¶
视图是一种虚拟表,它本身不存储数据,而是作为一个查询语句保存在数据字典中。根据查询语句的定义来动态地生成数据。
CREATE VIEW top10 AS SELECT * FROM player ORDER BY level DESC LIMIT 10;
视图中的数据是动态的,会随着表的数据变化而变化。
ALTER VIEW top10 AS SELECT * FROM player ORDER BY level LIMIT 10;
DROP VIEW top10;