SQL
SQL语言具有两种使用方式,分别为
- 交互式SQL:在终端交互方式下使用
- 嵌入式SQL:嵌入在高级语言的程序中使用;这些高级语言可以是C语言、PASCAL、COBOL等,被称为宿主语言
交互式SQL
MySQL
MySQLMS SQL Server
SQL ServerACCESS
Post not found: ACCESS嵌入式SQL
嵌入C语言程序
- SQL 与 C 语言处理记录的方式是不同的。当将 SQL 语句嵌入到 C 语言程序时,为协调两者而引入游标(题目来源)
SQL标准
- SQL92标准定义的最严格事务级别是:Serializable(可串行化)
SQL语言
SQL有四种语言(也有的说法将TCL考虑为第五种):
- DDL 数据定义语言
- DQL 数据查询语言
- DML 数据库操纵语言
- DCL 数据库控制语言
- TCL 事务控制语言
详情请见《SQL语言类型》
相关书籍
数据设计
- 在关系数据库设计中,关系模式是用来记录用户数据的二维表
概念结构设计
数据设计中的E-R模型设计是概念结构设计阶段的主要工作之一
- 数据库的概念独立于具体的机器和DBMS
E-R方法
实体-联系方法(E-R,Entity-Relationship Approach),是描述现实世界概念结构模型的有效方法。
- 矩形:实体型
- 椭圆:实体的属性
- 菱形:实体型之间的联系
逻辑结构设计
- 在数据库设计中,将ER图转换为关系数据模型的过程属于逻辑设计阶段
物理结构设计
键(码)
数据库中的键(key)也可以称为码,是关系模型中的一个重要概念,它是逻辑结构,不是数据库的物理部分。
- 候选键(码):如果关系中的某一属性组的值能唯一地标识一个元组,则称该属性组为候选码
- 主键(码):如果一个关系有多个候选码,则选定其中一个为主码
- 主属性:候选码的诸属性
- 非主属性:不包含在任何候选码中的属性
超键(码)
能唯一标识元组的属性集中的其中一个属性可以作为一个超键,多个属性组合也可以作为一个超键(Super Key)。
- 在关系中能唯一标识元组的属性集称为关系模式的超键
候选键(码)
候选键(码)(Candidate Key)有2个要求:
- 始终能够唯一地标识一个元组
- 在属性集中找不出真子集能够满足条件
- 可以将“候选键(码)”理解为不能再“缩小”的超键(不含有多余属性的超键)
主键(码)
如果一个关系有多个候选键(码),则选定其中一个为主键(码)(Primary Key)
- 在关系模式中,对应关系的主键必须是能唯一确定元组的一组属性
- 主键是唯一、不为空值的列
外键(码)
- 在一个关系A中,有一个属性b不是关系A的主键(码)或候选键(码),但是是另一个关系B的主键,则关系A中的属性b是关系A中的外键(码)
- 在SQL语言中使用
FOREIGN KEY
时,与之配合的语句是REFERENCES
全键(码)
- 是候选键(码)的一种特殊情况
- 如果关系中只有一个候选键(码),且这个候选键(码)中包含了全部属性,那么称这个候选码为全键(码)
事务
详情请见《SQL事务》
特性
数据库事务的四大特性(简称ACID):
- 原子性(Atomicity)
- 一致性(Consistency)
- 隔离性(Isolation)
- 持久性(Durability)
事务隔离级别
- Read Uncommitted(未提交读)
- Read Committed(提交读)
- Repeatable Read(可重复读)
- Serializable(可串行化)
- 隔离级别依次增加
- 并发性能依次降低
- 随着隔离级别的增高,并发性能降低
视图
- 在视图上能够完成的操作:
- 更新视图
- 查询
- 在视图上定义新的视图
- 在视图上不能完成的操作是:在视图上定义新的表
数据类型
通用
COALESCE()
COALESCE(expression1, expression2, expression3, ...)
:接收一系列表达式或列,返回第一个非空的值。
- 如果都是空值(NULL),则会报错
CREATE
CREATE FUNCTION
编写函数:
1 | -- 某电器商品海关进口税征收办法,起征点为500元,超出部分按以下2级计算: |
DATEDIFF()
DATEDIFF(string enddate, string startdate)
:返回结束日期减去开始日期的天数
- 返回值:
int
1 | -- 计算0701-0715的区间三日留存率 |
1 | -- 计算次日、2日、3日留存率 |
DATE_FORMAT()
以不同的格式显示日期/时间数据
1 | -- 当月的第一天 |
DELETE
删除表中数据:DELETE TABLE table_name
- TRUNCATE也是删除表中数据的语句
TRUNCATE
比DELETE
的速度快TRUNCATE
是删除表的所有行;而DELETE
是删除表的一行或多行(除非没有WHERE
子句)- 在删除时,如果遇到任何一行违反约束(主要是外键约束),则
TRUNCATE
仍然删除表中数据,但是表的结构、列、约束、索引等保持不变,而DELETE
直接返回错误 - 对于被外键约束的表,不能使用
TRUNCATE
,而应该使用不带WHERE
子句的DELETE
- 如果想保留标识计数值,要用
DELETE
;因为TRUNCATE
会对新行标识所用的计数值重置为该列的种子
DROP
删除表:DROP TABLE table_name
grouping sets
分组集(Grouping Sets)是多个分组的并集,用于在一个查询中,按照不同的分组列对集合进行聚合运算,等价于对单个分组使用“union all”,计算多个结果集的并集。
- 在单个分组中缺失的分组列,返回
null
1 | select a |
IIF()
IIF(boolean_expression, valueForTrue, valueForFalse)
:如果boolean_expression
为真,则返回valueForTrue
;否则返回valueForFalse
。
INTO
ISNULL()
ISNULL(expression1, expression2)
:如果第一个参数为NULL
,则返回第二个参数expression2;否则,返回第一个参数expression1。等价于CASE WHEN expression1 IS NULL THEN expression2 ELSE expression1 END
。
LAG()
滞后若干项
1 | -- 表login_log记录用户的登录行为:uid(用户id)、login_date(登陆日期) |
last_day()
取某月的最后一天
1 | select last_day('2020-11-06'); |
locate()
LOCATE(substr, str)
:返回字符串str第一次出现子串substr的位置。
- 如果substr不在str中,则返回0
LOCATE(substr, str, pos)
:返回第一次出现在字符串str的子串substr的位置,从位置pos开始。
- 如果substr不在str中,则返回0
MAX()
1 | -- 用户最近登录的日期 |
MIN
- 题源:
1 | -- 新登录用户的次日登录成功的留存率 |
NULLIF()
NULLIF(expression1, expression2)
:如果两个参数相等,则返回NULL
;否则,返回第一个参数。等价于CASE WHEN expression1 = expression2 THEN NULL ELSE expression1 END
。
- 可用于防止分母中出现0而报错
1 | a/NULLIF(b, 0) |
ORDER BY
- 用于排序
- 默认升序
ASC
;降序需要在列名后加DESC
- 对带有排序作用的
ORDER BY
子句的查询,ORDER BY
返回的是一个对象,其中的行按特定的顺序组织在一起,这种对象被称为游标 ORDER BY
子句是唯一能重用列别名的子句- 这是因为
ORDER BY
子句是在SELECT
子句之后才执行的
1
2
3
4
5
6
7
8
9(8)SELECT (9)DISTINCT (11) <TOP num><SELECT list>
(1)FROM [left_table]
(3)<JOIN_type> JOIN <right_table>
(2)ON <join_condition>
(4)WHERE <where_condition>
(5)GROUP BY <group_by_list>
(6)WITH <CUBE | ROLLUP>
(7)HAVING <having_condition>
(10)ORDER BY <order_by_list>;- 这是因为
- 谨慎使用
ORDER BY
后面接数字的方式来进行排序,尽量使用ORDER BY+列名
或ORDER BY+列别名
1
2
3
4
5
6
7
8SELECT
col_a,
col_b,
col_c
FROM table_1
ORDER BY 1, 2, 3;
-- 实际按照SELECT后的字段顺序col_a, col_b, col_c进行排序
-- 当查询的列发生改变时,而忘了修改ORDER BY后的数字时,可能会获得错误的查询结果 - 表表达式不能使用
ORDER BY
进行排序- 表表达式包括:
- 视图(VIEW)
- 内联表值函数
- 派生表(子查询)
- 公用表表达式(CTE)
- 表表达式加了
TOP
可以使用ORDER BY
1
2
3
4
5
6
7
8
9
10SELECT
col_a
, col_b
FROM
(
SELECT TOP 5 *
FROM table_1
ORDER BY col_c
) AS t1 -- 实际返回的是没有固定顺序的表
ORDER BY col_a, col_b DESC; - 表表达式包括:
REGEXP_REPLACE()
正则替换
1 | -- 如何统计表tbl的字段comments中出现了多少次“何时下班”? |
ROW_NUMBER()
1 | -- 给定表table_a(包含user_id, login_date),计算连续3天登录的用户id |
1 | -- 给定表table_a(包含user_id, login_date),计算最近30天内,曾连续3天登录的用户数 |
1 | -- 表login_log记录用户每天的登陆情况:uid(用户id)、date_dy(日期)、is_login(用户是否登陆,1表示当天有登陆,0表示当天未登陆) |
1 | -- 连续四天看相同类别的视频的用户id及视频id |
SUM
求和
- 聚合函数之一
1 | -- 求累计薪资和 |
题源:
1 | -- 统计每天的新用户 |