SQL 学习

SQL 学习

  • 1. 概念
    • 1.1 数据库基本概念
    • 1.2 SQL 概述
  • 2. 查询
    • 2.1 SELECT 语句基本结构
    • 2.2 基本查询
    • 2.3 别名的使用
    • 2.4 删除查询结果中的重复数据
    • 2.5 限制查询结果
    • 2.6 连接列值
    • 2.7 查询中使用计算列
    • 2.8 查询中使用表达式
    • 2.9 条件查询-WHERE
    • 2.10 范围查询-BETWEEN
    • 2.11 日期查询
    • 2.12 过滤数据
    • 2.13 格式化结果集
      • 2.13.1 格式化日期
      • 2.13.2 数据表的数值类型转换--CAST()
      • 2.13.3 去掉空格--LTRIM()
    • 2.14 模糊查询--LIKE
    • 2.15 行数据过滤
      • 2.15.1 行查询
      • 2.15.2 空值判断
    • 2.16 数据排序
      • 2.16.1 数值排序
      • 2.16.2 汉字排序--COLLATE Chinese_PRC_
    • 2.17 数据统计分析
    • 2.18 分组统计
      • 2.18.1 创建分组
      • 2.18.2 使用 ROLLUP 关键字
      • 2.18.3 使用 CUBE 关键字
      • 2.18.4 使用 HAVING 子句进行过滤分组
      • 2.18.5 SELECT 子句的顺序
    • 2.19 子查询
      • 2.19.1 简单子查询
      • 2.19.2 多行子查询
    • 2.20 多表连接
      • 2.20.1 内连接
      • 2.20.2 外连接
      • 2.20.3 其他连接
      • 2.20.4 组合查询--UNION
  • 3. 插入数据--INSERT
    • 3.1 插入单行数据
    • 3.2 插入多行数据
    • 3.3 表中数据的复制
  • 4. 更新删除数据
    • 4.1 更新修改--UPDATE
    • 4.2 删除数据-DELETE
  • 5. 使用视图
    • 5.1 视图的优点
    • 5.2 创建视图
    • 5.3 删除视图
    • 5.4 视图的应用
  • 6. 使用存储过程
    • 6.1 存储过程概述
    • 6.2 SQL Server 存储过程:
    • 6.3 Oracle 创建存储过程
    • 6.4 MySQL 创建存储过程
  • 7. 使用游标
    • 7.1 声明游标
    • 7.2 打开游标
    • 7.3 读取游标中的数据
    • 7.4 关闭并释放游标
  • 8. 事务处理
    • 8.1 事务概述
    • 8.2 显式事务
    • 8.3 隐式事务
    • 8.4 事务操作
  • 9. 数据库管理
    • 9.1 创建数据库
    • 9.2 修改数据库
    • 9.3 删除数据库
  • 10. 数据表管理
    • 10.1 创建数据表
    • 10.2 查看数据表
    • 10.3 修改数据表
    • 10.4 删除数据表

1. 概念

1.1 数据库基本概念

  • 数据(Data):描述事物的符号记录
  • 数据库(DataBase, a.k.a DB):存放数据的仓库
  • 数据库管理系统(DataBase Management System, a.k.a DBMS):科学地组织和存储数据,高效地获取和维护数据。如 SQL Sever, Oracle, MySQL 等。
  • 数据库系统(DataBase System, a.k.a DBS):在计算机系统中引入数据库后的系统

1.2 SQL 概述

  • SQL 全称为 Structured Query Language,即结构化查询语言。功能包括数据查询、数据操纵、数据定义和数据控制四个部分。
  • 数据定义语言(Data Definition Language, a.k.a DDL):允许用户定义存储数据的结构和组织,以及存储数据项之间的关系
  • 数据检索语言:允许用户或应用程序从数据库中检索存储的数据并使用
  • 数据操纵语言(Data Manipulation Language, a.k.a DML):允许用户或应用程序通过增、删、改来对数据库进行更新
  • 数据控制语言(Data Control Language, a.k.a DCL):可以使用 SQL 语言来限制用户检索、添加和修改数据的能力,保护存储的数据不被未授权的用户所访问
  • 数据共享:可以使用 SQL 来协调多个并发用户共享数据,确保他们不会互相干扰
  • 数据完整性:SQL 语言在数据库中定义完整性约束条件,使它不会因不一致的更新或系统失败而遭到破坏

