SQL语法概述

SQL

Posted by Gu on 2022-07-05
Estimated Reading Time 17 Minutes
Words 4.2k In Total

SQL概述

SQL简介

SQL(Structured Query Language):结构化查询语言。

一种对关系型数据库进行操作的语言,可以应用到所有关系型数据库中,例如:MySQL、ORacle、SQL Server 等。SQL 标准(ANSI/ISO)有:

  • SQL-92:1992 年发布的 SQL 语言标准;
  • SQL:1999:1999 年发布的 SQL 语言标准;
  • SQL:2003:2003 年发布的 SQL 语言标准;

SQL 可以用在所有关系型数据库中,许多关系型数据库除了实现语言标准外,还都有标准之后的一些语法。例如 MySQL 中的 LIMIT 语句就是 MySQL 独有的,其它数据库都不支持!

语法要求

  • SQL语句可以单行/多行书写,以分号分割语句;
  • 可以用空格和缩进来增强语句的可读性;
  • 语句不区分大小写,对于标准的关键字建议大写,自定义的如表名,数据库名等可以小写。

SQL分类

DDL(Data DefINitiON Language):

数据定义语言,用来定义数据库对象:库、表、列等;

DML(Data ManipulatiON Language):

数据操作语言,用来定义数据库记录(数据);

DCL(Data CONtrol Language):

数据控制语言,用来定义访问权限和安全级别;

DQL(Data Query Language):

数据查询语言,用来查询记录(数据)

DDL(Data DefINitiON Lanuage) : 数据定义语言

操作数据库

基本操作

查看所有数据库:SHOW DATABASES;
切换数据库:USE 数据库名;

创建数据库:

CREATE DATABASE [IF NOT EXISTS] 数据库名;

删除数据库:

DROP DATABASE [IF EXISTS] 数据库名 [DEFAUlT CHARSET 字符集] [COLLATE 排序规则];

如果没有加入IF EXISTS删除不存在的数据库,会报错。

修改数据库:

ALTER DATABASE 数据库名 CHARACTER SET utf8; #修改数据库字符集

在 MySQL 中所有的 UTF-8 编码都不能使用中间的"-",即 UTF-8 要书写为 UTF8

操作表

基本操作

查看所有表:SHOW TABLES;
切换表:USE 表名;
查看表结构:DESC 表名;
查看建表语句:SHOW CREATE TABLE 表名;

数据类型:

INT: 整型;(除了INT之外整型还有TINYINT、SMALLINT、MEDIUMINT)
double: 浮点型,例如 double(5,2)表示最多 5 位,其中必须有 2 位小数,即最大值为 999.99;
decimal: 泛型型,在表单线方面使用该类型,因为不会出现精度缺失问题;
char: 固定长度字符串类型;(当输入的字符不够长度时会补空格)
varchar: 固定长度字符串类型;
text: 字符串类型;
blob: 字节类型;
date: 日期类型,格式为:yyyy-MM-dd;
time: 时间类型,格式为:hh:mm:ss
timestamp: 时间戳类型;

创建表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
CREATE TABLE 表名{
字段1 字段1类型[COMMENT 字段1注释],
字段2 字段2类型[COMMENT 字段2注释],
... ...
}[COMMENT 表注释];

## 例子
CREATE TABLE user (
`id` INt(11) COMMENT '编号',
`name` varchar(50) COMMENT '姓名',
`age` INt(11) COMMENT '年龄',
`gender` varchar(1) COMMENT '性别'
) COMMENT='用户表'

常见约束

image-20230223213339630

删除表

1
2
DROP TABLE [IF EXISTS] 表名;	#删除表
TRUNCATE TABLE 表名; #删除表,并重新创建该表(清空表中数据)

修改表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#添加字段
ALTER TABLE 表名 ADD 字段名 类型(长度) [COMMENT 注释] [约束];

#修改数据类型
ALTER TABLE 表名 MODIFY 字段名 新数据类型(长度);

#修改字段名和字段类型
ALTER TABLE 表名 CHANGE 旧字段名 新字段名 类型(长度) [COMMENT 注释] [约束];

#删除字段名
ALTER TABLE 表名 DROP 字段名

#修改表名,可以不加to也能修改
ALTER TABLE 表名 RENAME [TO] 新表名

复制表

