文章目录
- 登录
- 退出
- 查看MySQL版本
- 登录到MySQL服务端
- 命令行
- MySQL的语法规范
- SQL的语言分类
- SQL 常用语句
- SQL 语句
- 1. DQL 语言
- 1.1 基础查询
- 1.2 条件查询
- 1.3 排序查询
- 1.4 常见函数
- 1.4.1 单行函数
- 1.4.2 分组函数
- 1.5 分组查询
- 1.6 多表连接查询
- 1.6.1 传统模式下的连接:等值连接/非等值连接
- 1.6.2 sql99语法:通过join关键字实现连接
- 1.6.2.1 内连接
- 1.6.2.2 外连接
- 补充:SQL语句执行顺序
- 1.7 子查询
- 1.7.1 where或having后面
- 1.7.1.1 标量子查询(单行子查询) ☆
- 1.7.1.2 列子查询(多行子查询)★
- 1.7.1.3 行子查询(一行多列或多行多列)
- 1.7.2 select 后面
- 1.7.3 from后面
- 1.7.4 exists后面(相关子查询)
- 1.7.5 练习
- 1.8 分页查询
- 1.9 联合查询
- 2. DML 语言
- 2.1 插入语句
- 2.1.1 方式一
- 2.1.2 方式二
- 2.1.3 比较
- 2.2 修改语句
- 2.2.1 修改单表的记录☆
- 2.2.2 修改多表的记录
- 2.3 删除语句
- 2.3.1 方式一:delete
- 2.3.2 方式二:truncate
- 2.3.3 比较
- 3. DDL语句
- 3.1 库的管理
- 3.1.1 库的创建
- 3.1.2 库的修改
- 3.1.3 库的删除
- 3.2 表的管理
- 3.2.1 表的创建☆
- 3.2.2 表的修改
- 3.2.3 表的删除
- 3.3 表的复制
- 3.4 常见约束
- Reference
本篇文章已同步更新至github仓库JavaSummary,欢迎star!
登录
mysql 【-h主机名 -P端口号 】-u用户名 -p密码
mysql -hlocalhost -P3306 -uroot -p1997
mysql -uroot -p1997
退出
exit
ctrl+c
查看MySQL版本
登录到MySQL服务端
SELECT VERSION();
命令行
mysql --version
mysql -V
MySQL的语法规范
1.不区分大小写,但建议关键字大写,表名、列名小写
2.每条命令最好用分号结尾
3.每条命令根据需要,可以进行缩进 或换行
4.注释
单行注释:#注释文字
单行注释:-- 注释文字
多行注释:/* 注释文字 */
SQL的语言分类
- DQL(Data Query Language):数据查询语言
select
- DML(Data Manipulate Language) : 数据操作语言
insert 、update、delete
- DDL(Data Define Languge):数据定义语言
create、drop、alter
- TCL(Transaction Control Language):事务控制语言
commit、rollback
DCL是数据控制语言(Data Control Language)的简称,它包含诸如GRANT
之类的命令,并且主要涉及数据库系统的权限,权限和其他控件。
-
GRANT
:允许用户访问数据库的权限 -
REVOKE
:撤消用户使用GRANT命令赋予的访问权限
SQL 常用语句
- 查看当前所有的数据库
SHOW DATABASES;
- 打开指定的库
USE test;
- 查看当前库的所有表
SHOW TABLES;
- 查看其它库的所有表
SHOW TABLES FROM girls;
- 查看表结构
DESC emp;
SQL 语句
示例用到的数据库文件: 链接:https://pan.baidu.com/s/1u71e3oBR4Ylu72YitilqIg
提取码:ae0q
1. DQL 语言
1.1 基础查询
语法:
SELECT 【要查询的内容】
【FROM 表名】;
特点:
- 通过select查询完的结果 ,是一个虚拟的表格,不是真实存在
- 【要查询的内容】可以是常量值、表达式、字段、函数
示例:
USE myemployees;
# 查询表中单个字段
SELECT last_name FROM employees;
# 查询表中多个字段
SELECT last_name,salary,email FROM employees;
# 查询表中所有字段
SELECT * FROM employees;
# 查询常量值
SELECT 100;
SELECT 'john';
# 查询表达式
SELECT 100%98;
# 查询函数
SELECT version();
# 起别名
SELECT last_name As 姓 FROM employees;
SELECT last_name 姓,first_name 名 FROM employees;
SELECT salary AS "out put" FROM employees;
# 去重
## 案例:查询员工表中涉及到的所有的部门编号
SELECT department_id FROM employees;
SELECT DISTINCT department_id FROM employees;
# +号的作用
SELECT CONCAT('a','b','c') AS 结果;
SELECT
CONCAT(last_name," ",first_name) AS 姓名
FROM
employees;
1.2 条件查询
条件查询:根据条件过滤原始表的数据,查询到想要的数据
语法:
select
要查询的字段|表达式|常量值|函数
from
表
where
条件 ;
条件分类:
- 条件表达式
示例:salary>10000
条件运算符:
> < >= <= = != <>
SELECT last_name,salary FROM employees WHERE salary > 10000;
- 逻辑表达式
示例:salary>10000 && salary<20000
逻辑运算符:
and(&&):两个条件如果同时成立,结果为true,否则为false
or(||):两个条件只要有一个成立,结果为true,否则为false
not(!):如果条件成立,则not后为false,否则为true
SELECT last_name,salary FROM employees WHERE salary > 10000 && salary < 20000;
- 模糊查询
示例:last_name like 'a%'
SELECT last_name FROM employees WHERE last_name LIKE 'a%';
SHOW VARIABLES LIKE '%char%';
# 查询员工表的job_id中包含 a和e的,并且a在e的前面
SELECT job_id
FROM employees
WHERE job_id LIKE '%a%e%';
1.3 排序查询
语法:
select
要查询的东西
from
表
where
条件
order by 排序的字段|表达式|函数|别名 【asc|desc】
示例:
# 从 employees 表中查找工资大于10000的人员姓名并按照工资排序(DESC表示降序,ASC表示升序,默认升序)
SELECT CONCAT(last_name, " ",first_name) AS 姓名, salary AS 工资
FROM employees
WHERE salary > 10000
ORDER BY salary DESC;
# 查询员工信息,要求先按工资降序,再按employee_id升序
SELECT *
FROM employees
ORDER BY salary DESC,employee_id ASC;
# 查询员工表的employee_id job_id last_name, 按department_id降序,salary升序
SELECT employee_id, job_id, last_name
FROM employees
ORDER BY department_id DESC, salary ASC;
1.4 常见函数
1.4.1 单行函数
- 字符函数
concat 拼接
substr 截取子串
upper 转换成大写
lower 转换成小写
trim 去前后指定的空格和字符
ltrim 去左边空格
rtrim 去右边空格
replace 替换
lpad 左填充
rpad 右填充
instr 返回子串第一次出现的索引
length 获取字节个数
示例:
# length 获取参数值的字节个数
SELECT LENGTH('john');
# 将姓变大写,名变小写,然后拼接
SELECT CONCAT(UPPER(last_name),LOWER(first_name)) 姓名 FROM employees;
# 索引从1开始
# 截取从指定索引处后面所有字符
SELECT SUBSTR('Hello World!', 7) output;
# 截取从指定索引处指定字符长度的字符
SELECT SUBSTR('Hello World!', 7, 5) output;
# 返回子串第一次出现的索引,如果找不到返回0
SELECT INSTR('Hello World', 'World') output;
# 去前后指定的空格和字符
SELECT LENGTH(TRIM(' Hello World ')) output;
SELECT TRIM('aa' FROM 'aaaaHelloaaWorldaaaa') output;
# lpad 用指定的字符实现左填充到指定长度
SELECT LPAD('Hello World',10,'*') AS out_put;
# rpad 用指定的字符实现右填充到指定长度
SELECT RPAD('Hello World',12,'ab') AS out_put;
# replace 将Hello替换为World
SELECT REPLACE('HelloHelloWorldHello','Hello','World') AS out_put;
- 数学函数
round 四舍五入
rand 随机数
floor 向下取整
ceil 向上取整
mod 取余
truncate 截断
示例:
SELECT MOD(10,-3);
SELECT 10%3;
SELECT ROUND(1.2);
SELECT ROUND(1.567,2); #小数点后保留两位
SELECT CEIL(1.2);
SELECT FLOOR(1.2);
SELECT RAND();
SELECT TRUNCATE(1.69999,1); # 小数点后保留一位
- 日期函数
now 当前系统日期+时间
curdate 当前系统日期
curtime 当前系统时间
str_to_date 将字符转换成日期
date_format 将日期转换成字符
示例:
# now 返回当前系统日期+时间
SELECT NOW();
# curdate 返回当前系统日期,不包含时间
SELECT CURDATE();
# curtime 返回当前时间,不包含日期
SELECT CURTIME();
# 可以获取指定的部分,年、月、日、小时、分钟、秒
SELECT YEAR(NOW()) 年;
SELECT YEAR('1998-1-1') 年;
SELECT YEAR(hiredate) 年 FROM employees;
SELECT MONTH(NOW()) 月;
SELECT MONTHNAME(NOW()) 月;
# str_to_date 将字符通过指定的格式转换成日期
SELECT STR_TO_DATE('1998-3-2','%Y-%c-%d') AS out_put;
# 查询入职日期为1992--4-3的员工信息
SELECT * FROM employees WHERE hiredate = '1992-4-3';
SELECT * FROM employees WHERE hiredate = STR_TO_DATE('4-3 1992','%c-%d %Y');
# date_format 将日期转换成字符
SELECT DATE_FORMAT(NOW(),'%y年%m月%d日') AS out_put;
# 查询有奖金的员工名和入职日期(xx月/xx日 xx年)
SELECT last_name,DATE_FORMAT(hiredate,'%m月/%d日 %y年') 入职日期
FROM employees
WHERE commission_pct IS NOT NULL;
- 流程控制函数
if 处理双分支
case语句 处理多分支
情况1:处理等值判断
情况2:处理条件判断
# switch case
case 要判断的字段或表达式
when 常量1 then 要显示的值1或语句1;
when 常量2 then 要显示的值2或语句2;
...
else 要显示的值n或语句n;
end
# 多重 if
case
when 条件1 then 要显示的值1或语句1
when 条件2 then 要显示的值2或语句2
...
else 要显示的值n或语句n
end
示例:
SELECT IF(10<5,'大','小');
SELECT last_name,commission_pct,IF(commission_pct IS NULL,'没奖金','有奖金') 备注
FROM employees;
/*案例:查询员工的工资,要求
部门号=30,显示的工资为1.1倍
部门号=40,显示的工资为1.2倍
部门号=50,显示的工资为1.3倍
其他部门,显示的工资为原工资
*/
SELECT salary 原始工资,department_id,
CASE department_id
WHEN 30 THEN salary*1.1
WHEN 40 THEN salary*1.2
WHEN 50 THEN salary*1.3
ELSE salary
END AS 新工资
FROM employees;
/* 案例:查询员工的工资的情况
如果工资>20000,显示A级别
如果工资>15000,显示B级别
如果工资>10000,显示C级别
否则,显示D级别
*/
SELECT salary,
CASE
WHEN salary>20000 THEN 'A'
WHEN salary>15000 THEN 'B'
WHEN salary>10000 THEN 'C'
ELSE 'D'
END AS 工资级别
FROM employees;
- 其他
version 版本
database 当前库
user 当前连接用户
示例:
SELECT VERSION();
SELECT DATABASE();
SELECT USER();
1.4.2 分组函数
sum 求和
max 最大值
min 最小值
avg 平均值
count 计数
特点:
1、以上五个分组函数都忽略null值,除了count(*)
2、sum和avg一般用于处理数值型
max、min、count可以处理任何数据类型
3、都可以搭配distinct使用,用于统计去重后的结果
4、count的参数可以支持:
字段、*、常量值,一般放1
建议使用 count(*)
效率:
MYISAM存储引擎下 ,COUNT(*)的效率高
INNODB存储引擎下,COUNT(*)和COUNT(1)的效率差不多,比COUNT(字段)要高一些
示例:
SELECT COUNT(*) FROM employees; #统计行数
SELECT COUNT(1) FROM employees;
# 和分组函数一同查询的字段有限制
SELECT AVG(salary),employee_id FROM employees;
1.5 分组查询
语法:
select 查询的字段,分组函数
from 表
group by 分组的字段
特点:
1、可以按单个字段分组
2、和分组函数一同查询的字段最好是分组后的字段
3、分组筛选
针对的表 | 位置 | 关键字 | |
分组前筛选 | 原始表 | group by的前面 | where |
分组后筛选 | 分组后的结果集 | group by的后面 | having |
4、可以按多个字段分组,字段之间用逗号隔开
5、可以支持排序
6、having后可以支持别名
示例:
# 查询各个管理者手下员工的最低工资,没有管理者的员工不计算在内
SELECT MIN(salary),manager_id
FROM employees
WHERE manager_id IS NOT NULL
GROUP BY manager_id
#查询各个管理者手下员工的最低工资,其中最低工资不能低于6000,没有管理者的员工不计算在内
SELECT MIN(salary),manager_id
FROM employees
WHERE manager_id IS NOT NULL
GROUP BY manager_id
HAVING MIN(salary)>=6000;
# 查询所有部门的编号,员工数量和工资平均值,并按平均工资降序
SELECT department_id,COUNT(*),AVG(salary) a
FROM employees
GROUP BY department_id
ORDER BY a DESC;
1.6 多表连接查询
含义:又称多表查询,当查询的字段来自于多个表时,就会用到连接查询
笛卡尔乘积现象:表1 有m行,表2有n行,结果=m*n行
发生原因:没有有效的连接条件
如何避免:添加有效的连接条件
按年代分类 | sql92标准:仅仅支持内连接 | |
sql99标准【推荐】:支持内连接+外连接(左外和右外)+交叉连接 | ||
按功能分类 | 内连接 | 等值连接 |
非等值连接 | ||
自连接 | ||
外连接 | 左外连接 | |
右外连接 | ||
全外连接 | ||
交叉连接 |
1.6.1 传统模式下的连接:等值连接/非等值连接
- 等值连接的结果 = 多个表的交集
- n表连接,至少需要n-1个连接条件
- 多个表不分主次,没有顺序要求
- 一般为表起别名,提高阅读性和性能
示例:
# 等值连接
# 查询员工名和对应的部门名
SELECT last_name,department_name
FROM employees,departments
WHERE employees.`department_id`=departments.`department_id`;
# 为表起别名
## 提高语句的简洁度
## 区分多个重名的字段
## 注意:如果为表起了别名,则查询的字段就不能使用原来的表名去限定
# 可以加筛选
# 查询有奖金的员工名、部门名
SELECT last_name,department_name,commission_pct
FROM employees e,departments d
WHERE e.`department_id`=d.`department_id`
AND e.`commission_pct` IS NOT NULL;
# 可以加分组
# 查询每个城市的部门个数
SELECT COUNT(*) 个数,city
FROM departments d,locations l
WHERE d.`location_id`=l.`location_id`
GROUP BY city;
# 可以加排序
# 查询每个工种的工种名和员工的个数,并且按员工个数降序
SELECT job_title,COUNT(*)
FROM employees e,jobs j
WHERE e.`job_id`=j.`job_id`
GROUP BY job_title
ORDER BY COUNT(*) DESC;
# 三表连接
# 查询员工名、部门名和所在的城市
SELECT last_name,department_name,city
FROM employees e,departments d,locations l
WHERE e.`department_id`=d.`department_id`
AND d.`location_id`=l.`location_id`;
# 非等值连接
# 查询员工工资级别为A的员工
SELECT salary,grade_level
FROM employees e,job_grades g
WHERE salary BETWEEN g.`lowest_sal` AND g.`highest_sal`
AND g.`grade_level`='A';
# 自连接
# 查询 员工名和上级的名称
SELECT e.employee_id,e.last_name,m.employee_id,m.last_name
FROM employees e,employees m
WHERE e.`manager_id`=m.`employee_id`;
1.6.2 sql99语法:通过join关键字实现连接
含义:1999年推出的sql语法
支持:
- 等值连接、非等值连接 (内连接)
- 外连接
- 交叉连接
分类:
- 内连接(★):inner
- 外连接
- 左外(★) : left 【outer】
- 右外(★):right 【outer】
- 全外:full【outer】
- 交叉连接:cross
语法:
select 查询列表
from 表1
【inner|left outer|right outer|cross】join 表2 on 连接条件
【inner|left outer|right outer|cross】join 表3 on 连接条件
【where 筛选条件】
【group by 分组字段】
【having 分组后的筛选条件】
【order by 排序的字段或表达式】
优点:语句上,连接条件和筛选条件实现了分离,简洁明了!
1.6.2.1 内连接
语法:
select 查询列表
from 表1 别名
inner join 表2 别名 on 连接条件;
分类:
- 等值连接
- 非等值连接
- 自连接
特点:
- 添加排序、分组、筛选
- inner可以省略
- 筛选条件放在where后面,连接条件放在on后面,提高分离性,便于阅读
- inner join连接和sql92语法中的等值连接效果是一样的,都是查询多表的交集
示例:
等值连接:
# 查询员工名、部门名
SELECT last_name, department_name
FROM employees e
INNER JOIN departments d ON e.department_id=d.department_id;
# 查询名字中包含e的员工名和工种名(添加筛选)
SELECT last_name,job_title
FROM employees e
INNER JOIN jobs j ON e.`job_id`= j.`job_id`
WHERE e.`last_name` LIKE '%e%';
# 查询部门个数>3的城市名和部门个数(添加分组+筛选)
# ①查询每个城市的部门个数
# ②在①结果上筛选满足条件的
SELECT city,COUNT(*) 部门个数
FROM departments d
INNER JOIN locations l ON d.`location_id`=l.`location_id`
GROUP BY city
HAVING COUNT(*)>3;
# 查询部门的员工个数>3的部门名和员工个数,并按个数降序(添加排序)
#①查询每个部门的员工个数
SELECT COUNT(*),department_name
FROM employees e
INNER JOIN departments d ON e.`department_id`=d.`department_id`
GROUP BY department_name
#② 在①结果上筛选员工个数>3的记录,并排序
SELECT COUNT(*) 个数,department_name
FROM employees e
INNER JOIN departments d ON e.`department_id`=d.`department_id`
GROUP BY department_name
HAVING COUNT(*)>3
ORDER BY COUNT(*) DESC;
# 查询员工名、部门名、工种名,并按部门名降序(添加三表连接)
SELECT last_name,department_name,job_title
FROM employees e
INNER JOIN departments d ON e.`department_id`=d.`department_id`
INNER JOIN jobs j ON e.`job_id` = j.`job_id`
ORDER BY department_name DESC;
非等值连接:
# 查询员工的工资级别
SELECT salary,grade_level
FROM employees e
JOIN job_grades g ON e.`salary` BETWEEN g.`lowest_sal` AND g.`highest_sal`;
# 查询工资级别的个数>20的个数,并且按工资级别降序
SELECT COUNT(*),grade_level
FROM employees e
JOIN job_grades g ON e.`salary` BETWEEN g.`lowest_sal` AND g.`highest_sal`
GROUP BY grade_level
HAVING COUNT(*)>20
ORDER BY grade_level DESC;
自连接:
# 查询姓名中包含字符k的员工的名字、上级的名字
SELECT e.last_name,m.last_name
FROM employees e
JOIN employees m
ON e.`manager_id`= m.`employee_id`
WHERE e.`last_name` LIKE '%k%';
1.6.2.2 外连接
应用场景:用于查询一个表中有,另一个表没有的记录
特点:
- 外连接的查询结果为主表中的所有记录
- 如果从表中有和它匹配的,则显示匹配的值
- 如果从表中没有和它匹配的,则显示null
- 外连接查询结果 = 内连接结果 + 主表中有而从表没有的记录
- 左外连接,left join左边的是主表
- 右外连接,right join右边的是主表
- 左外和右外交换两个表的顺序,可以实现同样的效果
- 全外连接=内连接的结果+表1中有但表2没有的+表2中有但表1没有的
示例:
# 查询哪个部门没有员工
#左外
SELECT d.*,e.employee_id
FROM departments d # 主表
LEFT OUTER JOIN employees e
ON d.`department_id` = e.`department_id`
WHERE e.`employee_id` IS NULL;
# 右外
SELECT d.*,e.employee_id
FROM employees e # 主表
RIGHT OUTER JOIN departments d
ON d.`department_id` = e.`department_id`
WHERE e.`employee_id` IS NULL;
# 查询哪个城市没有部门
# 右连
SELECT city,d.*
FROM departments d
RIGHT OUTER JOIN locations l
ON d.`location_id`=l.`location_id`
WHERE d.`department_id` IS NULL;
# 查询部门名为SAL或IT的员工信息
SELECT e.*,d.department_name,d.`department_id`
FROM departments d
LEFT JOIN employees e
ON d.`department_id` = e.`department_id`
WHERE d.`department_name` IN('SAL','IT');
补充:SQL语句执行顺序
SQL语句执行顺序:
# 手写
SELECT DISTINCT
<select_list>
FROM
<left_table> <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>
# 机读
1 FROM < left_table >
2 ON <join_condition>
3 <join_type> JOIN <right_table>
4 WHERE <where_condition>
5 GROUP BY <group_by_list>
6 HAVING <having_condition>
7 SELECT
8 DISTINCT <select_list>
9 ORDER BY <order_by_condition>
10 LIMIT <limit_number>
1.7 子查询
含义:
- 一条查询语句中又嵌套了另一条完整的select语句,其中被嵌套的select语句,称为子查询或内查询。在外面的查询语句,称为主查询或外查询
特点:
- 子查询都放在小括号内
- 子查询可以放在from后面、select后面、where后面、having后面,但一般放在条件的右侧
- 子查询优先于主查询执行,主查询使用了子查询的执行结果
- 子查询根据查询结果的行数不同分为以下两类:
- 单行子查询
- 结果集只有一行
- 一般搭配单行操作符使用:> < = <> >= <=
- 非法使用子查询的情况:
- 子查询的结果为一组值
- 子查询的结果为空
- 多行子查询
- 结果集有多行
- 一般搭配多行操作符使用:any、all、in、not in
- in: 属于子查询结果中的任意一个就行
- any和all往往可以用其他查询代替
分类:
按子查询出现的位置 | select后面 | 仅仅支持标量子查询 |
from后面 | 支持表子查询 | |
where或having后面☆ | 标量子查询(单行)√ | |
列子查询(多行)√ | ||
行子查询 | ||
exists后面(相关子查询) | 表子查询 | |
按结果集的行列数不同 | 标量子查询 | 结果集只有一行一列 |
列子查询 | 结果集只有一列多行 | |
行子查询 | 结果集有一行多列 | |
表子查询 | 结果集一般为多行多列 |
1.7.1 where或having后面
1、标量子查询(单行子查询)
2、列子查询(多行子查询)
3、行子查询(多列多行)
特点:
①子查询放在小括号内
②子查询一般放在条件的右侧
③标量子查询,一般搭配着单行操作符使用:< >= <= = <>
列子查询,一般搭配着多行操作符使用:in、any/some、all
④子查询的执行优先于主查询执行,主查询的条件用到了子查询的结果
示例:
1.7.1.1 标量子查询(单行子查询) ☆
# 案例1:谁的工资比 Abel 高?
#①查询Abel的工资
SELECT salary
FROM employees
WHERE last_name = 'Abel';
#②查询员工的信息,满足 salary>①结果
SELECT *
FROM employees
WHERE salary>(
SELECT salary
FROM employees
WHERE last_name = 'Abel'
);
#案例2:返回job_id与141号员工相同,salary比143号员工多的员工 姓名,job_id 和工资
#①查询141号员工的job_id
SELECT job_id
FROM employees
WHERE employee_id = 141;
#②查询143号员工的salary
SELECT salary
FROM employees
WHERE employee_id = 143;
#③查询员工的姓名,job_id 和工资,要求job_id=①并且salary>②
SELECT last_name,job_id,salary
FROM employees
WHERE job_id = (
SELECT job_id
FROM employees
WHERE employee_id = 141
) AND salary>(
SELECT salary
FROM employees
WHERE employee_id = 143
);
#案例3:返回公司工资最少的员工的last_name,job_id和salary
#①查询公司的 最低工资
SELECT MIN(salary)
FROM employees
#②查询last_name,job_id和salary,要求salary=①
SELECT last_name,job_id,salary
FROM employees
WHERE salary=(
SELECT MIN(salary)
FROM employees
);
#案例4:查询最低工资大于50号部门最低工资的部门id和其最低工资
#①查询50号部门的最低工资
SELECT MIN(salary)
FROM employees
WHERE department_id = 50
#②查询每个部门的最低工资
SELECT MIN(salary),department_id
FROM employees
GROUP BY department_id
#③ 在②基础上筛选,满足min(salary)>①
SELECT MIN(salary),department_id
FROM employees
GROUP BY department_id
HAVING MIN(salary)>(
SELECT MIN(salary)
FROM employees
WHERE department_id = 50
);
1.7.1.2 列子查询(多行子查询)★
#案例1:返回location_id是1400或1700的部门中的所有员工姓名
# ①查询location_id是1400或1700的部门编号
SELECT DISTINCT department_id
FROM departments
WHERE location_id IN(1400,1700)
# ②查询员工姓名,要求部门号是①列表中的某一个
SELECT last_name
FROM employees
WHERE department_id IN(
SELECT DISTINCT department_id
FROM departments
WHERE location_id IN(1400,1700)
);
# 或
SELECT last_name
FROM employees
WHERE department_id =ALL(
SELECT DISTINCT department_id
FROM departments
WHERE location_id IN(1400,1700)
);
#案例2:返回其它工种中比job_id为‘IT_PROG’工种任一工资低的员工的员工号、姓名、job_id 以及salary
#①查询job_id为‘IT_PROG’部门任一工资
SELECT DISTINCT salary
FROM employees
WHERE job_id = 'IT_PROG'
#②查询员工号、姓名、job_id 以及salary,salary<(①)的任意一个
SELECT last_name,employee_id,job_id,salary
FROM employees
WHERE salary<ANY(
SELECT DISTINCT salary
FROM employees
WHERE job_id = 'IT_PROG'
) AND job_id<>'IT_PROG';
#或
SELECT last_name,employee_id,job_id,salary
FROM employees
WHERE salary<(
SELECT MAX(salary) # 小于任意一个用max,小于所有用min
# 任意是 all, 任一是 any
FROM employees
WHERE job_id = 'IT_PROG'
) AND job_id<>'IT_PROG';
#案例3:返回其它部门中比job_id为‘IT_PROG’部门所有工资都低的员工 的员工号、姓名、job_id 以及salary
SELECT last_name,employee_id,job_id,salary
FROM employees
WHERE salary<ALL(
SELECT DISTINCT salary
FROM employees
WHERE job_id = 'IT_PROG'
) AND job_id<>'IT_PROG';
#或
SELECT last_name,employee_id,job_id,salary
FROM employees
WHERE salary<(
SELECT MIN( salary)
FROM employees
WHERE job_id = 'IT_PROG'
) AND job_id<>'IT_PROG';
1.7.1.3 行子查询(一行多列或多行多列)
#案例:查询员工编号最小并且工资最高的员工信息
#①查询最小的员工编号
SELECT MIN(employee_id)
FROM employees
#②查询最高工资
SELECT MAX(salary)
FROM employees
#③查询员工信息
SELECT *
FROM employees
WHERE employee_id=(
SELECT MIN(employee_id)
FROM employees
)AND salary=(
SELECT MAX(salary)
FROM employees
);
# 或
SELECT *
FROM employees
WHERE (employee_id,salary)=(
SELECT MIN(employee_id),MAX(salary)
FROM employees
);
1.7.2 select 后面
仅仅支持标量子查询(单行子查询)
示例:
#案例:查询每个部门的员工个数
SELECT d.*,(
SELECT COUNT(*)
FROM employees e
WHERE e.department_id = d.`department_id`
) 个数
FROM departments d;
#案例2:查询员工号=102的部门名
SELECT (
SELECT department_name,e.department_id
FROM departments d
INNER JOIN employees e
ON d.department_id=e.department_id
WHERE e.employee_id=102
) 部门名;
1.7.3 from后面
将子查询结果充当一张表,要求必须起别名
#案例:查询每个部门的平均工资的工资等级
#①查询每个部门的平均工资
SELECT AVG(salary),department_id
FROM employees
GROUP BY department_id
#②连接①的结果集和job_grades表,筛选条件平均工资 between lowest_sal and highest_sal
SELECT ag_dep.*,g.`grade_level`
FROM (
SELECT AVG(salary) ag,department_id
FROM employees
GROUP BY department_id
) ag_dep
INNER JOIN job_grades g
ON ag_dep.ag BETWEEN lowest_sal AND highest_sal;
1.7.4 exists后面(相关子查询)
语法:
exists(完整的查询语句)
结果:
1或0
示例:
#案例1:查询有员工的部门名
#in
SELECT department_name
FROM departments d
WHERE d.`department_id` IN(
SELECT department_id
FROM employees
)
#exists
SELECT department_name
FROM departments d
WHERE EXISTS(
SELECT *
FROM employees e
WHERE d.`department_id`=e.`department_id`
);
1.7.5 练习
# 查询和Zlotkey相同部门的员工姓名和工资
#①查询Zlotkey的部门
SELECT department_id
FROM employees
WHERE last_name = 'Zlotkey'
#②查询部门号=①的姓名和工资
SELECT last_name,salary
FROM employees
WHERE department_id = (
SELECT department_id
FROM employees
WHERE last_name = 'Zlotkey'
);
# 查询工资比公司平均工资高的员工的员工号,姓名和工资。
#①查询平均工资
SELECT AVG(salary)
FROM employees
#②查询工资>①的员工号,姓名和工资。
SELECT last_name,employee_id,salary
FROM employees
WHERE salary>(
SELECT AVG(salary)
FROM employees
);
# 查询各部门中工资比本部门平均工资高的员工的员工号, 姓名和工资
#①查询各部门的平均工资
SELECT AVG(salary),department_id
FROM employees
GROUP BY department_id
#②连接①结果集和employees表,进行筛选
SELECT employee_id,last_name,salary,e.department_id
FROM employees e
INNER JOIN (
SELECT AVG(salary) ag,department_id
FROM employees
GROUP BY department_id
) ag_dep
ON e.department_id = ag_dep.department_id
WHERE salary>ag_dep.ag ;
# 查询和姓名中包含字母u的员工在相同部门的员工的员工号和姓名
#①查询姓名中包含字母u的员工的部门
SELECT DISTINCT department_id
FROM employees
WHERE last_name LIKE '%u%'
#②查询部门号=①中的任意一个的员工号和姓名
SELECT last_name,employee_id
FROM employees
WHERE department_id IN (
SELECT DISTINCT department_id
FROM employees
WHERE last_name LIKE '%u%'
);
# 查询在部门的location_id为1700的部门工作的员工的员工号
#①查询location_id为1700的部门
SELECT DISTINCT department_id
FROM departments
WHERE location_id = 1700
#②查询部门号=①中的任意一个的员工号
SELECT employee_id
FROM employees
WHERE department_id = ANY(
SELECT DISTINCT department_id
FROM departments
WHERE location_id = 1700
);
# 查询管理者是King的员工姓名和工资
#①查询姓名为king的员工编号
SELECT employee_id
FROM employees
WHERE last_name = 'K_ing'
#②查询哪个员工的manager_id = ①
SELECT last_name,salary
FROM employees
WHERE manager_id IN(
SELECT employee_id
FROM employees
WHERE last_name = 'K_ing'
);
# 查询工资最高的员工的姓名,要求first_name和last_name显示为一列,列名为 姓.名
#①查询最高工资
SELECT MAX(salary)
FROM employees
#②查询工资=①的姓.名
SELECT CONCAT(first_name,last_name) "姓.名"
FROM employees
WHERE salary=(
SELECT MAX(salary)
FROM employees
);
1.8 分页查询
应用场景:实际的web项目中需要根据用户的需求提交对应的分页查询的sql语句(当要显示的数据,一页显示不全,需要分页提交sql请求)
语法:
select 查询列表
from 表
【join type】 join 表2
on 连接条件
where 筛选条件
group by 分组字段
having 分组后的筛选
order by 排序的字段】
limit 【offset,】size;
# offset要显示条目的起始索引(起始索引从0开始)
# size 要显示的条目个数
特点:
①limit语句放在查询语句的最后
②公式
要显示的页数 page,每页的条目数size
select 查询列表
from 表
limit (page-1)*size,size;
size=10
page
1 0
2 10
3 20
示例:
#案例1:查询前五条员工信息
SELECT * FROM employees LIMIT 0,5;
SELECT * FROM employees LIMIT 5;
#案例2:查询第11条——第25条
SELECT * FROM employees LIMIT 10,15;
#案例3:有奖金的员工信息,并且工资较高的前10名显示出来
SELECT
*
FROM
employees
WHERE commission_pct IS NOT NULL
ORDER BY salary DESC
LIMIT 10;
1.9 联合查询
引入:union
定义:将多条查询语句的结果合并成一个结果
应用场景:要查询的结果来自于多个表,且多个表没有直接的连接关系,但查询的信息一致时(上下连接,并集)
语法:
select 字段|常量|表达式|函数 【from 表】 【where 条件】 union 【all】
select 字段|常量|表达式|函数 【from 表】 【where 条件】 union 【all】
select 字段|常量|表达式|函数 【from 表】 【where 条件】 union 【all】
.....
select 字段|常量|表达式|函数 【from 表】 【where 条件】
特点:
1、多条查询语句的查询的列数必须是一致的
2、要求多条查询语句的查询的每一列的类型和顺序最好一致
3、union代表去重,union all代表不去重
示例:
# 查询部门编号>90 或 邮箱包含a的员工信息
SELECT * FROM employees WHERE email LIKE '%a%' OR department_id>90;;
SELECT * FROM employees WHERE email LIKE '%a%'
UNION
SELECT * FROM employees WHERE department_id>90;
2. DML 语言
2.1 插入语句
2.1.1 方式一
语法:
insert into 表名(列名,...) values(值1,...);
特点:
1、字段类型和值类型一致或兼容,而且一一对应
2、可以为空的字段,可以不用插入值,或用null填充
3、不可以为空的字段,必须插入值
4、字段个数和值的个数必须一致
5、字段可以省略,但默认所有字段,并且顺序和表中的存储顺序一致
2.1.2 方式二
语法:
insert into 表名
set 列名=值,列名=值,...
2.1.3 比较
1、方式一支持插入多行,方式二不支持
INSERT INTO demo
VALUES(23,'uestc','女','1990-4-23','1898888888',NULL,2)
,(24,'nuc','女','1990-4-23','1898888888',NULL,2);
INSERT INTO demo
SELECT 23,'uestc','女','1990-4-23','1898888888',NULL,2 UNION
SELECT 24,'nuc','女','1990-4-23','1898888888',NULL,2;
2、方式一支持子查询,方式二不支持
INSERT INTO demo(NAME,phone)
SELECT boyname,'1234567'
FROM demo1 WHERE id<4;
INSERT INTO demo(id,NAME,phone)
SELECT 26,'nucc','11809866';
2.2 修改语句
2.2.1 修改单表的记录☆
语法:
update 表名
set 列=新值,列=新值,...
where 筛选条件;
示例:
# 案例1:修改beauty表中姓唐的女生的电话为123456789
UPDATE beauty
SET phone='123456789'
WHERE NAME LIKE '唐%';
# 案例2:修改boys表中id好为2的名字为张飞,魅力值 10
UPDATE boys
SET boyname='张飞' , usercp = 10
WHERE id = 2;
2.2.2 修改多表的记录
语法:
# sql92语法:
update 表1 别名,表2 别名
set 列=值,...
where 连接条件
and 筛选条件;
# sql99语法:
update 表1 别名
inner|left|right join 表2 别名
on 连接条件
set 列=值,...
where 筛选条件;
示例:
# 案例:修改张无忌的女朋友的手机号为119
UPDATE boys bo
INNER JOIN beauty b ON bo.`id`=b.`boyfriend_id`
SET b.`phone`='119'
WHERE bo.`boyName`='张无忌';
2.3 删除语句
2.3.1 方式一:delete
语法:
# 1、单表的删除【★】
delete from 表名 where 筛选条件
# 2、多表的删除【补充】
## sql92语法:
delete 表1的别名,表2的别名
from 表1 别名,表2 别名
where 连接条件
and 筛选条件;
## sql99语法:
delete 表1的别名,表2的别名
from 表1 别名
inner|left|right join 表2 别名 on 连接条件
where 筛选条件;
示例:
#1.单表的删除
##案例:删除手机号以9结尾的女生信息
DELETE FROM beauty WHERE phone LIKE '%9';
##案例:删除表中所有数据
DELETE FROM 表名;
#2.多表的删除
##案例:删除张无忌的女朋友的信息
DELETE b
FROM beauty b
INNER JOIN boys bo ON b.`boyfriend_id` = bo.`id`
WHERE bo.`boyName`='张无忌';
##案例:删除黄晓明的信息以及他女朋友的信息
DELETE b,bo
FROM beauty b
INNER JOIN boys bo ON b.`boyfriend_id`=bo.`id`
WHERE bo.`boyName`='黄晓明';
2.3.2 方式二:truncate
语法:
# 删除表中所有数据
truncate table 表名;
2.3.3 比较
1.delete 可以加where 条件,truncate不能加
2.truncate删除,效率高一丢丢
3.假如要删除的表中有自增长列,
如果用delete删除后,再插入数据,自增长列的值从断点开始,
而truncate删除后,再插入数据,自增长列的值从1开始。
4.truncate删除没有返回值,delete删除有返回值
5.truncate删除不能回滚,delete删除可以回滚.
3. DDL语句
3.1 库的管理
创建、修改、删除
3.1.1 库的创建
语法:
create database [if not exists]库名;
示例:
#案例:创建库Books
CREATE DATABASE IF NOT EXISTS books ;
3.1.2 库的修改
语法:
# 更改库名
RENAME DATABASE 库名 TO 新库名;
# 更改库的字符集
ALTER DATABASE 库名 CHARACTER SET gbk;
3.1.3 库的删除
语法:
DROP DATABASE IF EXISTS books;
3.2 表的管理
创建、修改、删除
3.2.1 表的创建☆
语法:
create table 表名(
列名 列的类型【(长度) 约束】,
列名 列的类型【(长度) 约束】,
列名 列的类型【(长度) 约束】,
...
列名 列的类型【(长度) 约束】
);
示例:
# 案例:创建表Book
CREATE TABLE book(
id INT,#编号
bName VARCHAR(20),#图书名
price DOUBLE,#价格
authorId INT,#作者编号
publishDate DATETIME#出版日期
);
# 查看表结构
DESC book;
常见约束:
NOT NULL
DEFAULT
UNIQUE
CHECK
PRIMARY KEY
FOREIGN KEY
AUTO_INCREMENT
3.2.2 表的修改
语法:
alter table 表名 add|drop|modify|change column 列名 【列类型 约束】;
示例:
# ①修改列名
ALTER TABLE book CHANGE COLUMN publishDate pubDate DATETIME;
# ②修改列的类型或约束
ALTER TABLE book MODIFY COLUMN pubDate TIMESTAMP;
## 案例:向表emp2的id列中添加PRIMARY KEY约束(my_emp_id_pk)
ALTER TABLE emp2 MODIFY COLUMN id INT PRIMARY KEY;
ALTER TABLE emp2 ADD CONSTRAINT my_emp_id_pk PRIMARY KEY(id);
## 案例:向表emp2中添加列dept_id,并在其中定义FOREIGN KEY约束,与之相关联的列是dept2表中的id列。
ALTER TABLE emp2 ADD COLUMN dept_id INT;
ALTER TABLE emp2 ADD CONSTRAINT fk_emp2_dept2 FOREIGN KEY(dept_id) REFERENCES dept2(id);
## 位置 支持的约束类型 是否可以起约束名
## 列级约束: 列的后面 语法都支持,但外键没有效果 不可以
## 表级约束: 所有列的下面 默认和非空不支持,其他支持 可以(主键没有效果)
# ③添加新列
ALTER TABLE book ADD COLUMN press VARCHAR(20);
# ④删除列
ALTER TABLE book DROP COLUMN press;
# ⑤修改表名
ALTER TABLE book RENAME TO books;
3.2.3 表的删除
语法:
DROP TABLE IF EXISTS 表名;
通用的写法:
DROP DATABASE IF EXISTS 旧库名;
CREATE DATABASE 新库名;
DROP TABLE IF EXISTS 旧表名;
CREATE TABLE 表名();
3.3 表的复制
#1.仅仅复制表的结构
CREATE TABLE copy LIKE book;
#2.复制表的结构+数据
CREATE TABLE copy2
SELECT * FROM book;
#只复制部分数据
CREATE TABLE copy3
SELECT id,price
FROM book
WHERE authorId=3;
#仅仅复制某些字段
CREATE TABLE copy4
SELECT id,price
FROM book
WHERE 0;
3.4 常见约束
含义:一种限制,用于限制表中的数据,为了保证表中的数据的准确和可靠性
分类:六大约束
-
NOT NULL
:非空,用于保证该字段的值不能为空,比如姓名、学号等 -
DEFAULT
:默认,用于保证该字段有默认值,比如性别 -
PRIMARY KEY
:主键,用于保证该字段的值具有唯一性,并且非空, 比如学号、员工编号等 -
UNIQUE
:唯一,用于保证该字段的值具有唯一性,可以为空,比如座位号 -
CHECK
:检查约束【mysql中不支持】,比如年龄、性别 FOREIGN KEY
:外键,用于限制两个表的关系,用于保证该字段的值必须来自于主表的关联列的值
- 在从表添加外键约束,用于引用主表中某列的值
- 比如学生表的专业编号,员工表的部门编号,员工表的工种编号
添加约束的时机:
- 创建表时
- 修改表时
约束的添加分类:
- 列级约束:六大约束语法上都支持,但外键约束没有效果
- 表级约束:除了非空、默认,其他的都支持
主键约束和唯一约束的对比:
保证唯一性 | 是否允许为空 | 一个表是否可以一多个 | 是否允许组合 | |
主键 | √ | × | 至多1个 | √,但不推荐 |
唯一 | √ | √ | 可以有多个 | √,但不推荐 |
外键:
1、要求在从表设置外键关系
2、从表的外键列的类型和主表的关联列的类型要求一致或兼容,名称无要求
3、主表的关联列必须是一个key(一般是主键或唯一)
4、插入数据时,先插入主表,再插入从表;删除数据时,先删除从表,再删除主表