2. 查询

2.1 SELECT 语句基本结构

  • SELECT 语句可以从数据表中或视图中进行查询,并将查询结果以表格的形式返回,称为结果集
  • SELECT 的主要结构如下
SELECT select_list    # 指定要查询的列,* 代表所有列
[INTO new_table]    # 创建新表并将查询行插入新表中
FROM table_name    # 指定要查询的表,可能包括基表,视图和链接表
[WHERE search_condition]    # 搜索条件,无法使用聚合函数
[GROUP BY group_by_expression]    # 根据 group_by_expression 列中的值将结果集分组
[HAVING search_condition]    # 指定组或聚合的搜索条件。通常用于处理 GROUP BY 之后的数据
[ORDER BY order_expression [ASC | DESC]];    # 定义结果集中的行排列的顺序,默认为 ASC 升序

2.2 基本查询

  1. 单列
SELECT select_list FROM table_name;
  1. 多列
SELECT list1, ..., listn FROM table_name;
  1. 所有列
SELECT * FROM table_name;

2.3 别名的使用

  1. 使用方法
SELECT list "别名" FROM table_name;
SELECT list '别名' FROM table_name;
SELECT list 别名 FROM table_name;
SELECT list AS "别名" FROM table_name;
# 别名中有空格时必须使用引号
  1. 使用场景
  • 字段为英文或缩写时,增强可阅读性
SELECT list_name AS "名称" FROM table;
  • 区分多个表查询时出现的相同列名
SELECT table1.list AS "表一的列", table2.list AS "表二的列" 
FROM table1, table2 
WHERE table1.id = table2.id;
  • 为计算结果设置别名列
SELECT list1 AS "A", list2 AS "B", (list1 - list2) AS "DIFF" FROM table;
  • 为使用聚合函数的列设置别名
SELECT MAX(list1) AS "MAX", MIN(list2) AS "MIN" FROM table;

2.4 删除查询结果中的重复数据

SELECT [DISTINCT | ALL] list FROM table;    # DISTINCT 只能使用一次且必须放在第一位

2.5 限制查询结果

  1. SQL Server:
SELECT TOP n list FROM table;    # 查询前 n 行,n 介于 0 ~ 4294967295
  1. MySQL:
SELECT list FROM table LIMIT n;    # 查询前 n 行
SELECT list FROM table LIMIT m, n;    # 从第 m 行开始的 n 条数据信息(m 从 0 开始计算)
SELECT list FROM table LIMIT n OFFSET m;    # 从第 m 行开始的 n 条数据信息(m 从 0 开始计算)
  1. Oracle:
SELECT list FROM table WHERE ROWNUM <= n;    # 前 n 行数据

2.6 连接列值

  • 将多个列中的数据合并到一列,需指定列名,否则为空
SELECT list1 + list2 AS "NAME" FROM table;

2.7 查询中使用计算列

SELECT (list_a * list_b - list_c) / list_d AS "NAME" FROM table;

2.8 查询中使用表达式

  1. 数值表达式
SELECT list + 50 AS 加50 FROM table;
  1. 字符表达式
SELECT convert(char(2), list) + '个' AS NAME;
  1. 使用表达式创建新列
SELECT 1+1 AS NAME1, "字符"+"串列" AS NAME2

2.9 条件查询-WHERE

  1. 基本语法结构
SELECT list FROM table WHERE condition
  1. 常用比较运算符:=, >, <, >=, <=, !>, !<, <>, !=

2.10 范围查询-BETWEEN

  1. 查询两个数或日期之间的数据,包括 m 和 n
SELECT list1 FROM table WHERE list2 BETWEEN m AND n   
  1. 查询不在两个数或日期之间的数据
SELECT list1 FROM table WHERE list2 NOT BETWEEN m AND n

2.11 日期查询

  1. GETDATE(), DATEADD()
SELECT list1 FROM table WHERE list2 
BETWEEN
DATEADD(DAY, -1, GETDATE())    # DATEADD 在这里为减1天
AND
GETDATE()    # 获得当前日期
  1. 计算两个日期的间隔天数