1
2
3
4
5
6
# 复制表结构及数据
CREATE TABLE 新表名 SELECT * FROM 旧表名;

#复制表结构到新表,不复制数据(下面两个都行)
CREATE TABLE 新表名 SELECT * FROM 旧表名 WHERE 1 = 2;
CREATE TABLE 新表名 LIKE 旧表名;

DML (Data ManipulatiON Language) : 数据操作语言

插入数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#给指定字段添加数据
INSERT INTO 表名(字段名1, 字段名2, ......) VALUES (值1, 值2, ......);
## 例子
INSERT INTO employee
(id, wORkno, name, gender, age, idcard,entrydate)
VALUES
(1, '1', 'Itcast', '男', 10, '123412341234123412', '2022-09-18');

#未指定字段名,则是给全部字段添加数据
INSERT INTO 表名 VALUES(值1,值2,...);
## 例子
INSERT INTO employee
VALUES
(2, '2', 'Itcast', '男', 10,'123412348234123412', '2022-09-17');

#批量添加数据(下面两种方式都可以)
INSERT INTO 表名(字段1,字段2,......)
VALUES(值1,值2,...),(值1,值2,...),(值1,值2,...);

INSERT INTO 表名
VALUES(值1,值2,...),(值1,值2,...),(值1,值2,...);

#复制旧表的数据到新表
INSERT INTO 新表名(字段1,字段2,......)
SELECT 字段1,字段2,......
FROM 旧表名

修改数据

1
2
3
4
5
# 修改记录,如果没有条件,则会修改整张表的记录
UPDATE 表名 SET 字段1=值1,字段2=值2,...[WHERE 条件];
## 例子
UPDATE employee SET name='itheima' WHERE id = 1;
UPDATE employee SET entrydate = '2008-01-01'; //修改所有数据的日期

删除数据

1
2
3
4
5
# 删除记录,如果没有条件会删除整张表的记录
DELETE FROM 表名 [WHERE 条件]
## 例子
DELETE FROM employee WHERE gender = '女';
DELETE FROM employee;#删除该表所有数据

DCL(Data CONtrol Language):数据控制语言

查询用户:

1
2
USE mysql;
SELECT * FROM user;

创建用户

1
2
3
4
5
6
7
# 创建用户
CREATE USER '用户名'@'主机名' IDENTIFIED BY '密码';
## 例子
CREATE USER 'xiaomi'@'localhost' IDENTIFIED BY '123456asd...';

# 创建任意主机都可以访问的用户 ‘%’代表任意主机
CREATE USER 'heima'@'%' IDENTIFIED BY 'qiu11.29';

修改用户密码(以root身份)

1
2
3
4
# 修改用户密码
ALTER USER '用户名'@'主机名' IDENTIFIED WITH mysql_native_passwORd BY '新密码';
## 例子
ALTER USER 'xiaomi'@'localhost' IDENTIFIED WITH mysql_native_passwORd by'123456Asd1231...';

删除用户

1
2
3
4
# 删除用户
DROP USER '用户名'@'主机名';
## 例子
DROP USER 'xiaomi'@'localhost';

授权用户

用户权限

image-20230223205048498

1
2
3
4
5
# 授予权限
GRANT 权限列表 ON 数据库名.表名 TO '用户名'@'主机名';

# 授予用户访问itcast数据库所有表的权限
GRANT ALL ON itcast.* TO 'xiaomi'@'localhost';

撤销授权

1
2
3
4
5
# 撤销权限
REVOKE 权限列表 ON 数据库名.表名 FROM '用户名'@'主机名';

# 撤销用户的所有权限
REVOKE ALL ON itcast.* FROM 'xiaomi'@'localhost';

查看用户权限

1
2
3
4
# 查询权限
SHOW GRANTS FOR '用户名'@'主机名';
## 例子
SHOW GRANTS FOR 'xiaomi'@'localhost';

DQL(Data Query Language):数据查询语言

基础查询

基础格式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 查询语句格式
SELECT 字段列表

FROM 表名列表

WHERE 条件列表

GROUP BY 分组字段列表

HAVING 分组后条件列表

ORDER BY 排序字段列表

LIMIT 分页参数


# 基本使用
SELECT 字段1,字段2,... FROM 表名;
## 例子
SELECT * FROM employees;
SELECT employee_id, last_name, salary FROM employees;

