MySQL:
基础:
好处:
1.实现数据持久化
2.使用完整的管理系统统一管理,易于查询
DB:
数据库(database):存储数据的“仓库”,保存了一系列有组织的数据
DBMS:
数据库管理系统(DatabaseManagementSystem),数据库是通过DBMS创建和操作的容器
SQL:
结构化查询语言(StructureQueryLanguage):专门用来与数据库通信的语言;每条SQL语句都用;结尾
优点:
1.不是某个特定数据库供应商专有的语言,几乎所有DBMS都支持SQL
2.简单易学
3.虽然简单,但实际上是一种强有力的语言,灵活使用其他语言元素,可以进行非常复杂和高级的数据库操作
数据库的特点:
1.将数据放到表里,表再放到库里
2.一个数据库中可以有多个表,每个表都有一个名字,用来标识自己,表名具有唯一性
3.表具有一些特性,这些特性定义了数据在表中如何存储,类似java中“类”的设计
4.表由列组成,称为字段,所有表都是由一个或者多个列组成,每一列相当于java中的”属性“
5.表中的数据是按行存储的,每一行类似于java中的”对象“
DBMS分为两类:
1.基于共享文件系统的DBMS(Access)
2.基于客户机–服务器(C/S)的DBMS(MySQL、Oracle、SqlServer)
MySQL的常见命令:
show database:显示数据库
use 库名:进入该数据库
show tables:显示表
show tables from 库名:显示特定库中的表
select database():显示现在所在的数据库
create table 表名:创建表 (id int)列名 列类型
desc 表名:显示表的结构
select version():显示数据库的版本
DQL语言查询:
基础查询:
语法:
select 查询列表 from 表 ;
特点:
查询列表可以是表中的字段;常量;常量值;表达式;函数
查询的结果是一个虚拟的表格
USE myemployees;//先打开特定的数据库,再进行查询
1.查询表中的单个字段:
SELECT last_name FROM employees;
2.查询表中的多个字段:
SELECT last_name,salary,email FROM employees;
3.查询表中的所有字段:
SELECT * FROM employees;(或者双击字段名加,即可)
注意:当要查询的字段和关键字重名时加上``增强可读性,一般要查询的字段尽量都加上,避免出现
4.查询常量值:
SELECT 100;
SELECT ‘john’;
5.查询表达式:
SELECT 100%9;
6.查询函数:
SELECT VERSION();
7.起别名:
//便于理解
//如果要查询的字段有重名的情况,使用别名可以区分开来
方式一:使用as
SELECT 100%98 AS 结果;
SELECT last_name AS 姓 ,first_name AS 名 FROM employees;
方式二:使用空格
SELECT last_name 姓 FROM employees;
特殊情况:当别名中有特殊符号(空格 #号 关键字)时,给别名加上”“即可
SELECT salary “out put” FROM employees;
8.去重:
//在 字段名前加上 DISTINCT
SELECT DISTINCT department_id FROM employees;
9.+号的作用
//mysql中的+号只有一个功能:运算符
//select 100+90 ;//两个操作数都为数值型,则做加法运算
//select ‘123’ +90;//其中一方为字符型,试图将字符型数值转换成数值型,如果转换成功,则继续做加法;
//select ‘john’+ 90;//如果转换失败则将字符型数值转换成0;//90
//select null + 0;//只要其中一方为null,结果肯定为null;
10.CONCAT 拼接字符串
SELECT CONCAT(‘a’ ,‘b’,‘c’) AS 姓名 FROM employees;
//查询员工名和姓名连接成一个字段,并显示为姓名
SELECT CONCAT(last_name,first_name) AS 姓名 FROM employees;
IFNULL(commission_pct,0) //逗号前一个表示这个字段可能为null,后一个表示如果为null后表示的值就是0;
条件查询:
SELECT 查询列表 FROM 表名 WHERE 筛选条件
分类:
1.按条件表达式筛选(条件运算符: > < = <>不等于 <= >=)
2.按逻辑表达式筛选(逻辑运算符:&& ! || and or not)[用于连接条件表达式]
3.模糊查询(like between and in is null)
1.条件表达式筛选
案例一:查询工资>12000的员工信息
SELECT * FROM employees WHERE salary >12000;
案例二:查询部门编号不等于90号的员工名和部门编号
SELECT last_name, department_id FROM employees WHERE department_id <>90;
2.按逻辑表达式筛选
案例一:查询工资在10000到20000之间的员工名、工资以及奖金
SELECT last_name,salsry,commission_pct FROM employees WHERE salary >=10000 AND salary<=20000;
案例二:查询部门编号不是在90到110之间,或者工资高于15000的员工信息
SELECT * FROM employees WHERE department_id<90 AND department_id>110 OR salary>15000;
SELECT * FROM employees WHERE NOT(department_id>=90 AND department_id<=110) OR salary>15000;
3.模糊查询:
like;between and; in;is full/is not full
通配符:
% 任意多个字符,包含0个字符
_ 任意单个字符
1.like:(可以判断字符型和数值型)
案例一:查询员工名中包含字符a的员工信息
SELECT * FROM employees WHERE last_name LIKE ‘%a%’😭%表示通配符,就是不确定那个位置上是a)
案例二:查询员工名中第三个字符为e,第五个字符为a的员工名和工资
SELECT last_name,salary FROM employees WHERE last_name LIKE ‘__e_a%’;
案例三:查询员工名中第二个字符为_的员工名
SELECT last_name FROM employees WHERE last_name LIKE ‘’;//在两个_中间加上转义字符\或者随意定义一个字符$ 在后面再加上 ESCAPE '$'即可;
2.between and:
使用between and 可以提高语句的简洁度
包括临界值
两个临界值不能调换
案例一:查询员工编号在100到120之间的员工信息
SELECT * FROM employees WHERE employee_id BETWEEN 100 AND 120;
3.in:
用于判断某字段的值是否属于in列表中的某一项
提高语句简洁度
in列表的值类型必须一致或者兼容
in列表中必须是明确的值,不能用通配符表示
案例:查询员工的工种编号是 IT_PROG、AD_VP、AD_PRES中的一个员工名和工种编号
SELECT last_name ,job_id FROM employees WHERE job_id IN (‘IT_PROG’ ,‘AD_VP’ , ‘AD_PRES’);
4.is null:(仅能判断null值,可读性高)
= 或者 <> 不能用于判断null值要用 is null 或者 is not null;
案例:查询没有奖金的员工名和奖金率
SELECT last_name,commission_pct FROM employees WHERE commission_pct IS NULL;
补充:安全等于 (<=>)(既可以判断null值又可以判断普通的数值,可读性差)
案例1:查询没有奖金的员工名和奖金率
SELECT last_name,commission_pct FROM employees WHERE commission_pct <=> NULL;
案例2:查询工资为12000的员工信息
SELECT last_name,commission_pct FROM employees WHERE salary <=> 12000;
排序查询:
SELECT 查询列表 FROM 表 [WHERE 筛选条件] ORDER BY 排序列表 [asc(升序/desc(降序)];如果不写默认升序
案例1:查询员工信息,工资从高到底排序
select * FROM employees ORDER BY salary DESC;
案例2:查询部门编号>=90的员工信息,按入职时间的先后进行排序
SELECT * FROM employees WHERE department_id >=90 ORDER BY hiredate ASC;
案例3:按年薪的高低显示员工的信息和年薪[按表达式排序]
SELECT *,salary乘以12 乘以(1+IFNULL(commission_pct,0)) AS 年薪 FROM employees ORDER BY salary乘以12 乘以(1+IFNULL(commission_pct,0));
案例4:按年薪的高低显示员工的信息和年薪[按别名排序]
SELECT *,salary乘以12 乘以(1+IFNULL(commission_pct,0)) AS 年薪 FROM employees ORDER BY salary乘以12 乘以(1+IFNULL(commission_pct,0)) DESC;
SELECT *,salary乘以12 乘以(1+IFNULL(commission_pct,0)) AS 年薪 FROM employees ORDER BY 年薪 DESC;
案例5:按姓名的长度显示员工的姓名和工资[按函数排序]
SELECT LENGTH(last_name) AS 字节长度,last_name,salary FROM
employees ORDER BY LENGTH(last_name) DESC;
案例6:查询员工信息,要求按工资升序,再按员工编号降序[按多个字段排序]
SELECT * FROM employees ORDER BY salary ASC ,employee_id DESC;
ORDER BY : asc 代表升序,desc代表降序,如果不写默认升序,order by 子句中可以支持单个字段、多个字段、表达式、函数、别名 ,一般放在查询语句的最后面
常见函数:
1.单行函数:
函数(概念):类似于java中的方法:将一组逻辑语句封装在方法体中,对外暴露方法名
好处:1.隐藏了实现的细节2.提高代码的重用性
调用:SELECT 函数名(实参列表) [FROM 表];
分类:
1.单行函数: concat、length、ifnull
字符函数、数学函数、日期函数、其他函数、流程控制函数
2.分组函数:做统计使用,又称统计函数
字符函数:
1.length :获取参数值的字节个数
SELECT LENGTH(‘john’);//4
2.concat:拼接字符串
SELECT CONCAT(last_name, ‘_’,frist_name) AS 姓名 FROM employees;
3.upper、lower:大小写转化
SELECT UPPER(‘john’);
4.substr:截取字符[索引从1开始]
SELECT SUBSTR (‘李莫愁爱上了陆展元’,7) AS ‘out_put’;//陆展元
案例:姓名中首字符大写,其他字符小写然后用_拼接,显示出来
SELECT CONCAT(UPPER(SUBSTR(last_name,1,1)),’_’ ,LOWER(SUBSTR(last_name,2))) AS out-put FROM employees
5.instr:返回字串的首个索引,如果找不到返回0
SELECT INSTR(‘杨不悔爱上了殷六侠’,‘殷六侠’) AS out-put ;//7
6.trim:去前后空格[数据库中一个子占三个字节]
SELECT LENGTH(TRIM(’ 张翠山 '))AS out-put;//9
SELECT TRIM(‘aa’ FROM ‘aaaaaa张aa翠山aaaa’) AS out-put;//张aa翠山(看成整体)
7.Lpad:用指定的字符实现左填充指定长度
SELECT LPAD(‘殷素素’,10,’ ′ ) A S o u t − p u t ; / / ') AS out-put;// ′)ASout−put;//$$$$$$殷素素(指定长度小于原有长度,从右边截断)
8.Rpad:用指定的字符实现右填充指定长度
SELECT RPAD(‘殷素素’,10,‘ab’) AS out-put;
9.replace :替换
SELECT REPLACE(‘张无忌爱上了周芷若’,‘周芷若’,‘赵敏’) AS out-put;
数学函数:
1.round:四舍五入
SELECT ROUND(1.65);//2
SELECT ROUND(1.567,2)//小数点后保留2位
2.ceil:向上取整,返回>=该参数的最小整数
SELECT CEIL(1.002);//2
3.floor:向下取,整返回<=该参数的最大整数
SELECT FLOOR(1.65);//1
4.truncate:截断
SELECT TRUNCATE(1.69999,1);//1.6(小数点后保留一位)
5.mod:取余
mod(a,b): a-a/b*b;
SELECT MOD(10,3);//1
日期函数:
1.now:返回当前系统日期
SELECT NOW();
2.curdate:返回当前系统日期,不包含时间
SELECT CURDATE();
3.curtime:返回当前时间,不包含日期
SELECT CURTIME();
4.获取指定的部分,年、月、日、小时、分钟、秒
SELECT YEAR(NOW());// 年;
SELECT YEAR(hiredata) AS 年 FROM employees;
5.str_to_date:将字符通过特定的格式转换成日期
SELECT STR_TO_DATE(‘1998-3-2’,’%Y-%c-%d’) AS out-put;//1998-3-2
案例:查询入职日期为1992-4-3的员工信息
SELECT * FROM employees WHERE hiredate = STR_TO_DATE(‘4-3 1992’,’%c-%d %Y’);
6.date_format:将日期转换称字符
SELECT DATE_FORMATE(NOW(),’%y年%m月%d日’) AS out-put;
案例:查询有奖学金的员工和入职日期(xx月/xx日/xx年)
SELECT last_name,DATE_FORMAT(hiredate,’%m月/%d日 %y年’) AS 入职日期 FROM employees WHERE comission_pct IS NOT NULL;
其他函数:version();database();user()
流程控制函数:
1.if函数:if else 的效果
SELECT IF(10>5,‘大’,‘小’);
SELECT last_name,commision_pct,IF(comission_pct IS NULL,‘没奖金,呵呵’,‘有奖金’)
2.case函数:
switch case 的效果
switch(变量){
case 常量一: 语句1;break;
…
default:语句;break;
}
第一种case(准确的值) : case 要判断的字段或表达式 when 常量1 then 要显示的值1或者语句1;… else 要显示的值n或者语句n;(语句+分号,值不+)
案例:查询员工的工资,要求 部门号=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;
第二种case:(区间判断)
case
when 条件1 then 要显示的值1或语句1
when 条件2 then 要显示的值2或语句2
…
else 要显示的值n或者语句n
end
案例:查询员工的工资情况
如果工资>20000,显示A级别
如果工资>15000,显示B级别
如果工资>10000,显示C级别
否则,显示D级别
SELECT salary,
CASE
WHEN salary>20000 THEN ‘A’
WHEN salary>15000 THEN ‘B’
WHEN salary>10000 TNEN ‘C’
ELSE ‘D’
END AS 工资级别
FROM employees;
2.分组函数:
用于统计使用,又称聚合函数
特点:
sum、avg一般用于处理数值型
max、min、count可以处理任何类型
以上分组函数都忽略null值
可以和关键字搭配使用(distinct)
SELECT SUM(DISTINCT salary) , SUM(salary) FROM employees;
count函数的详细介绍
SELECT COUNT(*) FROM employees;//查询表里所有的行数(只要一行中有一个列不为null就算一行)
SELECT COUNT(1) FROM employees;//相当于在最前面的列的前面在加上一列1,所以还是等于总行数
count括号中加上任意一个常量值,相当于在表中加上了一列那个常量值,所以返回的还是总行数
一般count(*)效率高于count(字段),因为里面如果是字段的话,还要判断该字段是否为null
和分组函数一同查询的字段要求是group by 后的字段
分类:sum:求和;avg:平均值;max:最大值;min:最小值;count:计算个数
1.简单使用
SELECT SUM(salary) FROM employees;//工资之和
SELECT COUNT(salary) FROM employees;//非空的值有几个
2.连续使用
SELECT SUM((salary) 和,AVG(salary) 平均,MAX(salary) 最高,MIN(salary) 最低,COUNT(salary) 个数) FROM employees;
DATEDIFF(日期1,日期2)//表示两个日期相差的天数
SELECT DATEDIFF(MAX(hiredate),MIN(hiredate)) AS DIFFRENCE FROM employees;
分组查询:
特点:
1.分组查询种的筛选条件分为两类
分组前筛选 原始表 group by 子句的前面 where
分组后筛选 分组后的结果集 group by 子句的后面 having
分组函数做条件肯定放在having子句中
能用分组前筛选的,就优先考虑使用分组前筛选
group by子句支持单个字段分组,多个字段分组(多个字段之间用逗号隔开,没有顺序要求),也可添加排序,放在最后
方法:找每个后面的就是要group by 的列
SELECT 分组函数 ,列(要求出现在group by 的后面)
FROM 表
[WHERE 筛选条件]
GROUP BY 分组的列表
[ORDER BY 子句]
注意:列表必须要特殊,要求是分组函数和group by 后面出现的字段
案例1:查询每个工种的最高工资
SELECT MAX(salary),job_id
FROM employees
GROUP BY job_id;
案例2:查询每个位置上的部门个数
SELECT COUNT(*),location_id
FROM departments
GROUP BY location_id;
添加分组前的筛选条件
案例3:查询邮箱中包含a字符的,每个部门的平均工资
SELECT AVG(salary),department_id
FROM employees
WHERE email LIKE ‘%a%’
GROUP BY department_id;
案例4:查询有奖金的每个领导手下员工的最高工资
SELECT MAX(salary),manage_id
FROM employees
WHERE comission_pct IS NOT NULL
GROUP BY manage_id;
添加分组后的筛选条件
案例1:查询哪个部门的员工个数>2
SELECT COUNT(*),department_id
FROM employees
GROUP BY department_id
HAVING COUNT(*)>2;
案例2:查询每个工种有奖金的员工的最高工资>12000的工种编号和最高工资
SELECT MAX(salary),job_id
FEOM employees
WHERE commision_pct IS NOT NULL
GROUP BY job_id
HAVING MAX(salary) >12000;
案例3:查询领导编号>102的每个领导手下的最低工资>5000的领导编号是哪个,以及其最低工资
SELECT MIN(salary),manage_id
FROM employees
WHERE department_id>102
GROUP BY manage_id
HAVING MIN(salary) >5000;
按表达式或函数分组
案例:按员工姓名的长度分组,查询每一组的员工个数,筛选员工个数>5的有哪些
SELECT COUNT(*),LENGTH(last_name)
FROM employees
GROUP BY LENGTH(last_name)
HAVING COUNT(*)>5;
按多个字段分组
案例:查询每个部门每个工种的员工的平均工资
SELECT AVG(salary),department_id,job_id
FROM employees
GROUP BY department_id,job_id;
添加排序
案例:查询每个部门每个工种的员工的平均工资,并且按平均工资的高低显示
SELECT AVG(salary),department_id,job_id
FROM employees
WHERE department_id IS NOT NULL
GROUP BY department_id,job_id;
HAVING AVG(salary)>10000
ORDERE BY AVG(salary) DESC;
group by order by having 都支持起别名
连接查询:
多表查询,当查询的字段来自于多个表时,就会用到连接查询
笛卡尔乘积现象:表1有m行,表2有n行,结果=m*n行
原因:没有有效的连接条件
避免:添加有效的连接条件
分类:
按年代分类:sql92标准(仅支持内连接);sql99标准
按功能分类:内连接(等值连接,非等值连接,自连接),外连接(左外连接,右外连接,全外连接),交叉连接
外连接特点:
1.查询的结果=主表中所有的行,如果从表和它匹配的将显示匹配行,如果从表没有匹配的则显示null
left join:左边的是主表,right join :右边的是主表
full join :两边都是主表,一般用于查询除了交集部分的剩余的不匹配的行
SELECT name,boyName FROM boys,beauty
WHERE beauty.boyfriend_id = boys.id;//这句就是添加连接条件
等值连接:
1.多表等值连接的结果为夺标的交集部分
2.n表连接,至少需要n-1个连接条件
3.多表的顺序没有要求
4.一般需要为表起别名
5.可以搭配排序,分组,筛选
sql92标准:
案例一:查询女生名和对应的男生名
SELECT name,boyName
FROM boys,beauty
WHERE beauty.boyfriend_id = boys.id;
案例二:查询员工名和对应的部门名
SELECT last_name,department_name
FROM employees,departments
WHERE employees.department_id = departments.department_id;
案例三:查询员工名、工种号、工种名(为表起别名,方便SQL语句的编写,区分多个重名的字段)
注意:如果为表起了别名,则查询的字段就不能在使用原来的表名去限定;两个表的顺序可以调换
SELECT last_name,e.job_id,job_title
FROM employees AS e,jobs AS j
WHERE e.job_id = j.job_id;
添加筛选
案例1:查询有奖金的员工名、部门名
SELECT last_name,department_id
FROM employees e,departments d
WHERE e.department_id = d.department_id
AND commision_pct IS NOT NULL;
案例2:查询城市名中第二个字符为o的部门名和城市名
SELECT department_id,city
FROM departments d,locations l
WHERE d.location_id = l.location_id
AND city LIKE ‘_o%’;
添加分组
案例1:查询每个城市的部门个数
SELECT COUNT(*) 个数 ,city
FROM locations l,departments d
WHERE l.location_id = d.location_id
GROUP BY city;
案例2:查询有奖金的每个部门的部门名和部门的领导编号和该部门的最低工资
SELECT department_name ,d.manager_id ,MIN(salary)
FROM departments d ,employees e
WHERE commision_pct IS NOT NULL
AND d.department_id = e.department_id
GROUP BY department_name,d.manager_id;
添加排序
案例:查询每个工种的工种名和员工的个数,并且按员工个数降序
SELECT job_title,COUNT(*)
FROM jobs j,employees e
WHERE j.job_id = e.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 e.location_id = l.location_id
AND city LIKE ‘s%’;
非等值连接:
案例1:查询出员工的工资和工资级别
SELECT salary,grade_level
FROM employees e,job_grades g
WHERE salary BETWEEN g.lowest_sal AND g.highest_sal;
自连接:
所要查询的内容在一张表中
案例:查询 员工名和上级的名称
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;
sql99语法:
特点:
1.添加排序、分组、筛选
2.inner 可以省略
3.筛选条件放在where后面,连接条件放在on后面,便于阅读
4.inner join 连接和sql92语法中的等值连接效果一样,都是查询多表的交集
SELECT 查询列表
FROM 表1 别名 [连接类型]
join 表2 别名
on 连接条件
[where 筛选条件]
[group by 分组]
[having 筛选条件]
[order by 排序列表]
分类:
内连接:inner
外连接:
左外:left(outer)
右外:right(outer)
全外:full(outer)
交叉连接:cross
1.内连接:
SELECT 查询列表
FROM 表1 别名
INNER JOIN 表2 别名
ON 连接条件;
分类:等值连接,内连接,自连接
一:等值连接
案例1:查询员工名、部门名
SELECT last_name ,department_name
FROM employees e
INNER JOIN employees m
ON e.employee_id = m.employee_id;
案例2:查询名字中包含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:查询部门个数>3的城市名和部门个数
SELECT city,COUNT(*)
FROM departments d
INNER JOIN locations l
ON d.location_id = l.location_id
GROUP BY city
HAVING COUNT(*)>3;
案例4:查询哪个部门的员工个数>3的部门和员工个数,并按个数降序
SELECT department_name,COUNT(*)
FROM employees e
INNER JOIN departments d
ON e.department_id = d.department_id
WHERE COUNT(*)>3
GROUP BY d.department_name
ORDER BY COUNT(*) DESC;
案例5:查询员工名、部门名、工种名、并按部门名降序
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 d.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.hight_sal;
查询工资级别的个数>2的个数,并且按工资级别降序
SELECT salary,grade_level,COUNT(*)
FROM employees e
JOIN job_grades g
ON e.salary BETWEEN g.lowest_sal AND g.hight_sal;
GROUP BY grade_level
HAVING COUNT(*)>2
ORDER BY grade_level DESC;
自连接:
查询员工的名字、上级的名字
SELECT last_name,manager_name
FROM employees e
JOIN employees m
ON e.manager_id = m.employee_id;
外连接:
用于查询一个表中有的,另一个表没有的
特点:
1.外连接的查询结果为主表中的所有记录
如果从表中有和它匹配的,则显示匹配的值
如果从表中没有和它匹配的,则显示null
外连接查询结果 = 内连接结果+主表中有而从表没有的记录
2.左外连接left join左边的是主表
右外连接right join 右边的是主表
3.左外和右外交换两个表的顺序,可以实现同样的效果
案例:查询男朋友不在男生表的女生名
SELECT b.name,bo.*
FROM beauty b
LEFT OUTER JOIN boys bo
ON b.boyfriend_id = bo.id
WHERE bo.id IS NULL;
案例:查询哪个部门没有员工
左外:
SELECT d.*,e.department_id
FROM departments d
LEFT OUTER JOIN employees e
ON d.department_id = e.department_id
WHERE e.department_id IS NULL;
全外连接(mysql不支持):
全外连接=内连接结果+表1中有但表2中没有的+表2中有但表1中没有的
交叉连接:
SELECT b.*,bo.星
FROM beauty b
CROSS JOIN boys bo;//笛卡尔乘积
子查询:
含义:出现在其他语句的select语句,称为子查询或内查询,外部的查询语句,称为主查询或外查询
分类:
按子查询出现的位置:
select后面(标量子查询)
from后面(表子查询)
where或having后面(标量子查询,列子查询)
exists后面(相关子查询)(表子查询)
按结果集的行列数不同:
标量子查询(结果集只有一行一列)
列子查询(结果集只有一列多行)
行子查询(结果集有一行多列)
表子查询(结果集一般为多行多列)
一.where或having后面
1:标量子查询(单行子查询)
2:列子查询
3.行子查询
特点:
1.子查询放在小括号内
2.子查询一般放在条件右侧
3.标量子查询,一般搭配着单行操作符使用(> < >= <=)
列子查询,一般搭配着多行操作符使用(in all any/some)
4.子查询的执行优先于主查询执行,主查询的条件用到了子查询的结果
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
第三步:
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 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 department_id,MIN(salary)
FROM employees
GROUP BY department_id
第三步:
SELECT department_id ,MIN(salary)
FROM employees
GROUP BY department_id
HAVING salary>(
SELECT MIN(salary)
FROM employees
WHERE department_id = 50
)
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)
);
案例2:返回其他工种比job_id为‘IT_PROG’部门任一工资低的员工的:工号、姓名、job_id以及salary
第一步:查询job_id为’IT_PROG’部门的所有工资
SELECT salary
FROM employees
WHERE job_id = ‘IT_PROG’
第二步:
SELECT employee_id,last_name,job_id,salary
FROM employees
WHERE salary < ANY(
SELECT salary
FROM employees
WHERE job_id = ‘IT_PROG’
)
AND job_id <> ‘IT_PROG’;
3.行子查询:
案例1:查询员工编号最小并且 工资最高的员工信息
第一步:查询最小的员工编号
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 MIN(employee_id)
FROM employees
);
2.select后面
案例:查询每个部门的员工个数(在部门表最后一列加上个数)
SELECT d.*,(
SELECT COUNT(*)
FROM employees e
WHERE d.department_id = e.department_id
) 个数
FROM department d;
案例2:查询员工号=102的部门名
SELECT (
SELECT department_name
FROM employees e
INNER JOIN departments d
ON e.department_id = e.department_id
WHERE employee_id = 102
);
3.from后面
案例:查询每个部门的平均工资的工资等级
第一步:查询每个部门的平均工资(在第一步查询后的结果集在加上一列工资等级) 注意:表子查询必须起别名
SELECT AVG(salary) department_id
FROM employees
GROUP BY department_id
第二步:
SELECT ag_dep.*,grade_level
FROM (
SELECT AVG(salary) ag department_id
FROM employees
GROUP BY department_id
) ag_dep
INNER JOIN job_grade g
ON ag_dep.ag BETWEEN lowest_sal AND hight_sal;
exists后面(相关子查询) 是否存在
SELECT EXISTS(SELECT employee_id FROM employees) //1 括号中如果有值返回1如果没值返回0
案例1:查询有员工的部门名
SELECT department_name
FROM departments d
WHERE EXISTS(
SELECT *
FROM employees e
WHERE e.department_id = d.department_id
);
案例2:查询没有女朋友的男生信息
in:
SELECT bo.*
FROM boys bo
WHERE bo.id NOT IN (
SELECT boyfriend_id
FROM beauty
);
exists:
SELECT bo.*
FROM boys bo
WHERE NOT EXISTS(
SELECT boyfriend_id
FROM beauty b
WHERE bo.id = b.boyfriend_id
);
经典案例:
查询个部门中工资比本部门平均工资高的员工的员工号,姓名和工资
1.查询各部门的平均工资
SELECT AVG(salary) ,department_id
FROM employees
GROUP BY department_id
2.连接1结果和employees表,进行筛选
SELECT employee_id,last_name,salary
FROM employees e
INNER JOIN (
SELECT AVG(salary) ag ,department_id
FROM employees
GROUP BY department_id
) ag_dep
ON ag_dep,department_id = e.department_id
WHERE salary>ag_dep.ag;
2.查询所有学员的邮箱的用户名(邮箱中@前面的字符)
SELECT SUBSTR(email,1,instr(email,’@’)-1) 用户名
FROM stuinfo;
案例3:查询平均工资最低的部门信息
方法一:
1.查询个部门的平均工资
SELECT AVG(salary),department_id
FROM employees
GROUP BY department_id
2.查询平均工资最低的部门
SELECT MIN(ag)
FROM (
SELECT AVG(salary) ag,department_id
FROM employees
GROUP BY department_id
) ag_dep
3.查询哪个部门的平均工资等于2
SELECT department_id,AVG(salary)
FROM employees
GROUP BY department_id
HAVING AVG(salary) = (
SELECT MIN(ag)
FROM (
SELECT AVG(salary) ag,department_id
FROM employees
GROUP BY department_id
) ag_dep
)
4.查询部门的信息
SELECT d.*
FEOM departments d
WHERE department_id = (
SELECT department_id,AVG(salary)
FROM employees
GROUP BY department_id
HAVING AVG(salary) = (
SELECT MIN(ag)
FROM (
SELECT AVG(salary) ag,department_id
FROM employees
GROUP BY department_id
) ag_dep
)
)
方法二:
1.各部门的平均工资
SELECT AVG(salary),department_id
FROM employees
GROUP BY department_id
2.将1查询到的结果按升序排列然后分页只要最小的哪个
SELECT department_id
FROM employees
GROUP BY department_id
ORDER BY AVG(salary)
LIMIT 1;
3.查询信息
SELECT d.*
FROM departments d
WHERE department_id = (
SELECT department_id
FROM employees
GROUP BY department_id
ORDER BY AVG(salary)
LIMIT 1;
)
案例4:查询平均工资最高的job信息
1.查询最高的job平均工资
SELECT AVG(salary),job_id
FROM employees
GROUP BY job_id
ORDER BY AVG(salary) DESC
LIMIT 1;
2.查询Job的信息
SELECT *
FROM jobs
WHERE job_id =(
SELECT AVG(salary),job_id
FROM employees
GROUP BY job_id
ORDER BY AVG(salary) DESC
LIMIT 1;
)
案例5:查询出公司所有manager的详细信息
1.查询所有manager的员工编号
SELECT manager_id
FROM employees
2.查询详细信息
SELECT *
FROM employees
WHERE employee_id =(
SELECT manager_id
FROM employees
)
分页查询:
特点:
limit语句放在查询语句的最后
公式:
page:要显示的页数page,每页的条目数size
select 查询列表
from 表
limit (page-1)*siaze,size;
应用场景:要显示的数据一页显示不全,需要分页提交sql请求
SELECT 查询列表
FROM 表
[JOIN type] JOIN 表2
ON 连接条件
WHERE 筛选条件
GROUP BY 分组字段
HAVING 分组后的筛选
ORDER BY 排序的字段
LIMIT OFFSET, SIZE;
offset:要显示条目的起始索引(起始索引从0开始)
size:要显示的条目个数
案例1:查询前五条员工信息
SELECT *
FROM employees
LIMIT 0,5;
案例2:查询第11条到25条
SELECT *
FROM employees
LIMIT 10,15;
案例3:有奖金的员工信息,并且工资较高的前10名显示出来
SELECT COUNT(*),salary
FROM employees
WHERE commision_pct IS NOT NULL
ORDER BY salary DESC
LIMIT 10;
联合查询:
语法:
查询语句1
union
查询语句2
union
查询语句3
…
应用场景:
要查询的结果来自于多个表,且多个表没有直接的连接关系,但查询的信息一致
特点:
1.要求多条查询语句的查询列数是一致的
2.要求多条查询语句的查询的每一列的类型和顺序最好一致
3.union关键字默认去重,如果使用union all 可以包含重复项
union :联合,合并 将多条查询语句的结果合并成一个结果
案例:查询部门编号>90或者邮箱包含a的员工信息
SELECT * FROM employees
WHERE emai LIKE ‘%a%’
UNION
SELECT * FROM department_id>90;
DML语言(插入,修改,删除):
1.插入语句(insert)
方式一:
语法:
insert into 表名(列名1, …)
values(值1, …);
1.插入的值的类型要与列的类型一致或兼容
2.不可以为null的列必须要插入值,可以为null的列 可以插入null或者不写
3.列的顺序可以调换
4.列数和值数要一致
5.可以省略列名,默认所有列,而且列的顺序和表中的顺序一致
INSERT INTO beauty(id,name,sex,borndate,phone,photo,boyfriend_id)
VALUES(13,‘唐艺昕’,‘女’,‘1990-4-23’,‘18988888888’,null,2);
方式二:
语法:
insert into 表名
set 列名=值,列名=值…
INSERT INTO beauty
SET id=19,name=‘刘焘’;
两种方式比较:
1.方式一支持插入多行,方式二不支持
insert into beauty
values(…),
values(…);
2.方式一支持子查询,方式二不支持
INSERT INTO beauty(id,name,phone)
SELECT 26,‘宋茜’,‘124343435’
//先查询下面一条信息然后再插入到表里
2.修改语句(update)
1.修改单表的记录
语法:
update 表名
set 列=新值,列=新值,…
where 筛选条件;
案例1:修改beauty表中姓唐的女生电话为12345678912
UPDATE beauty
SET photo = ‘1234567812’
WHERE name LIKE ‘%唐%’;
案例2:修改boys表中Id为2的名称为张飞,魅力值为10
UPDATE boys
SET boyname = ‘张飞’,usercp= 10
WHERE id = 2;
2.修改多表的记录
语法:
sql92语法
update 表1 别名 ,表2 别名
set 列=值, …
where 连接条件
and 筛选条件
sql99语法
update 表1 别名
inner/left/right join 表2 别名
on 连接条件
set 列=值,…
where 筛选条件
案例1:修改张无忌的女朋友的手机号为12345678912
UPDATE boys bo
INNER JOIN beauty b
ON b.boyfriend_id = bo.id
SET b.photo = ‘12345678912’;
WHERE bo.boyName = ‘张无忌’;
案例2:修改没有男朋友的女生的男朋友编号都为2
UPDATE boys bo
RIGHT JOIN beauty b
ON b.boyfriend_id = bo.id
SET B.boyfriend_id = 2
WHERE b.boyfriend_id = NULL;
3.删除语句
单表删除
方式一:delete
语法:
delete from 表名 where 筛选条件
方式二:
语法:
truncate table 表名;
多表删除
语法(sql99):
delect 表1的别名 ,表二的别名(删除那张表的信息就写那张表,都写就都删)
from 表1 别名
inner/right/left join 表2 别名 on 连接条件
where 筛选条件
方式一:delect语句
单表删除
案例:删除手机号以9结尾的女生信息
DELECT FROM beauty WHERE photo LIKE ‘%9’;
多表删除
案例:删除张无忌的女朋友的信息
DELECT b
FROM beauty b
INNER JOIN boys bo
ON b.boyfriend_id = bo.id
WHERE b.boyName = ‘张无忌’;
案例:删除黄晓明的信息和他女朋友的信息
DELECT b,bo
FROM boys bo
INNER JOIN beauty b
ON b.boyfriend_id = bo.id
WHERE b.boyName = ‘黄晓明’;
方式二:truncate语句
注意:truncate不可加where语句
区别:
1.delect可以加where条件,truncate不可以
2.truncate删除效率高一些
3.假如要删除的表中有自增长列,再插入数据,自增长列的值从断点开始,而truncate删除后,再插入数据,自增长列的值从1开始
4.truncate删除没有返回值,delect删除有返回值
5.truncate删除不能回滚,delect删除可以回滚
DDL语言:
数据定义语言;库和表的管理
1.库的管理
创建、修改、管理
2.表的管理
创建、修改、删除
创建:create
修改:alter
删除:drop
一:库的管理
1.库的创建
语法:
CREATE DATABASE (IF NOT EXISTS)库名;
2.更改库的字符集
ALTER DATABASE 库名 CHARACTER SET 新字符集
3.库的删除
DROP DATABASE 库名;
二:表的管理
1.表的创建
CTERE table 表名 (
列名 列的类型(长度,约束),
列名 列的类型(长度,约束),
列名 列的类型(长度,约束),
)
案例:创建表book
CREATE TABLE book(
id INT ,编号
bName VARCHAR(20),书名
price DOUBLE, 价格
authorId INT, 作者编号
publishDate DATETIME 出版日期
);
2.表的修改
alter table 表名 add/drop/modify/change column 列名 (列的类型 约束);
1.修改列名
ALTER TABLE book CHANGE COLUMN publishdate pubDate DATETIME;//后面跟类型
2.修改列的类型和约束
ALTER TABLE book MODIFY COLUMN pubDate TIMESTAMP;
3.添加新列
ALTER TABLE author ADD COLUMN annual DOUBLE;
4.删除列
ALTER TABLE author DROP COLUMN annual;
5.修改表名
ALTER TABLE author RENAME TO book_author;
3.表的删除
DROP TABLE (IF EXISTS) book_author;
4.表的复制
一:仅复制表的结构
CREATE TABLE copy LIKE author;
二:复制表的结构+数据
CREATE TABLE copy2
SELECT * FROM author;
三:只复制部分数据
CREATE TABLE copy3
SELECT id,au_name
FROM author
WHERE nation = ‘中国’;
四:仅复制某些字段
CREATE TABLE copy4
SELECT id,au_name
FROM author
WHERE 0;//写上不满足的条件,使得只能复制字段
常见的数据类型:
数值型:整数,小数(定点数,浮点数)
字符型:较短的文本:char、varchar
较长的文本:text、blob(较长的二进制数据)
日期型:
一:整型:
特点:
1.如果不设置无符号还是有符号,默认是有符号,如果想设置无符号,在后面加上 unsigned
2.如果插入的数值超出整型的范围,会报out of rang ,并且插入临界值
3.如果不设置长度,会有默认的长度(如果长度大于给定的长度,直接显示,如果数值的长度小于给定的长度也返回该数值但数值无效,在创建列的后面加上zreofill表示用0左填充到给定的长度并且默认无符号位就可以省略unsigned)
tinyint 1个字节 -128–127
smallint 2个字节
mediumint 3个字节
int 、integer 4个字节
bigint 8个字节
1.如何设置无符号和有符号
CREATE TABLE tab_int(
t1 INT,//有符号
t2 INT UNSIGNED//无符号
);
二:小数
1.浮点型(float,double)
float(M,D)//float(5,2) (123.12)
double(M,D)
2.定点型:
DEC(M,D)
特点:
M代表整数部位外加小数部位
D表示小数部位
M和D都可以省略,如果是decimal,M默认是10,D默认是0,如果是float和double则会根据插入的数值的精度来决定精度
定点型的精确度较高,如果要求插入数值的精度较高如货币运算等则考虑定点型
原则:
所选择的类型越简单越好,能保存数值的类型越小越好
三:字符型:
较短的文本:
char varchar
较长的文本:
text
blob
其他:
binary和varbinary用于保存较短的二进制
enum用于保存枚举
set用于保存集合
特点:
char(M) 可以省略,默认为1 varchar(M)不可省略
M:表示最多的字符数
特点:char代表固定长度的字符,空间消耗多,效率高;varchar代表可变长度的字符,空间耗费少,效率低
四:日期型:
date只保存日期
time只保存时间
year只保存年
datetime保存日期+时间
timestamp保存日期+时间
字节 范围 时区等的影响
datetime 8 1000-9999 不受
timestamp 4 1970-2038 受
常见约束的介绍:
含义:一种限制,用于限制表中的数据,为了保证表中的数据的准确和可靠性
分类:
NOT NULL:非空,用于保证该字段的值不能为空(比如姓名、学号等)
DEFAULT: 默认,用于保证该字段有默认值(比如性别)
PRIMARY KEY:主键,用于保证该字段的值具有唯一性,并且非空(比如学号、员工编号)
UNIQUE:唯一,用于保证该字段的值具有唯一性,可以为空(比如座位号)
CHECK:检查约束(mysql不支持)
FOREIGN KEY:外键,用于限制两个表的关系,用于保证该字段的值必须来自于主表的关联列的值(在从表添加外键约束,用于引用主表中某列的值)
比如:学生表的专业编号,员工表的部门编号,员工表的工种编号
添加约束的时机:
1.创建表时
2.修改表时
约束的添加分类:
列级约束:六大约束语法上都支持,但外键约束没有效果
表级约束:除了非空、默认其他的都支持
一:创建表时添加约束
1.添加列级约束
语法:直接在字段名和类型后面追加约束条件即可,只支持默认,非空,主键,唯一
CREATE TABLE stuinfo(
id INT PRIMARY KEY,//主键
stuName VARCHAR(20) NOT NULL,//非空
gender CHAR(1) CHECK(gender=‘男’ OR gender=‘女’),//检查
seat INT UNIOUE, //唯一
age INT DEFAULT 18,//默认
majorId INT REFERENCE major(id),//外键
);
CREATE TABLE major(
id INT PRIMARY KEY,
majorName VARCHAR(20)
);
2.添加表级约束
语法:在各个字段的最下面
[constraint 约束名 ] 约束类型(字段名)
CREATE TABLE stuinfo(
id INT,
gender CHAR(1),
seat INT,
age INT,
majorid INT,
PRIMARY KEY(id),//主键
UNIQUE(seat),//唯一键
CHECK (gender=‘男’ OR gender=‘女’)//检查
FOREIGN KEY (majorid) REFERENCES major(id)//外键
)
二:修改表时添加约束
语法:
1.添加列级约束
alter table 表名 modify column 字段名 字段类型 新约束;
2.添加表级约束
alter table 表名 add 约束类型 (字段名)
1.添加非空约束
ALTER TABLE stuinfo MODIFY COLUMN stuname VARCHAR(20) NOT NULL;
2.添加默认约束
ALTER TABLE stuinfo MODIFY COLUMN age INT DEFAULT 18;
3.添加主键
列级约束
ALTER TABLE stuinfo MODIFY COLUMN id INT PRIMARY KEY;
表级约束
ALTER TABLE stuinfo ADD PRIMARY KEY(id);
4.添加唯一
列级约束
ALTER TABLE stuinfo MODIFY COLUMN seat INT UNIQUE;
表级约束
ALTER TABLE stuinfo ADD UNIQUE(seat);
ALTER TABLE stuinfo ADD UNIQUE(seat);
5.添加外键
ALTER TABLE stuinfo ADD FOREIGN KEY(majorid) REFERENCE major(id);
三:修改表时删除约束
1.删除非空约束
ALTER TABLE stuinfo MODIFY CLOUMN stuname VARCHAR(20) NULL;
2.删除默认约束
ALTER TABLE stuinfo MODIFY COLUMN age INT;
3.删除主键
ALTER TABLE stuinfo DROP PRIMARY KEY;
4.删除唯一
ALTER TABLE stuinfo DROP INDEX seat;
5.删除外键
ALTER TABLE stuinfo DROP FOREIGN KEY majorid;
主键和唯一的对比:
保证唯一性 是否允许为空 一个表可以有多少个 是否允许组合
主键 是 否 至少有1个 是
唯一 是 是 可以有多个 是
外键:
1.要求在从表设置外键关系
2.从表的外键列的类型和主表的关联列的类型要求一致或兼容,名称无要求
3.主表的关联列必须是一个key(一般是主键或唯一)
4.插入数据时,先插入主表,再插入从表;删除数据时,先删除从表再删除主表
删除主表中的数据
方式一:级联删除(在添加外键的时候在最后面加上ON DELETE CASCADE)
ALTER TABLE stuinfo ADD CONSTRAINT fk_stu_major FOREIGN KEY(majorid) REFERENCES major (id) ON DELETE CASCADE;
方式二:级联置空
ALTER TABLE stuinfo ADD CONSTRAINT fk_stu_major FOREIGN KEY(majorid) REFERENCES major (id) ON DELETE SET NULL;//着是将主表中的数据删除,将从表中设置外键的数据变为null
标识列:
特点:
1.标识列不一定和主键搭配,主要是个key就行
2.一个表至多一个标识列
3.标识列的类型只能是数值型
4.标识列可以通过(set auto_increment_increment=3)设置步长也可以手动插入值,设置起始步长
又称自增长列,含义:可以不用手动的插入值,系统提供默认的序列值
一:创建表时设置标识列
CREATE TABLE tab_identity(
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(20)
)
INESRT INTO tab_identity VALUES(NULL,‘john’);
这种表名后面不加列默认全部但后面为了满足列数一致写null
INSERT INTO tab_identity (name) VALUES(‘lucy’);
二:修改表时设置标识列
ALTER TABLE tab_identity MODIFY COLUMN id INT PRIMARY KEY AUTO INCREMENT;
三:修改表时删除标识列
ALTER TABLE tab_identy MODIFY COLUMN id INT;
TCL语言
TCL(Transaction Control Language)事务控制语言
事务:一个或一组sql语句组成一个执行单元,这个执行单元要么全部执行,要么全部不执行
事务是ACID原则:
1.原子性:原子性是指事务是一个不可分隔的工作单位,事务的操作要么都发生要么都不发生
2.一致性:事务必须使数据库从一个一致状态变换到另外一个一致性状态
3.隔离性:事务的隔离性是指一个事务的执行不能被其他事务干扰,事务内部的操作及使用的数据对并发的其他事务是隔离的,并发执行的各个事务之间不能互相干扰
4.持久性:持久性是指一个事务一旦被提交,它对数据库中数据的改变就是永久性的
事务的创建:
隐式事务:事务没有明显的开启和结束的标记(比如insert,update,delete)
DELETE FROM 表 WHERE id=1;
显式事务:事务具有明显的开启和结束的标记
前提:必须先设置自动提交功能为禁用(set autocommit=0)
步骤1:开启事务
set autocommit=0;
步骤二:编写事务中的sql语句(select insert update delete)
语句1;语句2;
步骤三:结束事务
commit;//提交事务
rollback;//回滚事务
事务的并发问题:
1.脏读:对于两个事务T1,T2,T1读取了已经被T2更新但还没有被提交的字段之后,若T2回滚,T1读取的内容就是临时且无效的
2.不可重复读:对于两个事务T1,T2,T1读取了一个字段,然后T2更新了该字段之后,T1再次读取同一个字段,值就不同了
3.幻读:对于两个事务T1,T2,T1从一个表中读取了一个字段,然后T2在该表中插入了一些新的行之后,如果TI再次读取同一个表,就会多出几行
MySQL默认的事务隔离级别是REPEATABLE READ
隔离级别:
READ UNCOMMITED(读取未提交数据):
允许事务读取未被其他事务提交的变更,脏读,不可重复读和幻读都不可避免
READ COMMITED(读已提交数据)
只允许事务读取已经被其他事务提交的变更,可以避免脏读,但不可避免重复读和幻读
REPEATABLE READ(可重复读)
确保事务可以多次从一个字段中读取相同的值,在这个事务持续期间,禁止其他事务对这个字段进行更新,可以避免脏读和不可重复读但幻读仍然存在
SERIALIZABLE (串行化)
确保事务可以从一个表中读取相同的行,在这个事务持续期间,禁止其他事务对该表执行插入更新和删除操作,所有并发问题都可以避免但性能低下
查看当前的隔离级别:
SELECT @@tx_isolation
设置当前MySQL连接的隔离级别
SET TRANSATION ISOLATION LEVEL READ COMMITTED;
savepoint:保存点(搭配rollback使用)
SET autocommit=0;
START TRANSACTION;
DELECT FROM account WHERE id=25;
SAVEPOINT a;//设置保存点
DELETE FROM account WHERE id=28;
ROLLBACK TO a;//回滚到保存点
delete和truncate在事务使用时的区别:
前者支持回滚,后者不支持回滚
视图:
含义:虚拟表,和普通表一样使用,mysql5.1版本出现的新特性,是通过表动态生成的数据(就是将常用到的数据生成一张表,然后再要找数据时就可以直接从虚拟表里找即可)
应用场景:
1.多个地方用到同样的查询结果
2.该查询结果使用的sql语句较复杂
就可以将其封装成视图,然后直接在里面查询就行了
案例:查询姓张的学生名和专业名
CREATE VIEW v1
AS
SELECT stuname,majorname
FROM stuinfo s
INNER JOIN major m ON s.majorid = m.id;
SELECT * FROM v1 WHERE stuname LIKE ‘张%’;
视图的创建:
语法:
CREATE view 视图名
AS
查询语句;
案例:查询姓名中包含a字符的员工名、部门名和工种信息
1.创建视图
CREATE VIEW myv1
AS
SELECT last_name,department_id,job_title
FROM employees e
JOIN departments d
WHERE e.department_id = d.department_id
JOIN jobs j
WHERE d.job_id = j.job_id;
2.使用视图
SELECT * FROM myv1 WHERE last_name LIKE ‘%a%’;
案例2:查询各部门的平均工资级别
1.创建视图查看每个部门的平均工资
CREATE VIEW myv2
AS
SELECT AVG(salary) ag,department_id
FROM employees
GROUP BY department_id;
2.使用视图
SELECT myv2.ag,g.grade_level
FROM myv2
JOIN job_grade g
WHERE myv2.ag BETWEEN g.lowest_sal AND g.hightest_sal;
3.查询平均工资最低的部门信息
SELECT * FROM myv2 ORDER BY ag LIMIT 1;
好处:
1.sql语句的重用
2.简化复杂的sql操作
3.保护数据,提高安全性
视图的修改:
方式一:
CREATE OR REPLACE VIEW 视图名
AS
查询语句
案例:将原来查看各部门的平均工资换成查看各工种的平均工资
CREATE OR REPLACE VIEW myv3
AS
SELECT AVG(salary),job_id
FROM employees
GROUP BY job_id;
方式二:
ALTER VIEW 视图名
AS
查询语句
视图的删除:
语法:
DROP VIEW 视图名,视图名,…;
视图的查看:
语法:
DESC 视图名;
视图的更新:
1.插入:
INSERT INTO myv1 VALUES(‘张飞’,‘zf@qq.com’);
2.修改:
UPDATE myv1 SET last_name = ‘张无忌’ WHERE last_name =‘张飞’;
3.删除:
DELETE FROM myv1 WHERE last_name=‘张无忌’;
//对视图进行增删改,主表中的数据也会同步
具备以下特点的视图不允许更新
1.包含以下关键字的sql语句:分组函数、distinct、group by、having union或者 union all
2.常量视图
案例:
CREATE OR REPLACE VIEW myv2
AS
SELECT ‘john’ name
更新:
UPDATE myv2 SET NAME=‘lucy’;//结果会报错
3.select中包含子查询
CREATE OR REPLACE VIEW myv3
SELECT (SELECT MAX(salary) FROM employees) 最高工资;
UPDATE myv3 SET 最高工资 = 10000;//会报错
4.join
5.from一个不能更新的视图
6.where子句的子查询引用了from子句中的表
CREATE OR REPLACE VIEW myv6
AS
SELECT last_name ,email,salary
FROM employees
WHERE empoyee_id IN(
SELECT manager_id
FROM employees
WHERE manager_id IS NOT NULL
);
UPDATE myv6 SET salary=10000 WHERE last_name =‘k_ing’
//报错
创建语法的关键字 是否实际占用物理空间 使用
视图 create view 没有(只是保存了sql逻辑) 增删改查
表 create table 占用(保存了实际数据) 增删改查
变量:
系统变量:
全局变量、会话变量
自定义变量:
用户变量、局部变量
一:系统变量:
变量由系统提供,不是用户定义,属于服务器层面
语法:
1.查看所有的系统变量
SHOW (SESSION/GLOBAL)VARIABLES;
2.查看满足条件的部分系统变量
SHOW GLOBAL/SESSION VARIABLES LIKE ‘%char%’;
3.查看指定的某个系统变量的值
SELECT @@(GLOBAL/SESSION).系统变量名;
4.为某个系统变量赋值
方式一:
SET (GLOBAL/SESSION)系统变量 = 值;
方式二:
SET @@(GLOBAL/SESSION).系统变量名=值;
如果是全局级别需要加global,如果是会话级别,需要加session,如果不写,默认session
一、全局变量
作用域:服务器每次启动将为所有的全局变量赋初始值,针对所有的会话(连接)有效,但不能跨重启
1.查看系统全局变量
SHOW GLOBAL VARIABLES;
2.查看部分的全局变量
SHOW GLOBAL VARIABLES WHERE LIKE ‘%char%’;
3.查看指定的全局变量
SELECT @@global.autocommit;
SELECT @@tx_isolation;
4.为某个指定的全局变量赋值
SET @@global.autocommit=0;
二、会话变量
作用域:仅仅针对于当前会话(连接)有效
1.查看所有的会话变量
SHOW VARIABLES;
SHOW SESSION VARIABLES;
2.查看部分的会话变量
SHOW VARIABLES LIKE ‘%char%’;
3.查看指定的某个会话变量
SELECT @@tx_islocation;
SELECT @@session.tx_islocation;
4.为某个会话变量赋值
方式一:
SET @@session.tx_islocation = ‘read-uncommitted’;//只对当前会话有效
方式二:
SET SESSION tx_islocation = ‘read-committed’;
二:自定义变量
变量是用户自定义的,不是由系统的
步骤:声明、赋值、使用
1.用户变量
赋值的操作符: =或:=
作用域:针对于当前会话(连接)有效,同于会话变量的作用域
声明并初始化
SET @用户变量名 = 值;
SET @用户变量名:=值;
SELECT @用户变量名:=值;
2.赋值(更新用户变量的值)
方式一:SET和SELECT
SET @用户变量名 = 值;
SET @用户变量名:=值;
SELECT @用户变量名:=值;
案例:
SET @name = ‘john’;//这样声明默认name是字符型
SET @name =100;//这样写默认name是整型
方式二:SELECT INTO
SELECT COUNT(*) INTO @count
FROM employees;
3.使用(查看用户变量名)
SELECT @用户变量名;
2.局部变量:
作用域:仅仅在定义它的begin and中有效
应用在begin end中的第一句
1.声明
DECLARE 变量名 类型;
DECLARE 变量名 类型 DEFAULT 值;
2.赋值
方式一:SET和SELECT
SET 局部变量名 = 值;
SET 局部变量名:=值;
SELECT @局部变量名:=值;
方式二:SELECT INTO
SELECT 字段 INTO 局部变量
FROM 表;
3.使用
SELECT 局部变量名;
对比用户变量和局部变量
作用域 定义和使用的位置 语法
用户变量 当前会话 会话中的任何地方 必须加@符号
局部变量 begin end 只能在begin end中,且为第一句话 一般不用加@符号
案例:声明两个变量并赋初值,求和,并打印
1.用户变量
SET@m =3;
SET@n =2;
SET @sum = @m+@n;
SELECT @sum;
2.局部变量
DECLARE m INT DEFAULT 1;
DEFAULT n INT DEFAULT 2;
DECLARE sum INT;
SET sum = m+n;
SELECT sum;
存储过程:
存储过程和函数:类似于java中的方法
好处:
1.提高代码的重用性
2.简化操作
3.减少编译次数并且减少了和数据库服务器的连接次数,提高了效率
存储过程:
含义:一组预先编译好的sql语句集合,理解成批处理语句
语法:
1.创建:
CREATE PROCEDURE 存储过程名(参数列表)
BEGIN
存储过程体(一组sql语句)
END
参数列表包含三部分
参数模式,参数名,参数类型(IN stuname VARCHAR(20))
参数模式:
IN :该参数可以作为输入,也就是该参数需要调用方法传入值
OUT :该参数可以作为输出,也就是该参数可以作为返回值
INOUT:该参数既可以作为输入又可以作为输出,也就是该参数既需要传入值,又可以返回值
如果存储过程体仅仅只有一句话,begin end可以省略
存储过程体中的每条sql语句的结尾要求必须加分号,存储过程的结尾可以使用DELIMITER 重新设置
案例:DELIMITER $
调用语法
call 存储过程名(实参列表);
1.空参列表
案例:插入到admin表中五条记录
DELIMITER $
CREATE PROCEDURE myp1()
BEGIN
INSERT INTO admin(username,password) VALUES(‘john’,‘0000’);
…
END $
CALL myv1() $
创建带IN模式参数的存储过程
案例1:创建存储过程,根据女生名,查询对应的男生名
CREATE PROCEDURE myp2 (IN btautyName VARCHAR(20))
BEGIN
SELECT bo.*
FROM boys bo
FIGHT JOIN beautys b
ON bo.id = b.boyfriend_id;
WHERE b.name = beautyName;
END $
CALL myv2(‘刘岩’ ) $
案例2:创建存储过程实现,用户是否登录成功
CREATE PROCEDURE myv3(IN usernmae VARCHAR(20),IN password VARCHAR(20))
BEGIN
DECLARE result INT DEFAULT 0//声明并初始化
SELECT COUNT(*) INTO result//赋值
FROM admin
WHERE admin.username = username
AND admin.password = password;
SELECT IF(result>0,‘成功’,‘失败’);
END $
CALL myv3(‘张飞’,‘0000’)$
3.创建带out模式的存储过程
案例1:根据女生名返回对应男生名
CREATE PROCEDURE myv5(IN beautyName VARCHAR(20),OUT boyName VARCHAR(20) )
BEGIN
SELECT bo.boyName INTO boyName
FROM boys bo
INNER JOIN beauty b
ON b.boyfriend_id = bo.id
WHERE b.name = beautyName;
END $
调用
SET @bName $//用于接受查询的结果
CALL myv5(‘小昭’,@bName)$
SELECT @bName;
案例2:根据女生名,返回对应的男生名和男生魅力值
CREATE PROCEDURE myv6(IN beautyName VARCHAR(20),OUT boyName VARCHAR(20),OUT userCP INT)
BEGIN
SELECT bo.boyName,bo.userCP INTO boyName,userCP
FROM boys bo
INNER JOIN beauty b
ON bo.id = b.boyfriend_id
WHERE b.name = beautyName;
END $
SET @bName;
SET@usercp;
CALL myv6(‘小昭’,@bName,@usercp) $
SELECT @bName;
SELECT @usercp;
4.创建带inout模式参数的存储过程
CREATE PROCEDURE myv8(INOUT a INT,INOUT b INT)
BEGIN
SET a = a*2;
SET b = b*2;
END $
SET @m=10$
SET @n=20$
CALL myv8(@m,@n)$
SELECT @m$
SELECT @n$
经典案例:
1.创建存储过程实现传入用户名和密码,插入到admin表中
CREATE PROCEDURE test_pro1(IN usename VARCHAR(20),IN loginPwd VARCHAR(20))
BEGIN
INSERT INTO admin(admin.username,password)
VALUES(username,loginpwd);
END$
2.创建存储过程实现传入女生编号,返回女生名称和女生电话
CREATE PROCEDUCE test_pro2(IN id INT,OUT name VARCHAR(20),OUT phone VARCHAR(20))
BEGIN
SELECT b.name,b.phone INTO name,phone
FROM beauty b
WHERE b.id=id;
END$
3.创建存储过程或函数实现传入一个日期,格式化成xx年xx月xx日并返回
CREATE PROCEDURE test_pro3(IN mydate DATETIME, OUT strDate VARCHAR(50))
BEGIN
SELECT DATE_FORMAT(mydate ,’%y年%m月%d日’) INTO strDate;
END $
CALL test_pro(NOW(),@str)$
SELECT @str $
删除存储过程
语法: DROP PROCEDURE 存储过程名
查看存储过程的信息
SHOW CREATE PROCEDURE 存储过程名;
函数:
好处:
1.提高代码的重用性
2.简化操作
3.减少编译次数并且减少了和数据库服务器的连接次数,提高了效率
区别:
存储过程:可以有0个返回,也可以有多个返回,适合做批量插入,批量更新
函数:有且仅有1个返回,适合做处理数据后返回一个结果
语法:CREATE FUNCTION 函数名(参数列表) RETURNS 返回类型
BEGIN
函数体
END
参数列表包含参数名和参数类型
函数体中有且仅有一句话,则可以省略begin end
使用delimiter语句设置结束标记
delimiter $;
调用语法:
SELECT 函数名(参数列表)
1.无参有返回
案例:返回公司的员工个数
CREATE FUNCTION myf1() RETURNS INT
BEGIN
DECLARE c INT DEFAULT 0;
SELECT COUNT(*) INTO c
FROM employees;
RETURN c;
END $
SELECT myf1() $
2.有参有返回
案例:根据员工名,返回他的工资
CREATE FUNCTION myf2(empName VARCHAR(20)) RETURNS DOUBLE
BEGIN
SET @sal=0;//定义用户变量
SELECT salary INTO @sal
FROM employees
WHERE last_name = empName;
RETURN @sal;
END $
SELECT myf2(‘k_ing’) $
查看函数:
SHOW CREATE FUNCTION myf3;
删除函数:
DROP FUNCTION myf3;
流程控制结构:
顺序结构:从上往下依次执行
分支结构:从两条或者多条路径中选择一条去执行
循环结构:在满足一定条件的基础上,重复执行一段代码
1.if函数
语法:
IF(表达式1,表达式2,表达式3)
如果表达式1成立则返回表达式2的值,否则返回表达式3的值
任何地方都可以使用
2.case函数
语句:
情况1:
CASE 变量、表达式、字段
WHEN 要判断的值 THEN 返回的值1或语句1;
WHEN 要判断的值 THEN 返回的值2或者语句2;
…
ELSE 要返回的值n;
END CASE;
情况2:
语法:
CASE
WHEN 要判断的条件1 THEN 返回的值1或语句1;
WHEN 要判断的条件2 THEN 返回的值2或语句2;
…
ELSE 要返回的值n或语句n;
END CASE;
特点:
可以作为表达式,嵌套在其他语句中使用,可以放在任何地方
可以做为独立的语句使用,只能放在begin end 中
如果WHEN中的值满足或条件成立,则执行对应的THEN后面的语句,并且结束CASE,如果都不满足,则执行ELSE中的语句或值
ELSE可以省略,如果ELSE省略,并且所有WHEN条件都不满足,则返回NULL
案例:创建存储过程,根据传入的成绩,来显示等级,90-100显示A,80-90显示B,60-80显示C,否则显示D
CREATE PROCEDURE test_case(IN score INT)
BEGIN
CASE
WHEN score>=90 AND score<=100 THEN SELECT ‘A’;
WHEN score>=80 THEN SELECT ‘B’;
WHEN score>=60 THEN SELECT ‘C’;
ELSE SELECT ‘D’;
END CASE;
END $
CALL test_case(95) $
IF结构
语法:
if 条件1 then 语句1;
else if 条件2 then 语句2;
…
else if;
案例:根据传入的成绩,来显示等级,90-100返回A,80-90返回B,60-80返回C,否则返回D
CREATE FUNCTION test_if(score INT) RETURN CHAR
BEGIN
IF score>=90 AND score<=100 THEN RETURN ‘A’;
ELSE IF score >=80 THEN RETURN ‘B’;
ELSE IF score>=60 THEN RETURN ‘C’;
ELSE RETURN ‘D’;
END IF;
END $
循环结构:
分类:
while、loop、repeat
循环控制:
iterate (continue)结束本次循环,继续下一次
leave(break)结束当前所在的循环
1.while
语法:
(标签):while 循环条件 do
循环体;
end while (标签);
2.loop
(标签) loop
循环体;
end loop (标签);
3.repeat
(标签) repeat
循环体;
until 结束循环的条件
end repeat (标签);
案例1:批量插入,根据次数插入到admin表中多条记录
CREATE PROCEDURE pro_while1(IN insertCount INT)
BEGIN
DECLARE i INT DEFAULT 1;
WHILE i<=insertCount DO
INSERT INTO admin (username,password) VALUES ((‘Rose’,i),‘666’);
SET i= i+1;
END WHILE;
END $
CALL pro_while1(100) $
案例2:
添加leave语句,批量插入,根据次数插入到admin表中多条记录,如果次数>20则停止
CREATE PROCEDUCE test_while1(IN insertCount INT)
BEGIN
DECLARE i INT DEFAULT 1;
a: WHILE i<=insertCount DO
INSERT INTO admin(username,password) VALUES (CONACT(xiaohua,i),‘000’);
IF i>=20 THEN LEAVE a;
END IF;
SET i=i+1;
END WHILE a;
END $
CALL test_while(100)$
经典案例:向该表插入指定个数的随机字符串
CREATE PROCEDURE test_randstr_insert(IN insertCount INT)
BEGIN
DECLARE i INT DEFAULT 1;
DECLARE str VARCHAR(26) DEFAULT(‘abcdefghijklmnopqrstuvwsyz’);
DECLARE startIndex INT DEFAULT 1;
DECLARE len INT DEFAULT 1;
SET len = FLOOR(RAND()*(20-startIndex+1)+1);
SET startIndex = FLOOR(RAND()*26+1);
INSERT INTO stringcontent (content) VALUES (SUBSTR(str,startIndex,len));
SET i=i+1;
END WHILE;
END $