# **SQL Server**
DATEDIFF(datepart, startdate, enddate)
# datepart 为计算哪部分的时间间隔,如 year, month, day 等
# startdate enddate 分别为开始和终止日期
# **MySQL 中** 也可用 DATADIFF 函数,只计算天数
DATEDIFF(stardate, enddate)
  1. 按指定日期查询数据
DAY()
MONTH()
YEAR()

2.12 过滤数据

  • 逻辑运算符:优先级 NOT > AND > OR
  • IN 操作符
SELECT list1 FROM table WHERE list2 IN (v1, v2, ...)
SELECT list1 FROM table WHERE n IN (col1, col2)    # n 在 col1 列或 col2 列的行
SELECT list1 FROM table WHERE list2 NOT IN(v1, v2, ...)

2.13 格式化结果集

2.13.1 格式化日期

  1. SQL Server
CONVERT(date_type[(length)], expression [, style])
# date_type 为目标数据类型(可选长度)
# expression 为 DATETIME 类型的数据
# style 指定转换形式,例如 120 或者 20 为 yyyy-mm-dd hh:mi:ss
  • style 参数可选值
可选值 输出格式
100 or 0 mon dd yyyy hh:miAM(or PM)
101 mm/dd/yy
102 yy.mm.dd
103 dd/mm/yy
104 dd.mm.yy
105 dd-mm-yy
106 dd mm yy
107 mm dd,yy
108 hh:mm:ss
109 or 9 mon dd yyyy hh:mi:ss:mmmAM(or PM)
110 mm-dd-yy
111 yy/mm/dd
112 yymmdd
113 or 13 dd mon yyyy hh:mi:ss:mmm(24h)
114 hh:mi:ss:mmm(24h)
120 or 20 yyyy-mm-dd hh:mi:ss(24h)
121 or 21 yyyy-mm-dd hh:mi:ss.mmm(24h)
126 yyyy-mm-ddThh:mi:ss.mmm(不含空格)
130 dd mom yyyy hh:mi:ss:mmmAM(or PM)
131 dd/mm/yy hh:mi:ss:mmmAM(or PM)
  1. MySQL
DATE_FORMAT(date, format)
# date: 一个合法的日期
# format: 规定日期/时间的输出格式
  • format 参数:
格式 说明
%a 简写的英文星期
%b 简写的英文月份
%c 数值表示的月份
%D 表示带有英文后缀的月中的第几天
%d 月中第几天(00~31)
%e 月中第几天(0~31)
%f 微秒数
%H 小时数(00~23)
%h 小时数(01~12)
%I 小时数(01~12)
%i 分钟数(00~59)
%j 年中的第几天(001~366)
%k 小时 (0-23)
%l 小时 (1-12)
%M 月名
%m 月,数值(00-12)
%p AM 或 PM
%r 时间,12-小时(hh:mm:ss AM 或 PM)
%S 秒(00-59)
%s 秒(00-59)
%T 时间, 24-小时 (hh:mm:ss)
%U 周 (00-53) 星期日是一周的第一天
%u 周 (00-53) 星期一是一周的第一天
%W 完整的英文日期
%w 周的天 (0=星期日, 6=星期六)
%Y 年,4 位
%y 年,2 位
  1. Oracle
TO_CHAR(expression, format)
格式 说明
YYYY 年, 4位
YYY 年,后三位
YY 年,后两位
Y 年,最后一位
YEAR 英文表示的年份
MONTH 文字表示的月份
MM 数字表示的月份
DAY 星期名
DDD 年中第几天
DD 月中第几天
D 一周第几天 1~7,1为星期日
DY 星期名缩写
WW 年中第几周
W 月中第几周
HH 12 小时 的小时
HH24 24 小时的小时
MI 分钟数
SS 秒数
AM|PM(A.M.|P.M.) 上午或下午

2.13.2 数据表的数值类型转换–CAST()

CAST(expression AS data_type)
# expression: 任何有效的 SQL Sever 表达式
# data_type: 目标类型,必须是系统所提供的数据类型
# 将浮点型转换为整型时,小数部分会舍去而不会进行四舍五入
# 将字符串转换为 decimal 类型时,需要指定精度(总位数)和小数位数,此时小数部分为四舍五入