1、空值参与运算也为NULL;

2、着重号在与关键词重名时候使用

执行顺序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
FROM 表名(列表)
WHERE 条件(列表)
GROUP BY 分组字段(列表)
HAVING 分组后的条件(列表)
SELECT 字段(列表)
ORDER BY 排序字段(列表)
LIMIT 分页参数

# 列的别名只能在ORDER BY中使用,不能在WHERE中使用,与SQL执行原理有关
SELECT employee_id, salary, salary * 12 annual_sal FROM employees WHERE
annual_sal > 81600;#错误语法

# WHERE 需要声明在FROM后,ORDER BY
SELECT employee_id, salary # 再执行这句
FROM employees WHERE department_id IN (50, 60, 70) # 先执行这句
ORDER BY department_id DESC; # 最后执行这句

条件查询

条件查询就是在查询时给出 WHERE 子句,在 WHERE 子句中可以使用如下运算符及关键字:

  • =、!=、<>、<、<=、>、>=;
  • BETWEEN…AND;
  • IN(set);
  • IS NULL;
  • AND;
  • OR;
  • NOT;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
# 查询性别为女,并且年龄小于 50 的记录
SELECT * FROM stu
WHERE gender='female' AND age<50;

# 查询学号为 S_1001,或者姓名为 liSi 的记录
SELECT * FROM stu
WHERE sid ='S_1001' OR sname='liSi';

# 查询学号为 S_1001,S_1002,S_1003 的记录
SELECT * FROM stu
WHERE sid IN ('S_1001','S_1002','S_1003')

# 查询学号不是 S_1001,S_1002,S_1003 的记录
SELECT * FROM stu
WHERE sid NOT IN ('S_1001','S_1002','S_1003');

# 查询年龄为 NULL 的记录
SELECT * FROM stu
WHERE age IS NULL;

# 查询年龄在 2040 之间的学生记录
SELECT * FROM stu
WHERE age>=20 AND age<=40;
# 或者
SELECT * FROM stu
WHERE age BETWEEN 20 AND 40;

# 查询性别非男的学生记录
SELECT * FROM stu
WHERE gender!='male';
# 或者
SELECT * FROM stu
WHERE gender<>'male';
# 或者
SELECT * FROM stu
WHERE NOT gender='male';

# 查询姓名不为 NULL 的学生记录
SELECT * FROM stu
WHERE NOT sname IS NULL;
# 或者
SELECT * FROM stu
WHERE sname IS NOT NULL;

模糊查询

LIKE匹配

1
2
# 模糊查询 LIKE 格式
SELECT 字段 FROMWHERE 某字段 LIKE 条件

其中关于LIKE条件,SQL 提供了两种匹配模式:

  • % :表示任意 0 个或多个字符。可匹配任意类型和长度的字符,有些情况下若是中文,请使用两个百分号(%%)表示。

  • _: 表示任意单个字符。匹配单个任意字符,它常用来限制表达式的字 符长度语句。

1
2
3
4
5
6
7
8
## 例子
# 查询姓名由 5 个字母构成的学生记录
SELECT * FROM stu
WHERE sname LIKE '_ _ _ _ _';

# 查询姓名以“z”开头的学生记录
SELECT * FROM stu
WHERE sname LIKE 'z%';

正则表达式匹配

1
2
3
4
# 正则表达式匹配
# ^表示以一些字符开头
# $表示以一些字符结尾
SELECT 'shkstart' REGEXP '^shk', 'shkstart' REGEXP 't$', 'shkstart' REGEXP 'hk' FROM DUAL;

字段控制查询

1
2
3
4
5
6
7
8
9
10
11
12
# 别名(AS)使用
# AS->alias,可以省略
# 列的别名可以使用一对''
## 例子
SELECT wORkaddress [AS] '工作地址' FROM emp;

SELECT employee_id [AS] emp_id, last_name lname, department_id "dept_id",salary * 12 annual_sal
FROM employees;

# 去除重复行,使用DISTINCT
## 例子
SELECT DISTINCT department_id FROM employees

排序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# ASC 升序(默认)     DESC 降序
## 例子
# 按照年龄升序
SELECT * FROM stu
ORDER BY age ASC;
# 或
SELECT * FROM stu ORDER BY age;

# 按照年龄降序
SELECT * FROM stu
ORDER BY age DESC;

