0 推荐书籍

  • 《SQL必知必会》
  • 《Mysql必知必会》
  • 《MySQL技术内幕》第2版
  • 《高性能MySQL》
  • 《MySQL技术内幕 InnoDB存储引擎》第2版
    OSQL基础看前两本书,后两本读起来挺累的。本文是对SQL语句的归纳总结。

1 MySQL增删改查

1.1 select语句

select语句编写顺序

select 
distinct   `查询列名1`,`查询列名2`  
FROM   `表名`  
join_type   JOIN   right_table  
on   join_condition  
where   where_condition  
group by   group_by_list  
having   having_condition  
order by   order_by_condition   
limit   limit_number   offset   offset_number  
  • from: 需要从哪个数据表检索数据
  • distinct: 去重
  • join:联合多表查询返回记录时,并生成一张临时表
  • on:在生成临时表时使用的条件,配合join
  • where: 过滤主表中数据的条件
  • group by: 如何将上面过滤出的数据分组
  • having: 对上面已经分组的数据进行过滤的条件,只能与group by使用
  • select: 查看结果集中的哪个列,或列的计算结果
  • order by: 按照什么样的顺序来查看返回的数据,默认从小到大,desc 逆序
  • limit:限制查询结果返回的数量
  • offset: 查询偏移量(原点),分页查询

实际上的执行顺序

FROM
ON 
JOIN 
WHERE 
GROUP BY 
HAVING 
SELECT
DISTINCT 
ORDER BY 
LIMIT

具体的可以分为如下阶段:

  1. FROM阶段
    FROM阶段标识出查询的来源表,并处理表运算符。在涉及到联接运算的查询中(各种JOIN),主要有以下几个步骤:

    • 求笛卡尔积:不论是什么类型的联接运算,首先都是执行交叉连接(CROSS JOIN),求笛卡儿积(Cartesian product),生成虚拟表VT1-J1。
    • ON 筛选器: 这个阶段对上个步骤生成的VT1-J1进行筛选,根据ON子句中出现的谓词进行筛选,让谓词取值为true的行通过了考验,插入到VT1-J2。
    • 添加外部行:如果指定了OUTER JOIN,如LEFT OUTERJOIN、RIGHT OUTER JOIN),还需要将VT1-J2中没有找到匹配的行,作为外部行添加到VT1-J2中,生成VT1-J3。如果FROM子句包含两个以上表,则对上一个连接生成的结果表VT1-J3和下一个表重复依次执行3个步骤,直到处理完所有的表为止。
      经过以上步骤,FROM阶段就完成了。
    1. WHERE 阶段
      WHERE阶段是根据 where_predicate 中条件对VT1中的行进行筛选,让条件成立的行才会插入到VT2中。此时数据还没有分组,所以不能在WHERE中出现对统计的过滤。

    2. GROUP BY 阶段
      GROUP阶段按照指定的列名列表,将VT2中的行进行分组,生成VT3。最后每个分组只有一行。在GROUP BY阶段,数据库认为两个NULL值是相等的,因此会将NULL值分到同一个分组中。

    3. HAVING 阶段
      该阶段根据HAVING子句中出现的谓词对VT3的分组进行筛选,并将符合条件的组插入到VT4中。COUNT(expr) 会返回expr不为NULL的行数,count(1)、count(*)会返回包括NULL值在内的所有数量。

    4. SELECT 阶段
      这个阶段是投影的过程,处理SELECT子句提到的元素,产生VT5。这个步骤一般按下列顺序进行:
      计算SELECT列表中的表达式,生成VT5-1。
      若有DISTINCT,则删除VT5-1中的重复行,生成VT5-2。

    5. ORDER BY 阶段
      根据ORDER BY子句中指定的列明列表,对VT5-2中的行,进行排序,生成VT6。如果不指定排序,数据并非总是按照主键顺序进行排序的。NULL被视为最小值。

    6. LIMIT 阶段
      取出指定行的记录,产生虚拟表VT7,并返回给查询用户。LIMIT n, m的效率是十分低的,一般可以通过在WHERE条件中指定范围来优化 WHERE id ? limit 10。

2流程控制语句

2.1 变量

普通变量的声明语法:
  declare 变量名 变量类型 [default 初始值]
变量的赋值语法
  set 变量名 = 变量值
mysql还有一种变量形式,可以称为“会话变量”
  会话变量的形式为: @变量名;
  会话变量无需单独声明,而是直接赋值就可以
  会话变量的赋值: set 变量名 = 值;
  会话变量可以在普通命令行环境中或编程环境中使用。

语法1:set 变量名 = 表达式; #此语法中的变量必须先使用declare声明
语法2:set @变量名 = 表达式; #此方式可以无需declare语法声明,而是直接赋值,类似php定义变量并赋值。
语法3:select @变量名 := 表达式;#此语句会给该变量赋值,同时还会作为一个select语句输出“结果集”
语法4:select 表达式 into @变量名;#此语句虽然看起来是select语句,但其实并不输出“结果集”,而只是给变量赋值

2.2 CASE WHEN语句

case when有两种,第一种等值执行,第二种类似多个if判断语句

CASE value 
    WHEN [compare-value] THEN result 
    [WHEN [compare-value] THEN result ...] 
    [ELSE result] 
    END
CASE WHEN [condition] THEN result 
     [WHEN [condition] THEN result ...]
     [ELSE result] 
     END 
  • 特点1:
    可以作为表达式,嵌套其他语句使用,放在begin end内外都可以
    可以作为单独语句使用,只能放在begin end中
  • 特点2:
    如果when的值满足,则执行then后面的语句,并结束case
    都不满足,则执行else中的值或语句
  • 特点3:
    else可以省略,若else省略,且所有when都不满足,则返回null

2.3 IF语句

  • IF 流程
IF condition THEN
    ...
ELSE condition THEN
    ...
ELSE
    ...
END IF

与编程语言语义相同

  • IF 表达式
IF(expr1, expr2, expr3) 

如果 expr1 为 true (不为 0 和 NULL),则 IF() 的返回值为 expr2;否则,返回值为 expr3

  • IFNULL 表达式
IFNULL(expr1, expr2) 

如果 expr1 为 NULL,则 IFNULL() 的返回值为 expr2;否则其返回值为 expr1

  • NULLIF 表达式
NULLIF(expr1, expr2) 

如果 expr1 等于 expr2 成立,那么返回值为 NULL ;否则,返回值为 expr1