2.13.3 去掉空格–LTRIM()

LTRIM(character_expression)

2.14 模糊查询–LIKE

  1. 通配符及其含义
通配符 说明
% 由0个或多个字符组成的任意字符串
_ 任意单个字符
[] 用于指定范围,和正则表达式中类似
[^] 用于表示指定范围外的
  1. LIKE 语句格式
WHERE list LIKE '%mr%'
WHERE list LIKE 'mr%'
WHERE list LIKE '[mr]'
WHERE list LIKE '[^a-z]'
...
  1. 转义字符使用 ESCAPE 定义
WHERE list LIKE '%10#%' ESCAPE '#'
# '#' 被定义为转义字符,其后的 '%' 被解释为普通字符

2.15 行数据过滤

2.15.1 行查询

  1. 查询指定行:查询第 n 行,先将表中的前 n 行数据查询出来,再将表中的前 n-1 行数据查询出来,最后通过 NOT EXISTS 操作符将表中的第 n 行数据显示出来。(如下示例,其中用到了子查询)
SELECT list1, list2 FROM (SELECT TOP n * FROM table) aa
WHERE NOT EXISTS (SELECT * FROM (SELECT TOP n-1 * FROM table) bb
WHERE aa.list1=list2);
  1. 随机查询一行数据
  • SQL Server:使用 NEWID() 函数返回一个唯一的标识符值(类似随机排序,然后选择第一个)
SELECT TOP 1 list
FROM table order by NEWID();
  • MySQL:使用 RAND() 函数
SELECT list
FROM table
ORDER BY RAND() LIMIT 1;
  • Oracle:
SELECT list FROM(
SELECT list FROM table ORDER BY DBMS_RANDOM.VALUE())
WHERE ROWNUM=1;
  1. 在结果集中添加行号
SELECT (SELECT COUNT(num) FROM table A
WHERE A.num>=B.num) id, num, sn
FROM table B ORDER BY 1;
  1. 使用 ROW_NUMBER() OVER() 函数查询指定行
  • 例子:SQL Server:
SELECT 编号, list2 FROM (
SELECT ROW_NUMBER() OVER(ORDER BY list2) 编号, list2
FROM table) a WHERE a.编号%2=1;
  • Oracle:取余函数使用 MOD()
  • MySQL 不支持 ROW_NUMBER() OVER() 函数
  • 使用 BETWEEN…AND… 可查询指定范围内的行

2.15.2 空值判断

  1. 查询是否为空值:
SELECT list1, list2
FROM table
WHERE list2 IS [NOT] NULL;
  1. 对空值进行处理:
  • SQL Server 中填充空值:
SELECT list1, list2, ISNULL(list3, 0) AS new_list3
FROM table;
  • Oracle 中填充空值:
SELECT list1, list2, NVL(list3, 0) AS new_list3
FROM table;
  • MySQL: ISNULL() 只返回 0 或 1
  • 将指定值转换为空值:NULLIF()
SELECT list1, list2, NULLIF(name, 'abc') AS name
FROM table;

2.16 数据排序

2.16.1 数值排序

  • ORDER BY 基本语法:
ORDER BY { order_by_expression [ ASC | DESC ] } [ ,...n]
# order_by_expression:指定要排序的列,列名或别名的表达式,可以指定多个排序列,第一个列为主排列,以此类推
# 默认为 ASC 升序
# ORDER BY 只能出现在 SELECT 语句的最后
# 一般情况下,排序列可以不出现在 SELECT 选择列表中,但当 SELECT 语句出现了 DISTINCT 或 UNIQUE 关键字,则 ORDER BY 只能指定前面选择列表中的项目

# 例子:
SELECT list1, list2
FROM table
ORDER BY list2 DESC;
  • SQL Server 中,ORDER BY 优先级高于 TOP, Oracle 中,ORDER BY 优先级低于 ROWNUM()

2.16.2 汉字排序–COLLATE Chinese_PRC_

  1. 排序规则:Chinese_PRC_[] 是指针对简体字 UNICODE 字符集的排序规则
  2. 其中后半部分有:
  • _BIN: 表示二进制排序
  • _CI(CS): 是否区分大小写,前者为不区分
  • _AI(AS): 是否区分重音,前者为不区分
  • _KI(KS): 是否区分假名类型,前者为不区分
  • _WI(WS): 是否区分宽度,前者为不区分
  1. 例子:按姓氏笔画排序:Chinese_PRC_Stroke_