# 查询所有雇员,按月薪降序,月薪相同时,按编号升序排序
SELECT * FROM emp
ORDER BY sal DESC ,empno ASC;

如果没有使用排序操作,默认情况下查询返回的数据是按照添加数据顺序显示的

聚合函数

聚合函数是用来做纵向运算的函数:

COUNT():统计指定列不为 NULL 的记录行数;
## 例子
# 查询 emp 表中记录数:
SELECT COUNT(*) AS cnt FROM emp;

MAX():计算指定列的最大值,如果指定列是字符串类型,那么使用字符串排序运算;
MIN():计算指定列的最小值,如果指定列是字符串类型,那么使用字符串排序运算;
## 例子
# 查询最高工资和最低工资:
SELECT MAX(sal), MIN(sal) FROM emp;

SUM():计算指定列的数值和,如果指定列类型不是数值类型,那么计算结果为 0;
## 例子
#查询所有雇员月薪和:
SELECT SUM(sal) FROM emp;

AVG():计算指定列的平均值,如果指定列类型不是数值类型,那么计算结果为 0;
## 例子
# 统计员工平均薪资 
SELECT AVG(sal) FROM emp;

分组查询

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 语句格式
SELECT 字段列表 FROM 表名[WHERE 条件] GROUP BY 分组字段名 [HAVING 分组后过滤条件];

