noSql数据库满天飞的情况下,安下心来让SQL尘埃落定吧。(出来混总要还的😌)
《SQL必知必会》读书笔记,Ben Forta著。
了解SQL
Structured Query Language 结构化查询语言
基础语法
| 表示 在可选项中选择一个
[ ] 表示这个参数可选
- ALTER TABLE
更新 已存在 表 的 结构
1 | ALTER TABLE table |
- COMMIT
将 事务 写入 数据库。
1 | COMMIT [TRANSACTION]; |
- CREATE INDEX
在 一个或多个 列 上 创建 索引。
1 | CREATE INDEX i ndexname |
- CREATE PROCEDURE
创建存储过程。 Oracle 使用的语法稍有不同。
1 | CREATE PROCEDURE procedurename [parameters] [options] |
- CREATE TABLE
创建 新数据库表。
1 | CREATE TABLE tablename |
- CREATE VIEW
用来创建 一个或多个 表上的新视图。
1 | CREATE VIEW viewname AS |
- DELETE
从表中 删除 一行或多行。
1 | DELETE FROM tablename |
- DROP
永久地删除数据厍对象
1 | DROP INDEX | PROCEDURE | TABLE | VIEW |
- INSERT
为表添加一行。
1 | INSERT INTO tablename [(co1umns, ...)] |
- INSERT SELECT
将SELECT的结果插人到一个表
1 | INSERT INTO tablename [ (columns,)] |
- ROLLBACK
用于撤销-一个事务块。
1 | ROLLBACK [TO savepointname]; |
- SELECT
用于从一个或多个表(视图)中检索数据。
1 | SELECT columnname ,... |
- UPDATE
更新表中的一行或多行。
1 | UPDATE tablename |
数据类型
字符串
- CHAR
- 1-255个字符的定长字符串。长度必须在创建时规定。
- NCHAR
- CHAR的特殊形式。用来支持多字节或Unicode字符。
- TEXT (也称 LONG\MEMO\VARCHAR)
- 变长文本
- NVARCHAR
- TEXT的特殊形式。
数值
- BTT 单个二进制位
- DECIMAL 定点、或浮点可变的浮点值
- FLOAT 浮点值
- INT 4字节整数
- REAL 4字节浮点
- SMALLINT 2字节整数
- TINYINT 1字节,0-255的整数
多数DMBS支持货币数据类型
MONEY/CURRENCY
有特定取值范围的DECIMAL类型。更适合存货币值
日期时间
- DATE 日期
- DATETIME 日期时间
- SMALLDATETIME 日期时间精确到分
- TIME 时间
检索数据
- SELECT *
*
选择所有 - SELECT DISTINCT name
DISTINCT
结果去重
限制结果
返回前5行
MySQL PostgreSQL SQLite MariaDB
SELECT xxx FROM xxx LIMIT 5;进阶:LIMIT 后跟两个参数
1
LIMIT 10,2 -- 从第10个往后输出2个。输出的是 11 和 12
注释
1 | # 可以这样 |
排序检索数据
1 | SELECT id,name,grade |
重要:应保证 ORDER BY 子句是 SELECT 语句中的 最后一个 子句 ,否则会报错!
排序方向:
默认升序[A~Z] ,改降序:
1 | ORDER BY grade DESC |
过滤数据
WHERE 子句操作符:
= 等于 | > 大于 | >= 或 !< 大于等于 | BEWTEEN AND在指定值之间 |
---|---|---|---|
<> 或 != 不等于 | < <= | <= 或 !> 小于等于 | IS NULL 为NULL |
高级过滤
组合WHERE子句
用AND或OR组合子句
AND和OR的顺序
AND级别比OR高。 如果需要改变顺序,请加括号:
1 | WHERE (name = 'XiaoMing' OR name = 'XiaoHong') |
IN操作符
1 | WHERE id IN ('001','002'); |
IN的优点:
简单直观。比OR更快。
可以包含其他SELECT子句后面会介绍。
NOT 操作符
否定后面的条件。不单独使用。
1 | WHERE NOT id = '01' |
那为啥还要用NOT呢?
在复杂的条件中,可以迅速找出 不符合 条件的
通配符过滤
使用谓词 LIKE
- %通配符
表示任意字符出现任意次
1 | WHERE name LIKE 'Xiao%' |
%可以匹配 0 个 1 个 多个字符(包括空格)。当然 ,并不会匹配NULL值
- _通配符
_只匹配一个字符
- []通配符
匹配字符集(仅SQL Server支持)从[ ]
里取一个字符
1 | WHERE name LIKE 'Xiao[MH]' -- 匹配XiaoM和XiaoH |
通配符技巧
- 不要过度使用通配符。有其他操作符能达到目的应优先考虑其他。
- 通配符置于开始处,搜索起来是最慢的
SELECT name + ‘(‘ + classId + ‘)’拼接字段
就是合并列
1 | #在SQL Server中 用 + |
TRIM 函数 去某个字段的空格
LTRIM() 去掉字符左边的空格 RTRIM()右边 TRIM()两边
使用别名
拼接之后 AS newName 给新的字段用别名
算数计算
1 | SELECT quantity, price, quantity*price AS Pay |
函数
不同的sql还不一样名。不怎么通用。 P65 Mark
汇总数据
聚集函数
AVG() 返回列的平均值
COUNT()返回列的行数
- COUNT(columnName) 对特定的列计数,忽略NULL值
- COUNT( * ) 表中的行数计数。不论是不是NIULL都计数。
MAX() MIN()
SUM() 列值之和
1
SELECT AVG(price) AS avg_price FROM xxx; --返回平均价格
DISTINCT去重
1 | SELECT AVG(DISTINCT price) AS avg_price |
分组
GROPU BY和HAVING
不用GROUP BY
1 | SELECT SUM(grade) AS 小明的总分 FROM Stu |
但这时候如果还想看小红,还想看小亮的总分,总不能挨个都写到WHERE里。
GROUP BY
1 | SELECT nmae, SUM(grade) AS 总分 FROM Stu |
- GROUP BY必须出现于WHERE之后 ORDER BY之前
- NULL也会被分成一组
过滤分组
WHERE过滤的只是行,看上去像是分组了。
如果想排除分组怎么办?(比如不看小丽的总分)
HAVING,支持所有WHERE操作符。语法相同。
差别:
WHERE在分组前进行过滤,过滤掉的行不参与分组。
HAVING再对分组后的结果过滤
子查询
IN(SELECT)
用 IN 操作符 嵌套 SECLECT 查询
1 | SELECT name FROM Stu |
- 作为子查询的SELECT子句只能是单列
- 多次嵌套会影响效率
作为计算字段
当做返回值
1 | SELECT name, ( |
完全限定列名
两个表里都已id字段,要加前缀的
后面学习的JOIN代替上面的方法更有效
联结表
笛卡尔积
WHERE条件子句不写,直接
1 | SELECT id,name,grade |
内联结 等值联结
1 | SELECT id, name, grade |
等价于
1 | SELECT id, name, grade |
只不过关键词 WHERE 换成 ON
ANSI SQL规范首选 INNER JOIN 语法
第二种写法是很Low的哦
但第二种写法还可以联结多个表,当然性能会下降
高级联结
表的别名
使用AS ,注意,也可以在FROM之前的SELECT中使用哦
1 | SELECT A.*, B.name |
除了内联结(等值联结) 还有三种其他联结
自联结
假如查询和小明考了一样分数的同学们的名字,用嵌套查询的方式可以这样:
1 | SELECT name FROM Grade |
用自联结就可以这样:
1 | SELECT name |
一般情况下使用[[联结]]比使用[[子查询]]快得多。
当然也可以试用两种方法,以确定哪种性能更好
自然联结
排除多次出现。每一列只返回一次。
一般通过对一个表使用通配符(SELECT *),对其他表使用 明确的 子集来完成。
比如查询同学的成绩。学号的那张表肯定是唯一的,就可以
1 | SELECT S.* , xxxxxx |
外联结
左外联结和右外联结,
有时候 表1 和 表2 联结,并不能出现一一对应的情况,这时候以表一的数据为准,【表一中有,表二中没有的】 联结之后填充NULL值。就是左外联结。 关键词是
1 | FROM tab1 LEFT OUTER JOIN tab2 |
右外联结 就是 RIGHT OUTER JOIN
全外联结
FULL OUTER JOIN
带上左右不关联的行全部返回。但是 MySQL SQLite MariaDB等不支持 FULL OUTER JOIN 的 语法
组合查询
用 UNION 联结两条 SELECT
1 | SELECT name,id FROM xxx |
上面的例子当然可以用 WHERE 配合 OR 来组合条件完成,
但是当遇到复杂的过滤条件, UNION 处理起来更简单。
性能上的差别,最好是测试以确定更优。
- Note:列的数据类型必须完全兼容。上面我给的例子是完全相同的两个列,实际上,只要类型兼容即可(即 必须是DBMS可以隐含转换的类型)。
重复的行
UNOIN 默认会去除重复行。(看上去效果和使用了多个WHERE子句一样)
如果想返回所有行。请使用 UNOIN ALL
关键词。实现合并两个集合而不去重。这样可以解决【用WHERE会去重】的问题。
其他UNION
既然有并集。就还有 差集:
EXCEPT
交集:INTERSECT
但实际上他们很少使用,因为可以用 联结 来得到结果
插入数据
学了这么久,查插删改一直在查,终于到了插了:
- 插入完整的行
- 插入行的一部分
- 插入查询的结果
插入完整的行
1 | INSERT INTO tab1 |
但是这种方法不安全。完全依赖列的顺序插入。表的结构变动后,迟早会出问题。更安全(麻烦)的方法:
1 | INSERT INTO tab1(id,name,math,english,PE) |
插入部分行
就是说列名可以不写全。但必须满足以下某个条件:
- 该列定义 允许 NULL值
- 表定义中给出了默认值
插入检索的数据
1 | INSERT INTO tab1(xxx,xxx,xxx) |
其中INSERT 和 SELECT 的列名不要求匹配。插入只看位置。
从一张表复制到另一张表
1 | SELECT * |
如果只是复制部分列,把 * 换成 列名
MySQL Oracle PostgreSQL SQLite语法不同:
1 | CREATE TABLE tabCopy AS |
删改
更新数据
1 | UPDATE Stu |
更新总是要以 要更新的 表名 开始。
会以 WHERE 子句结束,它告诉DBMS要更新哪一行。
没有WHERE子句会更新所有行 这不是我们所希望的
删除数据
1 | DELETE FROM Stu |
DELETE删除的是【行】。一定要带上WHERE,不然就删了所有的行。
如果想删除所有行,请使用 TRUNCATE TABLE ,它完成相同的工作速度 更快。
操作表
创建表
1 | CREATE TABLE Stu |
附录D展示了常见的数据类型
上述代码在MySQL上varchar
必须替换为text
不指定NOT NULL
, 则可以为空(NULL
)
默认值(DEFAULT
)比Null更好用,常用于日期和时间戳,如在MySQL上获取时间:CURRENT_DATE()
更新表
应在设计表的时候考虑未来可能的需求
1 | ALTER TABLE Stu |
增删了一列
ALTER表前要备份。如果增加了,也许无法删除。如果删除了,也许无法恢复
删除表
1 | DROP TABLE Stu |
删除表没有确认也不能撤销。
如果该表是某个关系的组成成分,DBMS将阻止这条语句。这能防止意外删除。
重命名表
根据DBMS有所不同
使用视图
常见的数据类型
附录D
1.字符串
Q:定长和变长区别
A: 性能。处理定长比处理变长快得多;许多DBMS不允许变长列进行索引
类型 | 说明 |
---|---|
CHAR | 1~255的定长字符串 长度必须在创建时规定 |
NCHAR | CHAR的特殊形式 用来支持多字节或Unicode字符(此类型的不同实现变化很大) |
TEXT (也称为LONG、MEMO或VARCHAR) |
变长文本 |
NVARCHAR | TEXT的特殊形式 用来支持多字节或Unicode字符(此类型的不同实现变化很大) |
Notice:字符串的值 必须在 单引号内
Note: 「不是数值的数字」要保存成字符串,如邮编01234如果保存成数值是1234,丢失一位。应作为字符串保存。
2.数值
类型 | 说明 |
---|---|
BIT | 0/1 |
DECIMAL | 定点或精度可变的浮点数 |
FLOAT | 浮点数 |
INT | 4字节整数 -2147483648~2147483647 |
REAL | 4字节浮点数 |
SMALLINT | 2字节整数 -32768~32767 |
TINYINT | 1字节整数 0~255 |
多数DBMS支持 MONEY或CURRENCY,更适合存储货币的,有特定范围的DECIMAL
3.日期和时间
类型 | 说明 |
---|---|
DATE | 日期 |
TIME | 时间 |
DATETIME | 日期时间 |
SMALLDATETIME | 日期时间,精确到分(无秒、毫秒) |
NOTE: 不同的DBMS格式要参考具体文档
4.二进制
包含任何数据(图、多媒体、文档) 最不具兼容性
类型 | 说明 |
---|---|
BINARY | 定长二进制 255B~8000B |
VARBINARY | 变长二进制 255B~8000B |
RAW | 定长二进制 最长255B |
LONG RAW | 变长二进制 最长2GB |