SELECT * FROM table;
SELECT * FROM table
ORDER BY LEFT(name, 1) COLLATE Chinese_PRC_Stroke_CS_AS_KS_WS;
  1. 例子:按拼音排序:Chinese_PRC_
SELECT * FROM table;
SELECT * FROM table
ORDER BY LEFT(name, 1) COLLATE Chinese_PRC_CS_AS_KS_WS;

2.17 数据统计分析

SELECT SUM( [DISTINCT] expression) 
FROM table
[WHERE condition];    # 非空值求和

SELECT AVG( [DISTINCT] expression)    # expression 必须为数值型,且不允许为聚合函数和子查询
FROM table
[WHERE condition];    # 非空值 [非重复值] 求平均值

SELECT MIN( [DISTINCT] expression) 
FROM table
[WHERE condition];    # 最小值(数值、字符串、日期)

SELECT MAX( [DISTINCT] expression) 
FROM table
[WHERE condition];    # 最大值(数值、字符串、日期)

SELECT COUNT( [DISTINCT] * | expression)    # * 为所有行,不能与 DISTINCT 一起使用
FROM table
[WHERE condition];   # [非重复值] 计数
  • WHERE 语句中可以使用聚合函数
  • SQL Server 中聚合函数不能嵌套,在 Oracle 中可以,但必须设置 GROUP BY 子句
  • 子查询不能作为一个聚合函数的表达式

2.18 分组统计

2.18.1 创建分组

SELECT list, COUNT(*) AS 数量
FROM table
[WHERE condition]
GROUP BY list1 [, list2]
[ORDER BY item];
  • 如果使用了 GROUP BY 子句进行分组查询,则 SELECT 查询的列必须包含在 GROUP BY 子句中或者包含在聚合函数中(否则分组拿来干嘛用的)
  • 上述语句执行顺序为:先执行 FROM,如果存在 WHERE,则进行筛选,根据 GROUP BY 进行分组,最后根据 SELECT 子句生成结果(如果有 ORDER BY 子句的话)
  • 对于 NULL 值,尽管 SQL 中规定 NULL<>NULL ,但在分组时会将 NULL 值都分为一组

2.18.2 使用 ROLLUP 关键字

GROUP BY ROLLUP(A, B, C)    # Oracle, SQL Server
GROUP BY A, B, C WITH ROLLUP    # SQL Server
  • 系统先对 A, B, C 进行分组操作,然后对 A, B 进行分组操作, 然后对 A 进行分组操作,最后对全表分组(即全表汇总)
  • 相当于生成了各种分类汇总

2.18.3 使用 CUBE 关键字

GROUP BY CUBE(A, B)    # Oracle, SQL Server
GROUP BY A, B, C WITH CUBE    # SQL Server
  • 系统会对 A, B 分组,对 A 分组, 对 B 分组,最后对全表分组(即全表汇总)

2.18.4 使用 HAVING 子句进行过滤分组

  1. HAVING 子句和 WHERE 子句用法相似,两者区别如下:
  • WHERE 不能放在 GROUP BY 后面,HAVING 可以
  • HAVING 是和 GROUP BY 一起用的,放在其后面,作用和 WHERE 一样
  • WHERE 不能用于聚合函数,HAVING可以
  • WHERE 用于分组前过滤,HAVING 用于分组后过滤
  1. 示例:统计 list3 小于 1000 并且 list2 大于 list2 的平均值的,根据 list1 分组的条目数量
SELECT list 1, list2, COUNT(list1) 数量
FROM table
WHERE (list3 < 1000)
GROUP BY list1, list2
HAVING (list2 > 
	(SELECT AVG(list2)
	FROM table))
ORDER BY list2 DESC;

2.18.5 SELECT 子句的顺序

SELECT → \to FROM → \to WHERE → \to GROUP BY → \to HAVING → \to ORDER BY

2.19 子查询

2.19.1 简单子查询

  1. 子查询的语法:
(SELECT [ALL | DISTINCT]