## 例子
# 查询每个部门的部门编号以及每个部门工资大于 1500 的人数
SELECT deptno ,COUNT(*)
FROM emp
WHERE sal>1500`
GROUP BY deptno;

# 查询工资总和大于 9000 的部门编号以及工资和
SELECT deptno, SUM(sal)
FROM emp
GROUP BY deptno
HAVING SUM(sal) > 9000;

  1. 执行时机:where是分组之前过滤,不满足就不参与分组;havINg是分组之后进行过滤。
  2. 判断条件:where不能对聚合函数判断,havINg可以。
  3. 执行顺序 where > 聚合函数 > havINg 分组之后。
  4. 查询的字段为聚合函数和分组字段,查询其他字段无意义

限定查询

1
2
# LIMIT 格式,起始索引默认从0开始
SELECT 字段列表 FROM 表名 LIMIT [起始索引,]查询记录数;
  1. 起始索引从0开始,每一页的起始索引 = (页码 - 1)× 查询记录数。 分
  2. 页查询是数据库的方言,不同的数据库有不同的实现。LIMIT 可以在Mysql,PGSQL, MariaDB,SQLite等数据库中使用,表示分页。不能使用在SQL Server,DB2,ORacle。
  3. 如果查询的是第一页数据,起始索引可以省略,简写为limit 10。

连接查询

内连接:

查询的是两个表交集的部分

  • 隐式内连接
1
2
3
4
5
6
7
8
9
# 语法
SELECT 字段列表 FROM1,表2 WHERE 条件...;

## 例子
# 查询员工姓名,关联的部门的名称
SELECT emp.name, dept.name FROM emp, dept WHERE emp.dept_id = dept.id;

# 为表起别名,简化查询语句 先执行FROM
SELECT e.name, d.name FROM emp e, dept d WHERE e.dept_id = d.id;
  • 显示内连接(带有JOIN等关键字)
1
2
3
4
5
6
# 语法
SELECT 字段列表 FROM1 [INNER] JOIN2 ON 连接条件...;

## 例子
SELECT * FROM emp e INNER JOIN dept d ON e.dept_id = d.id;
SELECT * FROM emp e JOIN dept d ON e.dept_id = d.id;

外连接:

  • 左外连接

除了求两表的交集,还包含左表剩余的不能匹配右表的记录

1
2
3
4
5
6
7
8
# 语法
SELECT 字段列表 FROM1 LEFT [OUTER] JOIN2 ON 条件...;

## 例子
# 查询emp表的所有数据,包含其对应的部门信息, 哪怕员工没有部门也会显示
SELECT e.*, d.name FROM emp e LEFT OUTER JOIN dept d ON e.dept_id = d.id;
# 或
SELECT e.*, d.name FROM emp e LEFT JOIN dept d ON e.dept_id = d.id;
  • 右外连接

除了求两表的交集,还包含右表剩余的不能匹配左表的记录

1
2
3
4
5
6
7
8
9
10
# 格式
SELECT 字段列表 FROM1 RIGHT [outer] JOIN2 ON 条件...;

## 例子
# 查询dept表的全部数据,包括对应的员工信息
SELECT d.*, e.* FROM emp e RIGHT JOIN dept d ON e.dept_id = d.id;

# 右外可以改成左外,把表的顺序掉个个
SELECT d.*, e.* FROM dept d LEFT JOIN emp e ON e.dept_id = d.id;

  • 自连接

自连接可以是内连接也可以是外连接,只要把一个表起两个别名当两个表用即可

1
2
3
4
5
6
7
8
# 格式
SELECT 字段列表 FROM 表A 别名A JOIN 表A 别名B ON 条件...;

## 例子
# 查询员工 及其 所属领导 的名字,员工的managerid是其领导的id
SELECT a.name, b.name FROM emp a, emp b WHERE a.managerid = b.id;
# 哪怕没有领导也要显示
SELECT a.name '员工', b.name '领导' FROM emp a LEFT JOIN emp b ON a.managerid = b.id;

联合查询

把多张表查询的结果合并起来,形成一个新的结果集。

每张表的查询结果字段数必须保持一致。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 语法
SELECT 字段列表 FROM 表A...
UNION [all]
SELECT 字段列表 FROM 表B...;

## 例子
# 薪资低于5000和年龄大于50的(可能重复)
SELECT * FROM WHERE salary < 5000;
UNION all
SELECT * FROM WHERE age > 50;

# 薪资低于5000和年龄大于50的(合并后会去重,不会重复)
SELECT * FROM WHERE salary < 5000;
UNION
SELECT * FROM WHERE age > 50;

UNION 与 UNION ALL的区别在于UNION ALL不会去除结果集中的重复记录,而UNION会去除重复记录。

子查询

根据结果划分:

  • 标量子查询:子查询结果为单值
  • 行子查询:子查询结果为单行(单记录)
  • 列子查询:子查询结果为一列
  • 表子查询:子查询结果为多行多列

根据位置划分:

  • WHERE之后
  • FROM之后
  • SELECT之后

根据相关性划分:

  • 相关子查询

  • 无关子查询

子查询外部语句可以是INSERT / UPDATE / DELETE / SELECT 的任何一个

结果划分示例

  • 标量子查询
1
2
3
4
5
6
7
8
9
# 查询销售部的所有员工信息
-- step 1: 查询销售部的部门ID 4
SELECT id FROM dept WHERE name = '销售部';
-- step 2: 根据ID,查询员工信息
SELECT * FROM emp WHERE dept_id = 4;

# 化为子查询
SELECT * FROM emp WHERE dept_id = (SELECT id FROM dept WHERE name = '销售
部');
  • 列子查询

常用操作符:

image-20230223220117735

1
2
3
4
5
6
7
8
9
# 查询 "销售部" 和 "市场部" 的所有员工信息
-- step 1: 查询 "销售部" 和 "市场部" 的部门ID
SELECT id FROM dept WHERE name = '销售部' OR name = '市场部';
-- step 2: 根据部门ID, 查询员工信息
SELECT * FROM emp WHERE dept_id IN (2, 4);

# 化为子查询
SELECT * FROM emp WHERE dept_id IN (SELECT id FROM dept WHERE name = '销售部'
OR name = '市场部');
  • 行子查询

常见操作符:=,<, >, IN, NOT IN;

1
2
3
4
# 查询与‘张无忌’的薪资及领导相同的员工信息
# 化为子查询
SELECT * FROM emp WHERE (salary, managerid) =
(SELECT salary, managerid FROM emp WHERE name = '张无忌');
  • 表子查询

常见操作符:IN;

1
2
3
4
5
# 查询与 "鹿杖客" , "宋远桥" 的职位和薪资相同的员工信息
# 化为子查询
SELECT job, salary FROM emp WHERE name = '鹿杖客' OR name = '宋远桥';
SELECT * FROM emp WHERE (job,salary) IN (SELECT job, salary FROM emp WHERE
name = '鹿杖客' OR name = '宋远桥');

If you like this blog or find it useful for you, you are welcome to comment on it. You are also welcome to share this blog, so that more people can participate in it. If the images used in the blog infringe your copyright, please contact the author to delete them. Thank you !