学习MySQL看这一篇就够了
文章目录
- 整体大纲
- 1. 为什么要学习数据库
- 2. 数据库的相关概念
- 3. 数据库存储数据的特点
- 4. 初始MySQL
- 4.1 MySQL服务的登录和退出
- 4.2 MySQL的常见命令
- 4.3 MySQL的语法规范
- 4.4 SQL的语言分类
- 4.5 导入数据库表
- 5. DQL语言的学习
- 5.1 基础查询
- 5.1.1 基础查询练习
- 5.2 条件查询
- 5.2.1 条件查询练习
- 5.2.2 经典面试题
- 5.3 排序查询
- 5.3.1 排序查询练习
- 5.4 常见函数
- 5.4.1 常见函数练习
- 5.5 分组函数
- 5.5.1 分组函数练习
- 5.6 分组查询
- 5.6.1 分组查询练习
- 5.7 连接查询
- 5.7.1 连接查询练习
- 5.8 sql99连接查询
- 5.8.1 sql99连接查询练习
- 5.9 子查询
- 5.9.1 子查询练习
- 5.10 分页查询
- 5.11 联合查询
- 6. DML语言的学习
- 6.1 数据的增删改
- 6.1.1 增删改练习
- 7. DDL语言的学习
- 7.1 库和表的管理
- 7.1.1 库和表的管理练习
- 7.2 常见数据类型
- 7.3 常见约束
- 7.3.1 常见约束练习
- 7.4 标识列
- 8. TCL语言的学习
- 8.1 事务
- 9.视图
- 10.变量
- 11.存储过程
- 11.1 存储过程练习
- 12.函数
- 13.流程控制结构
- 13.1 流程控制结构练习
整体大纲
1. 为什么要学习数据库
数据库的好处
- 能够持久化到本地
- 可以实现结构化查询,方便管理
2. 数据库的相关概念
- DB:数据库,存储数据的容器(文件)
- DBMS:数据库管理系统,又称为数据库软件(产品),用于创建或管理DB中的数据
- SQL:结构化查询语言,用于和DBMS通信的语言,不是某个数据库软件特有的,而是几乎所有的主流数据库软件通用的语言
3. 数据库存储数据的特点
- 将数据放到表中,表再放到库中
- 一个数据库中可以有多张表,每张表都有一个名字,用来标识自己。表名具有唯一性
- 表具有一些特性,这些特性定义了数据在表中如何存储,类似java中 “类” 的设计
- 表由列组成,我们也称为字段。所有表都是由一个或多个列组成的,每一列类似 java 中的 “属性”
- 表中的数据是按行存储的,每一行类似于java中的 “对象”
常见的数据库管理系统
MySQL、Oracle、SQL Server、db2
MySQL的背景
前身属于瑞典的一加公司,MySQL AB
08年被sun公司收购
09年sun公司被Oracle公司收购,所以它现在是属于Oracle公司的
MySQL的优点
1、开源、免费、成本低
2、性能高、移植性也好
3、体积小,便于安装
4. 初始MySQL
4.1 MySQL服务的登录和退出
-- 方式一:
-- 打开终端,输入 mysql -h 主机名 -P 端口号 -u用户名 -p密码
xiexu@Macintosh ~ % mysql -h localhost -P 3306 -uroot -p283619
...
mysql>-- 方式二: (如果是本机电脑一般用这种)
-- mysql -u用户名 -p密码
xiexu@Macintosh ~ % mysql -uroot -p283619
...
mysql>-- 退出:
exit或ctrl+C
4.2 MySQL的常见命令
-- 1.查看当前所有的数据库
show databases;
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
| test |
+--------------------+
4 rows in set (0.00 sec)-- 2.打开指定的库
use 库名;
mysql> use test;
Database changed-- 3.查看当前库的所有表
show tables;
mysql> show tables;
+----------------+
| Tables_in_test |
+----------------+
| books |
+----------------+
1 row in set (0.00 sec)-- 4.查看其它库的所有表
show tables from 库名;
mysql> show tables from mysql;
+---------------------------+
| Tables_in_mysql |
+---------------------------+
| columns_priv |
| component |
| db |
|... |
+---------------------------+
33 rows in set (0.00 sec)-- 5.查看当前所在的库
select database();
mysql> select database();
+------------+
| database() |
+------------+
| test |
+------------+
1 row in set (0.00 sec)-- 6.创建表
create table 表名(列名 列类型,列名 列类型,...
);
mysql> create table stuinfo(-> id int,-> name varchar(20));
Query OK, 0 rows affected (0.00 sec)-- 7.查看表的结构
desc 表名;
mysql> desc stuinfo;
+-------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| id | int | YES | | NULL | |
| name | varchar(20) | YES | | NULL | |
+-------+-------------+------+-----+---------+-------+
2 rows in set (0.01 sec)-- 8.查看服务器的版本
-- 方式一:已经登录到mysql服务端
select version();
mysql> select version();
+-----------+
| version() |
+-----------+
| 8.0.19 |
+-----------+
1 row in set (0.00 sec)
-- 方式二:没有登录到mysql服务端
mysql --version
xiexu@Macintosh ~ % mysql --version
/usr/local/mysql/bin/mysql Ver 8.0.19 for macos10.15 on x86_64 (MySQL Community Server - GPL)
--或者输入:
mysql -V
xiexu@Macintosh ~ % mysql -V
/usr/local/mysql/bin/mysql Ver 8.0.19 for macos10.15 on x86_64 (MySQL Community Server - GPL)
4.3 MySQL的语法规范
1.不区分大小写,但建议关键字大写,表名、列名小写
2.每条命令最好用分号结尾
3.每条命令根据需要,可以进行缩进 或换行
4.注释(注意空格)单行注释:#注释文字单行注释:-- 注释文字多行注释:/* 注释文字 */
4.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
4.5 导入数据库表
为了让我们可以更加方面的操作和练习后面的内容,在这里提供了一个数据库文件,里面包含四张表
具体的操作步骤
表结构名称介绍
5. DQL语言的学习
5.1 基础查询
-- 进阶1:基础查询
/*
语法:
select 查询列表 from 表名;类似于: System.out.println(要打印的东西)特点:1、查询列表可以是: 表中的字段、常量值、表达式、函数2、查询的结果是一个虚拟的表格(临时存在的)
*/-- 指定使用的数据库
USE myemployees;-- 1. 查询表中的单个字段
SELECT last_name FROM employees;-- 2.查询表中的多个字段
SELECT last_name,salary,email FROM employees;-- 3.查询表中的所有字段
-- 方式一:
SELECT `employee_id`,`first_name`,`last_name`,`phone_number`,`job_id`,`salary`,`commission_pct`,`manager_id`,`department_id`,`hiredate`
FROMemployees;
-- 注意:``表示的是里面的内容是一个字段,而不是关键字,建议每次查询字段都要加上这个-- 方式二:
SELECT * FROM employees;-- 4.查询常量值
-- 注意:字符型和日期型的常量值必须用单引号引起来,数值型不需要
SELECT 100;-- 5.查询表达式
SELECT 100%98;-- 6.查询函数
SELECT VERSION();-- 7.为字段起别名
/*
1、便于理解
2、如果要查询的字段有重名的情况,使用别名可以区分开来
*/
-- 方式一:使用as
SELECT 100%98 AS 结果;
SELECT last_name AS 姓,first_name AS 名 FROM employees;-- 方式二:使用空格
SELECT last_name 姓,first_name 名 FROM employees;-- 案例:查询salary,显示结果为 out put
-- 注意:如果起的别名是关键字,建议使用双引号括起来
SELECT salary AS "out put" FROM employees;-- 8.去重
-- 案例:查询员工表中涉及到的所有的部门编号
SELECT DISTINCT department_id FROM employees;
-- 根据a和b两个字段去重的
SELECT DISTINCT a,b FROM 表名;-- 9.+号的作用
/*
java中的+号:
1、运算符,两个操作数都为数值型
2、连接符,只要有一个操作数为字符串mysql中的+号:
仅仅只有一个功能:运算符select 100+90; 两个操作数都为数值型,则做加法运算
select '123'+90;只要其中一方为字符型,试图将字符型数值转换成数值型如果转换成功,则继续做加法运算
select 'john'+90; 如果转换失败,则将字符型数值转换成0select null+10; 只要其中一方为null,则结果肯定为null
*/-- 10.concat函数
/*
1.作用:拼接字符
2.语法格式:select concat(字符1,字符2,...)
*/
-- 案例:查询员工名和姓连接成一个字段,并显示为 姓名
SELECT CONCAT('a','b','c') AS 结果;SELECT CONCAT(last_name,first_name) AS 姓名
FROMemployees;-- 11.isnull函数
/*
1.作用:判断某字段或表达式是否为null,如果是null,返回1,否则返回0
2.语法格式:select isnull(字段名) from 表名;
*/
SELECTISNULL( commission_pct ),commission_pct
FROMemployees;-- IFNULL函数
/*
1.作用:判断某字段或表达式是否为null,如果为null,就返回指定的值,否则返回原本的值
2.语法格式: select IFNULL(字段名,指定的值) from 表名;
*/
SELECT IFNULL(commission_pct,0) AS 奖金率,commission_pct
FROM employees;
5.1.1 基础查询练习
-- 1.显示表departments的结构,并查询其中的全部数据
DESC departments;
SELECT * FROM `departments`;-- 2.显示出表employees中的全部job_id(不能重复)
SELECT DISTINCT job_id FROM employees;-- 3.显示出表employees的全部列,各个列之间用逗号连接,列头显示成OUT_PUT
SELECTCONCAT(`first_name`,',',`last_name`,',',`job_id`,',',IFNULL(commission_pct,0)) AS out_put
FROMemployees;
5.2 条件查询
-- 进阶2:条件查询
/*
语法:select 查询列表from表名where筛选条件;分类:一、按条件表达式筛选简单条件运算符:> < = != <> >= <=注意:<>表示的是不等于,使用不等于的话建议用这个二、按逻辑表达式筛选逻辑运算符:&& || !and or not作用:用于连接条件表达式说明:&&和and:两个条件都为true,结果为true,反之为false||或or: 只要有一个条件为true,结果为true,反之为false!或not: 如果连接的条件本身为false,结果为true,反之为false三、模糊查询likebetween andinis null
*/-- 1.按条件表达式筛选
-- 案例1:查询员工工资>12000的员工信息
SELECT *
FROMemployees
WHEREsalary>12000;-- 案例2:查询部门编号不等于90号的员工名和部门编号
SELECT last_name,department_id
FROMemployees
WHEREdepartment_id<>90;-- 案例3:查询员工号为 176 的员工的姓名和部门号和年薪
SELECTlast_name,department_id,salary * 12 * ( 1+IFNULL ( commission_pct, 0 ) ) AS 年薪
FROMemployees
WHEREemployee_id = 176;-- 2.按逻辑表达式筛选
-- 案例1:查询工资在10000到20000之间的员工名、工资以及奖金
SELECTlast_name,salary,commission_pct
FROMemployees
WHEREsalary>=10000 AND salary<=20000;-- 案例2:查询部门编号不是在90到110之间,或者工资高于15000的员工信息
-- 方式一:
SELECT*
FROMemployees
WHERENOT(department_id>=90 AND department_id<=110) OR salary>15000;-- 方式二:
SELECT*
FROMemployees
WHEREdepartment_id < 90 OR department_id > 110 OR salary > 15000-- 3.模糊查询-- 3.1 like
/*特点:①一般和通配符搭配使用,可以判断字符型或数值型通配符:% 任意多个字符,包含0个字符_ 任意单个字符
*/
-- 案例1:查询员工名中包含字符a的员工信息
SELECT*
FROMemployees
WHERElast_name LIKE '%a%';-- 案例2:查询员工名中第三个字符为n,第五个字符为l的员工名和工资
SELECTlast_name,salary
FROMemployees
WHERElast_name LIKE '__n_l%';-- 案例3:查询员工名中第二个字符为'_'的员工名
-- 方式一:使用转义字符 "\_"
SELECTlast_name,salary
FROMemployees
WHERElast_name LIKE '_\_%';-- 方式二:使用ESCAPE '任意字符',将这个字符当做转义字符使用(推荐使用)
SELECTlast_name,salary
FROMemployees
WHERElast_name LIKE '_$_%' ESCAPE '$';-- 案例4:查询部门编号是1开头的,并且是3位数的员工信息
SELECT*
FROMemployees
WHEREdepartment_id LIKE '1__';-- 3.2 between and
/*
①使用between and 可以提高语句的简洁度
②包含临界值
③两个临界值不要调换顺序
*/
-- 案例1:查询员工编号在100到120之间的员工信息
-- 方式一:
SELECT*
FROMemployees
WHEREemployee_id >= 100 AND employee_id <= 120;-- 方式二:推荐使用
SELECT*
FROMemployees
WHEREemployee_id BETWEEN 100 AND 120;-- 3.3 in
/*
含义:判断某字段的值是否属于in列表中的某一项
特点:①使用in提高语句简洁度②in列表的值类型必须一致或兼容(同一字段)③in列表中不支持通配符
*/
-- 案例:查询员工的工种编号是 IT_PROG、AD_VP、AD_PRES中的一个的员工名和工种编号
-- 方式一:
SELECTlast_name,job_id
FROMemployees
WHEREjob_id = 'IT_PROT' OR job_id = 'AD_VP' OR JOB_ID ='AD_PRES';-- 方式二:推荐使用
SELECTlast_name,job_id
FROMemployees
WHEREjob_id IN( 'IT_PROT' ,'AD_VP','AD_PRES');-- 3.4 is null
/*!=或<>不能用于判断null值is null或is not null 可以判断null值
*/
-- 案例1:查询没有奖金的员工名和奖金率
SELECTlast_name,commission_pct
FROMemployees
WHEREcommission_pct IS NULL;-- 案例2:查询有奖金的员工名和奖金率
SELECTlast_name,commission_pct
FROMemployees
WHEREcommission_pct IS NOT NULL;-- 错误写法,执行报错
SELECTlast_name,commission_pct
FROMemployees
WHERE salary IS 12000;-- 3.5 安全等于 <=>
/*
面试题:isnull和<=>的区别?
IS NULL:仅仅可以判断NULL值,可读性较高,建议使用<=> :既可以判断NULL值,又可以判断普通的数值,可读性较低
*/
-- 案例1:查询没有奖金的员工名和奖金率
SELECTlast_name,commission_pct
FROMemployees
WHEREcommission_pct <=> NULL;-- 案例2:查询工资为12000的员工信息
SELECTlast_name,salary
FROMemployees
WHEREsalary <=> 12000;
5.2.1 条件查询练习
-- 1.查询工资大于 12000 的员工姓名和工资
SELECTlast_name,salary
FROMemployees
WHEREsalary > 12000;-- 2.查询员工号为 176 的员工的姓名和部门号和年薪
SELECTlast_name,department_id,salary * 12 * ( 1+IFNULL ( commission_pct, 0 ) ) AS 年薪
FROMemployees;-- 3.选择工资不在 5000 到 12000 的员工的姓名和工资
SELECTlast_name,salary
FROMemployees
WHERENOT ( salary < 5000 AND salary > 12000 );-- 4.选择在 20 或 50 号部门工作的员工姓名和部门号
SELECTlast_name,department_id
FROMemployees
WHEREdepartment_id = 20 OR department_id = 50;-- 5.选择公司中没有管理者的员工姓名及 job_id
SELECTlast_name,job_id
FROMemployees
WHEREmanager_id IS NULL;-- 6.选择公司中有奖金的员工姓名,工资和奖金级别
SELECTlast_name,salary,commission_pct
FROMemployees
WHEREcommission_pct IS NOT NULL;-- 7.选择员工姓名的第三个字母是 'a' 的员工姓名
SELECTlast_name
FROMemployees
WHERElast_name LIKE '__a%';-- 8.选择姓名中有字母 'a' 和 'e' 的员工姓名
SELECTlast_name
FROMemployees
WHERElast_name LIKE '%a%' AND last_name LIKE '%e%';-- 9.显示出表 employees 表中 first_name 以 'e'结尾的员工信息
SELECT*
FROMemployees
WHEREfirst_name LIKE '%e';-- 10.显示出表 employees 部门编号在 80-100 之间 的姓名、职位
SELECTlast_name,job_id
FROMemployees
WHEREdepartment_id BETWEEN 80 AND 100;-- 11.显示出表 employees 的 manager_id 是 100,101,110 的员工姓名、职位
SELECTlast_name,job_id
FROMemployees
WHEREmanager_id IN ( 100, 101, 110 );
5.2.2 经典面试题
试问:select * from employees; 和
select * from employees where `commission_pct` like '%%' and `last_name` like '%%';
结果是否一样?并说明原因回答:如果判断的字段中有null值,结果就是不一样的;而如果判断的字段中没有null值,结果就是一样的。因为like '%%' 表示的是不为空,而如果`commission_pct`或者`last_name`有一个为空,结果就不一样了。
5.3 排序查询
-- 进阶3:排序查询
/*
1.语法: [ ]里面的内容表示可以省略的select 查询列表from 表名[where 筛选条件]order by 排序列表 [asc | desc];
2.特点:1、asc代表的是升序,desc代表的是降序(如果不写,默认就是降序)2、order by子句中可以支持单个字段、多个字段、表达式、函数、别名3、order by子句一般是放在查询语句的最后面的,limit子句除外
*/
-- 案例1:查询员工信息,要求工资从高到低排序
SELECT*
FROMemployees
ORDER BYsalary DESC;-- 案例2:查询员工信息,要求工资从低到高排序
SELECT*
FROMemployees
ORDER BYsalary;-- 案例3:查询部门编号>=90的员工信息,按入职时间先后进行排序(升序)[添加筛选条件]
SELECT*
FROMemployees
WHEREdepartment_id >= 90
ORDER BYhiredate ASC;-- 案例4:按年薪的高低显示员工的信息和年薪[按表达式排序]
SELECT*,salary * 12 * ( 1+IFNULL ( commission_pct, 0 ) ) 年薪
FROMemployees
ORDER BYsalary * 12 * ( 1+IFNULL ( commission_pct, 0 ) ) DESC;-- 案例5:按年薪的高低显示员工的信息和年薪[按别名排序]
SELECT*,salary * 12 * ( 1+IFNULL ( commission_pct, 0 ) ) 年薪
FROMemployees
ORDER BY年薪 DESC;-- 案例6:按姓名的长度显示员工的姓名和工资[按函数排序]
SELECTLENGTH( last_name ) 字节长度,last_name,salary
FROMemployees
ORDER BYLENGTH( last_name ) DESC;-- 案例7:查询员工信息,要求先按工资升序排序,再按员工编号降序排序[按多个字段排序]
SELECT*
FROMemployees
ORDER BYsalary ASC,employee_id DESC;
5.3.1 排序查询练习
-- 1. 查询员工的姓名和部门号和年薪,按年薪降序 按姓名升序
SELECTlast_name,department_id,salary * 12 * ( 1+IFNULL ( commission_pct, 0 ) ) 年薪
FROMemployees
ORDER BY年薪 DESC,last_name ASC;-- 2. 选择工资不在 8000 到 17000 的员工的姓名和工资,按工资降序
SELECTlast_name,salary
FROMemployees
WHEREsalary NOT BETWEEN 8000 AND 17000
ORDER BYsalary DESC;-- 3. 查询邮箱中包含 e 的员工信息,并先按邮箱的字节数降序,再按部门号升序
SELECT*,LENGTH( email ) 邮箱字节数
FROMemployees
WHEREemail LIKE '%e%'
ORDER BY邮箱字节数 DESC,department_id ASC;
5.4 常见函数
常见函数:字符函数:length 获取字节个数concat 拼接substr 截取子串instr 返回子串第一次出现的索引trim 去前后指定的空格和字符upper 转换成大写lower 转换成小写lpad 左填充rpad 右填充replace 替换数学函数:round 四舍五入ceil 向上取整floor 向下取整truncate 截断mod 取余rand 获取随机数,返回0-1之间的小数 [0,1)日期函数:now 当前日期+时间curdate 返回当前日期curtime 返回当前时间year 年month 月monthname 以英文形式返回月day 日hour 小时minute 分钟second 秒datediff 返回两个日期相差的天数str_to_date 将字符转换成日期date_format 将日期转换成字符 其他函数:version 当前数据库服务器的版本号database 当前打开的数据库user 当前用户password('字符') 返回该字符的密码形式(自动加密) 注意:8版本不支持此种加密方式md5('字符') 使用md5加密形式对该字符进行加密流程控制函数:if(条件表达式,表达式1,表达式2) 如果条件表达式成立,返回表达式1,否则返回表达式2case(两种情况)case情况一:case 变量或表达式或字段when 常量1 then 值1when 常量2 then 值2 ...else 值nendcase情况二: case when 条件1 then 值1when 条件2 then 值2 ...else 值nend分组函数:max 最大值min 最小值sum 总和avg 平均值count 计算个数
-- 进阶4:常见函数
/*
概念:类似于Java中的方法,将一组逻辑语句封装在方法体中,对外暴露方法名
好处:1、隐藏了实现细节 2、提高代码的重用性
调用:select 函数名(实参列表) [from 表名]
特点:①叫什么(函数名)②干什么(函数的功能)
分类:1、单行函数如:concat、length、ifnull等2、分组函数功能:做统计使用的,又称为统计函数、聚合函数、组函数
*/-- 1.字符函数
-- 1.1 length 获取参数值的字节个数
SELECTLENGTH( 'john' ); #4SELECTLENGTH( '张三丰haha' ); #13-- 获取当前mysql的字符集
SHOW VARIABLES LIKE '%char%';-- 1.2 concat 拼接字符串
SELECTCONCAT( last_name, '_', first_name ) 姓名
FROMemployees;-- 1.3 upper:将指定字符变成大写的,lower:将指定字符变成小写的
SELECTUPPER( 'john' ); #JOHNSELECTLOWER( 'joHn' ); #john-- 案例:将姓变大写,名变小写,然后拼接
SELECTCONCAT( UPPER( last_name ), LOWER( first_name ) ) 姓名
FROMemployees;-- 1.4 substr、substring 注意:索引都是从1开始的-- 方法一:截取从指定索引处后面的所有字符
SELECTSUBSTR( '李莫愁爱上了陆展元', 7 ) out_put; # 陆展元-- 方法二:截取从指定索引处指定字符长度的字符
SELECTSUBSTR( '李莫愁爱上了陆展元', 1, 3 ) out_put; # 李莫愁-- 案例:姓名中首字符大写,其他字符小写然后用_拼接,显示出来
SELECTCONCAT(UPPER( SUBSTR( last_name, 1, 1 ) ),'_',LOWER( SUBSTR( last_name, 2 ) ) ) 姓名
FROMemployees;-- 1.5 instr 返回指定字符在另一个指定字符中第一次出现的索引,如果找不到返回0
SELECTINSTR( '杨不殷六侠悔爱上了殷六侠', '殷八侠' ) AS out_put; # 0SELECTINSTR( '杨不殷六侠悔爱上了殷六侠', '殷六侠' ) AS out_put; # 3-- 1.6 trim -- 方法一:去掉前后的空格
SELECTLENGTH( TRIM( ' 张翠山 ' ) ) AS out_put; # TRIM( ' 张翠山 ' )返回'张翠山'-- 方法二:过滤掉前后指定的字符
SELECTTRIM( 'aa' FROM 'aaaaaaaaa张aaaaaaaaaaaa翠山aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' ) AS out_put;
# a张aaaaaaaaaaaa翠山a-- 1.7 lpad 用指定的字符实现左填充指定长度
SELECTLPAD( '殷素素', 10, 'A' ) AS out_put; # AAAAAAA殷素素SELECTLPAD( '殷素素', 2, 'A' ) AS out_put; # 殷素-- 1.8 rpad 用指定的字符实现右填充指定长度
SELECTRPAD( '殷素素', 12, 'ab' ) AS out_put; # 殷素素ababababa,说明:因为殷素素已经占了3个字符,所以后面只能有9个字符-- 1.9 replace 替换
SELECT REPLACE( '周芷若周芷若周芷若周芷若张无忌爱上了周芷若', '周芷若', '赵敏' ) AS out_put;
# 赵敏赵敏赵敏赵敏张无忌爱上了赵敏
-- 2.数学函数-- 2.1 round -- 方法一:四舍五入
SELECTROUND( - 1.55 );# -2-- 方法二:小数点后保留几位小数
SELECTROUND( 1.567, 2 );# 1.57-- 2.2 ceil 向上取整,返回>=该参数的最小整数
SELECT CEIL(1.002); # 2
SELECT CEIL(-1.02); # -1-- 2.3 floor 向下取整,返回<=该参数的最大整数
SELECT FLOOR(9.8); # 9
SELECT FLOOR(-9.99); # -10-- 2.4 truncate 截断,小数点后保留几位小数
SELECT TRUNCATE(1.69999,1); # 1.6-- 2.5 mod 取余,左边的数是正数,结果就是正的,反之则为负数
/*
mod(a,b) 相当于 a - a/b * b
mod(-10,-3) : -10 - (-10)/(-3) * (-3) = -1
mod(10,-3) : 10 - 10/(-3) * (-3) = 1
*/
SELECT MOD(10,3); # 1
SELECT MOD(10,-3); # 1
SELECT MOD(-10,3); # -1-- 3.日期函数-- 3.1 now 返回当前系统日期+时间
SELECT NOW(); # 2020-10-04 18:12:56-- 3.2 curdate 返回当前系统日期,不包含时间
SELECT CURDATE(); # 2020-10-04-- 3.3 curtime 返回当前时间,不包含日期
SELECT CURTIME(); # 18:16:18-- 3.4 可以获取指定的部分,年、月、日、小时、分钟、秒
SELECT YEAR(NOW()) 年; # 2020
SELECT YEAR('1999-04-28') 年; # 1999SELECT YEAR(hiredate) 年 FROM employees;SELECT MONTH(NOW()) 月; # 10
SELECT MONTHNAME(NOW()) 月; # October-- 3.5 str_to_date 将字符通过指定的格式转换成日期
SELECT STR_TO_DATE('1999-4-28','%Y-%c-%d') 日期; # 1999-04-28-- 案例:查询入职日期为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');-- 3.6 date_format 将日期转换成字符
SELECT DATE_FORMAT(NOW(),'%y年%m月%d日') AS 日期; # 20年10月04日-- 案例:查询有奖金的员工名和入职日期,要求入职日期的格式是:(xx月/xx日 xx年)
SELECTlast_name,DATE_FORMAT( hiredate, '%m月/%d日 %y年' ) 入职日期
FROMemployees
WHEREsalary IS NOT NULL;-- 4.其他函数-- 4.1 version 查看当前系统的mysql版本号
SELECT VERSION(); # 8.0.19-- 4.2 database 查看当前所在数据库
SELECT DATABASE(); # myemployees-- 4.3 user 查看当前用户
SELECT USER(); # root@localhost-- 5.流程控制函数-- 5.1 if函数 实现if-else的效果
SELECT IF(10>5,'大','小'); # 大SELECTlast_name,commission_pct,
IF( commission_pct IS NULL, '没奖金,呵呵', '有奖金,嘻嘻' ) 备注
FROMemployees;-- 5.2 case函数-- 5.2.1 case函数的使用一:实现switch-case的效果
/*
Java中
switch(表达式){
case 常量1:执行语句1;break;
case 常量2:执行语句2;break;
...
defaule:执行语句n;break;mysql中
case 要判断的字段或表达式
when 常量1 then 要显示的值1或语句1
when 常量2 then 要显示的值2或语句2
...
else 要显示的值n或语句n
end
*//*
案例:查询员工的工资,要求
部门号=30,显示的工资为1.1倍
部门号=40,显示的工资为1.2倍
部门号=50,显示的工资为1.3倍
其他部门,显示的工资为原工资
*/
SELECTsalary 原始工资,department_id,
CASEdepartment_id WHEN 30 THENsalary * 1.1 WHEN 40 THENsalary * 1.2 WHEN 50 THENsalary * 1.3 ELSE salary END AS 新工资
FROMemployees;-- 5.2.2 case函数的使用二:类似于 多重if的效果
/*
java中:
if(条件1){语句1;
}else if(条件2){语句2;
}
...
else{语句n;
}mysql中:
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 THEN 'C'
ELSE 'D'
END AS 工资级别
FROM employees;
5.4.1 常见函数练习
-- 1. 显示系统时间(注:日期+时间)
SELECT NOW();-- 2. 查询员工号,姓名,工资,以及工资提高百分之 20%后的结果(new salary)
SELECTemployee_id,last_name,salary,salary * ( 1+0.2 ) AS "new salary"
FROMemployees;-- 3. 将员工的姓名按首字母排序,并写出姓名的长度(length)
SELECTlast_name,LENGTH( last_name ) 姓名长度,SUBSTR( last_name, 1, 1 ) 首字母
FROMemployees
ORDER BY首字母 ASC;-- 4. 做一个查询,产生下面的结果
/*
<last_name> earns <salary> monthly but wants <salary*3>Dream SalaryKing earns 24000 monthly but wants 72000
*/
SELECTCONCAT(last_name,' earns ',salary,' monthly but wants ',salary * 3 ) AS "Dream Salary"
FROMemployees
WHEREsalary = 24000;-- 5. 使用 case-when,按照下面的条件:
/*job grade AD_PRES A ST_MAN BIT_PROG CSA_REP DST_CLERK E产生下面的结果
last_name job_id GradeK_ing AD_PRES A*/
SELECT last_name,job_id,
CASE job_idWHEN 'AD_PRES' THEN 'A'WHEN 'ST_MAN' THEN 'B'WHEN 'IT_PROG' THEN 'C'WHEN 'SA_REP' THEN 'D'WHEN 'ST_CLERK' THEN 'E'
END AS 'Grade' FROM employees WHERE job_id = 'AD_PRES';
5.5 分组函数
-- 进阶4:常见函数2-- 分组函数
/*
功能:用作统计使用,又称为聚合函数或统计函数或组函数分类:
sum 求和 、 avg 平均值 、 max 最大值 、 min 最小值 、 count 计算个数特点:
1、sum、avg一般用于处理数值型max、min、count可以处理任何类型
2、以上分组函数都忽略null值3、可以和distinct搭配实现去重的运算4、count函数的单独介绍
count(字段):统计该字段非空值的个数
一般使用count(*)用作统计行数
另外 count(1)也是用来统计行数5、和分组函数一同查询的字段要求是group by后的字段
*/-- 1.简单的使用
SELECT SUM(salary) 工资总和 FROM employees;
SELECT AVG(salary) 工资平均值 FROM employees;
SELECT MIN(salary) 最小工资 FROM employees;
SELECT MAX(salary) 最大工资 FROM employees;
SELECT COUNT(salary) 总共多少份工资 FROM employees;SELECTSUM( salary ) 工资总和,AVG( salary ) 工资平均值,MIN( salary ) 最小工资,MAX( salary ) 最大工资,COUNT( salary ) 总共多少份工资
FROMemployees;SELECTSUM( salary ) 工资总和,ROUND( AVG( salary ), 2 ) "工资平均值(保留2位小数)",MIN( salary ) 最小工资,MAX( salary ) 最大工资,COUNT( salary ) 总共多少份工资
FROMemployees;-- 2.参数支持哪些类型
SELECT SUM(last_name),AVG(last_name) FROM employees; # 不支持
SELECT SUM(hiredate) ,AVG(hiredate) FROM employees; # 没必要
SELECT MAX(last_name),MIN(last_name) FROM employees;
SELECT MAX(hiredate),MIN(hiredate) FROM employees;
SELECT COUNT(commission_pct) FROM employees;
SELECT COUNT(last_name) FROM employees;-- 3.是否忽略null:都忽略null值
SELECTSUM( commission_pct ),AVG( commission_pct ),SUM( commission_pct ) / 35,SUM( commission_pct ) / 107
FROMemployees; SELECT MAX(commission_pct) ,MIN(commission_pct) FROM employees;
SELECT COUNT(commission_pct) FROM employees;
SELECT commission_pct FROM employees;-- 4.和distinct搭配
SELECT SUM(DISTINCT salary),SUM(salary) FROM employees;SELECT COUNT(DISTINCT salary),COUNT(salary) FROM employees;-- 5.count函数的详细介绍
/*
效率:
MYISAM存储引擎下 ,COUNT(*)的效率高
INNODB存储引擎下,COUNT(*)和COUNT(1)的效率差不多,比COUNT(字段)要高一些
*/
SELECT COUNT(salary) FROM employees;SELECT COUNT(*) FROM employees; # 经常用来统计行数 107SELECT COUNT(1) FROM employees; # 107-- 6.和分组函数一同查询的字段有限制
SELECT AVG(salary),employee_id FROM employees; #报错
5.5.1 分组函数练习
-- 1. 查询公司员工工资的最大值,最小值,平均值(保留两位小数),总和,并按 job_id 升序
SELECTMAX( salary ) 最大值,MIN( salary ) 最小值,ROUND( AVG( salary ), 2 ) 平均值,SUM( salary ) 总和
FROMemployees
ORDER BYjob_id ASC;-- 2. 查询员工最高工资和最低工资的差距(DIFFERENCE)
SELECT( MAX( salary ) - MIN( salary ) ) DIFFERENCE
FROMemployees;-- 3. 查询各个管理者手下员工的最低工资,其中最低工资不能低于 6000,没有管理者的员工不计算在内
SELECTMIN( salary ),manager_id
FROMemployees
WHEREmanager_id IS NOT NULL
GROUP BYmanager_id
HAVINGMIN( salary ) >= 6000;-- 4. 查询所有部门的编号,员工数量和工资平均值,并按平均工资降序
SELECTdepartment_id,count( * ),AVG( Salary )
FROMemployees
GROUP BYdepartment_id
ORDER BYAVG( salary ) DESC;-- 5. 选择具有各个 job_id 的员工人数
SELECTjob_id,COUNT( * )
FROMemployees
GROUP BYjob_id;-- 6. 查询员工表中的最大入职时间和最小入职时间的相差天数(DIFFERENCE)
SELECTDATEDIFF( MAX( hiredate ), MIN( hiredate ) ) DIFFERENCE
FROMemployees;-- 7. 查询某人从出生到现在的总天数
SELECTDATEDIFF( NOW( ), '1999-04-28' ) 总天数;-- 8.查询部门编号为90的员工个数
SELECTCOUNT( * )
FROMemployees 个数
WHEREdepartment_id = 90;
5.6 分组查询
-- 进阶5:分组查询
/*语法: [ ]里面的内容表示可以省略的select 查询列表 ①from 表 ②[where 筛选条件] ③group by 分组的字段 ④[having 分组后的筛选] ⑤[order by 排序的字段]; ⑥执行顺序:② -> ③ -> ④ - > ⑤ -> ① -> ⑥
注意:和分组函数一同查询的字段必须是group by后出现的字段特点:1.分组查询中的筛选条件分为两类数据源 位置 关键字分组前筛选 原始表(真实存在的表) group by子句的前面 where分组后筛选 分组后的结果集 group by子句的后面 having① 分组函数做筛选条件,肯定是放在having子句中② 能用分组前筛选的,就优先考虑使用分组前筛选(性能问题)2.group by子句支持单个字段分组,多个字段分组(多个字段之间用逗号隔开并且没有顺序要求),表达式或函数(用得较少)3.也可以添加排序(排序放在整个分组查询的最后)
*/
-- 1.简单的分组查询-- 案例1:查询每个工种的最高工资
SELECTMAX( salary ),job_id
FROMemployees
GROUP BYjob_id;-- 案例2:查询每个位置上的部门个数
SELECTCOUNT( * ),location_id
FROMdepartments
GROUP BYlocation_id;-- 2.添加分组前的筛选条件-- 案例1:查询邮箱中包含a字符的,每个部门的平均工资
SELECTAVG( salary ),department_id
FROMemployees
WHEREemail LIKE '%a%'
GROUP BYdepartment_id;-- 案例2:查询有奖金的每个领导手下员工的最高工资
SELECTMAX( salary ),manager_id
FROMemployees
WHEREcommission_pct IS NOT NULL
GROUP BYmanager_id;-- 3.添加分组后的筛选条件-- 案例1:查询哪个部门的员工个数>2-- ① 查询每个部门的员工个数
SELECTCOUNT( * ),department_id
FROMemployees
GROUP BYdepartment_id;-- ② 根据①的结果进行筛选,查询哪个部门的员工个数>2
SELECTCOUNT( * ),department_id
FROMemployees
GROUP BYdepartment_id
HAVINGCOUNT( * ) > 2;-- 案例2:查询每个工种有奖金的员工的最高工资>12000的工种编号和最高工资-- ① 查询每个工种有奖金的员工的最高工资
SELECTjob_id,MAX( salary )
FROMemployees
WHEREcommission_pct IS NOT NULL
GROUP BYjob_id;-- ② 根据①的结果继续筛选,最高工资>12000
SELECTjob_id,MAX( salary )
FROMemployees
WHEREcommission_pct IS NOT NULL
GROUP BYjob_id
HAVINGMAX( salary ) > 12000;-- 案例3:查询领导编号>102的每个领导手下的最低工资>5000的领导编号和最低工资
SELECTmanager_id,MIN( salary )
FROMemployees
WHEREmanager_id > 102
GROUP BYmanager_id
HAVINGMIN( salary ) > 5000;-- 4.按表达式或函数分组-- 案例1:按员工姓名的长度分组,查询每一组的员工个数,筛选员工个数>5的有哪些-- ① 查询每个长度的员工个数
SELECTCOUNT( * ),LENGTH( last_name ) 姓名长度
FROMemployees
GROUP BYLENGTH( last_name );-- ② 添加筛选条件
SELECTCOUNT( * ) c,LENGTH( last_name ) 姓名长度
FROMemployees
GROUP BY姓名长度
HAVINGc > 5;-- 5.按多个字段进行分组-- 案例1:查询每个部门每个工种的员工的平均工资
SELECTAVG( salary ),department_id,job_id
FROMemployees
GROUP BYdepartment_id,job_id;-- 6.添加排序-- 案例1:查询每个部门每个工种的员工的平均工资,并且按平均工资的高低显示,要求部门id不能为null,平均工资要大于10000
SELECTAVG( salary ),department_id,job_id
FROMemployees
WHEREdepartment_id IS NOT NULL
GROUP BYdepartment_id,job_id
HAVINGAVG( salary ) > 10000
ORDER BYAVG( salary ) DESC;
5.6.1 分组查询练习
-- 1. 查询各 job_id 的员工工资的最大值,最小值,平均值,总和,并按 job_id 升序
SELECTjob_id,MAX( salary ) 最大值,MIN( salary ) 最小值,ROUND( AVG( salary ), 2 ) 平均值,SUM( salary ) 总和
FROMemployees
GROUP BYjob_id
ORDER BYjob_id ASC;-- 2. 查询员工最高工资和最低工资的差距(DIFFERENCE)
SELECT( MAX( salary ) - MIN( salary ) ) DIFFERENCE
FROMemployees;-- 3. 查询各个管理者手下员工的最低工资,其中最低工资不能低于 6000,没有管理者的员工不计算在内
SELECTmanager_id,MIN( salary ) 最低工资
FROMemployees
WHEREmanager_id IS NOT NULL
GROUP BYmanager_id
HAVINGMIN( salary ) > 6000;-- 4. 查询所有部门的编号,员工数量和工资平均值,并按平均工资降序
SELECTdepartment_id,COUNT( * ) 员工数量,AVG( salary ) 平均工资
FROMemployees
GROUP BYdepartment_id
ORDER BYAVG( salary ) DESC;-- 5. 查询各个 job_id 的员工人数
SELECTjob_id,COUNT( * ) 员工人数
FROMemployees
GROUP BYjob_id;
5.7 连接查询
-- 进阶6:连接查询
/*
含义:又称多表查询,当查询的字段来自于多个表时,就会用到连接查询笛卡尔乘积现象:表1 有m行,表2有n行,结果=m*n行
发生原因:没有有效的连接条件
如何避免:添加有效的连接条件分类:按年代分类:sql92标准: 仅仅支持内连接sql99标准(推荐使用): 支持内连接+外连接(左外和右外)+交叉连接按功能分类:内连接:等值连接非等值连接自连接外连接:左外连接右外连接全外连接(mysql不支持)交叉连接
*/
USE girls;SELECT * FROM beauty;
SELECT * FROM boys;SELECT`name`,boyName
FROMbeauty,boys
WHEREbeauty.boyfriend_id = boys.id;-- sql92标准-- 1. 等值连接
/*
① 多表等值连接的结果为多表的交集部分
② n表连接,至少需要n-1个连接条件
③ 多表的顺序没有要求
④ 一般需要为表起别名
⑤ 可以搭配前面介绍的所有子句使用,比如排序、分组、筛选
*/-- 案例1:查询女神名和对应的男神名
SELECT`name`,boyName
FROMbeauty,boys
WHEREbeauty.boyfriend_id = boys.id;-- 案例2:查询员工名和对应的部门名
SELECTlast_name,department_name
FROMemployees,departments
WHEREdepartments.`department_id` = employees.`department_id`;-- 1.2 为表起别名
/*
①提高语句的简洁度
②区分多个重名的字段注意:如果为表起了别名,则查询的字段就不能使用原来的表名去限定
*/-- 案例1:查询员工名、工种号、工种名
SELECTlast_name,e.job_id,job_title
FROMemployees e,jobs j
WHEREe.job_id = j.job_id;-- 1.3 两个表的顺序可以调换-- 案例1:查询员工名、工种号、工种名
SELECTlast_name,e.job_id,job_title
FROMjobs j,employees e
WHEREe.`job_id` = j.`job_id`;-- 1.4 加筛选-- 案例1:查询有奖金的员工名、部门名
SELECTlast_name,department_name,commission_pct
FROMemployees e,departments d
WHEREe.`department_id` = d.`department_id` AND e.`commission_pct` IS NOT NULL;-- 案例2:查询城市名中第二个字符为o的部门名和城市名
SELECTdepartment_name,city
FROMdepartments d,locations l
WHEREd.`location_id` = l.`location_id` AND city LIKE '_o%';-- 1.5 加分组-- 案例1:查询每个城市的部门个数
SELECTcity,COUNT( * ) 个数
FROMdepartments d,locations l
WHEREd.location_id = l.location_id
GROUP BYcity;-- 案例2:查询有奖金的每个部门的部门名和部门的领导编号和该部门的最低工资
SELECTdepartment_name 部门名,d.manager_id 部门领导编号,MIN( salary ) 最低工资
FROMemployees e,departments d
WHEREe.department_id = d.department_id AND commission_pct IS NOT NULL
GROUP BYdepartment_name,d.manager_id;-- 1.6 加排序-- 案例1:查询每个工种的工种名和员工的个数,并且按员工个数降序
SELECTjob_title,COUNT( * ) 员工个数
FROMemployees e,jobs j
WHEREe.job_id = j.job_id
GROUP BYjob_title
ORDER BYCOUNT( * ) DESC;-- 1.7 实现三表连接-- 1.案例:查询员工名、部门名和所在的城市
SELECTlast_name,department_name,city
FROMemployees e,departments d,locations l
WHEREe.department_id = d.department_id AND d.location_id = l.location_id;-- 2.非等值连接-- 案例1:查询员工的工资和工资级别
SELECTsalary,grade_level
FROMemployees e,job_grades g
WHEREsalary BETWEEN g.lowest_sal AND g.highest_sal;-- 3.自连接-- 案例1:查询 员工名和上级的名称
SELECTe.employee_id,e.last_name,m.employee_id 领导id,m.last_name 领导名字
FROMemployees e,employees m
WHEREe.manager_id = m.employee_id;
5.7.1 连接查询练习
USE myemployees;-- 1.显示所有员工的姓名,部门号和部门名称。
SELECTlast_name,e.department_id,department_name
FROMemployees e,departments d
WHEREe.department_id = d.department_id;-- 2.查询90号部门员工的job_id和90号部门的location_id
SELECTe.department_id,job_id,location_id
FROMemployees e,departments d
WHEREe.department_id = d.department_id AND e.department_id = 90;-- 3. 选择所有有奖金的员工的last_name , department_name , location_id , city
SELECTlast_name,department_name,l.location_id,city
FROMemployees e,locations l,departments d
WHEREe.department_id = d.department_id AND d.location_id = l.location_id AND e.commission_pct IS NOT NULL;-- 4.选择city在Toronto工作的员工的last_name , job_id , department_id , department_name
SELECTlast_name,job_id,d.department_id,department_name,city
FROMemployees e,locations l,departments d
WHEREe.department_id = d.department_id AND d.location_id = l.location_id AND l.city = 'Toronto';-- 5.查询每个工种、每个部门的部门名、工种名和最低工资
SELECTd.department_name 部门名,j.job_title 工种名,MIN( salary ) 最低工资
FROMdepartments d,jobs j,employees e
WHEREd.department_id = e.department_id AND e.job_id = j.job_id
GROUP BYd.department_name,j.job_title;-- 6.查询每个国家下的部门个数大于2的国家编号
SELECTcountry_id,COUNT( * ) 部门个数
FROMdepartments d,locations l
WHEREd.location_id = l.location_id
GROUP BYcountry_id
HAVINGCOUNT( * ) > 2;-- 7、选择指定员工的姓名,员工号,以及他的管理者的姓名和员工号,结果类似于下面的格式
/*employees Emp# manager Mgr#kochhar 101 king 100
*/SELECTe.last_name employees,e.employee_id "Emp#",m.last_name manager,m.employee_id "Mgr#"
FROMemployees e,employees m
WHEREe.manager_id = m.employee_id AND e.last_name = 'kochhar';
5.8 sql99连接查询
-- sql99语法
/*
语法: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 连接条件;分类:等值连接非等值连接自连接特点:
①添加排序、分组、筛选
②inner可以省略
③筛选条件放在where后面,连接条件放在on后面,提高分离性,便于阅读
④inner join连接和sql92语法中的等值连接效果是一样的,都是查询多表的交集
*/-- 1.1 等值连接-- 案例1:查询员工名、部门名
SELECTlast_name,department_name
FROMemployees eINNER JOIN departments d ON e.department_id = d.department_id;-- 案例2:查询名字中包含e的员工名和工种名(添加筛选)
SELECTlast_name,job_title
FROMemployees eINNER JOIN jobs j ON e.job_id = j.job_id
WHEREe.last_name LIKE '%e%';-- 案例3:查询部门个数>3的城市名和部门个数,(添加分组+筛选)
SELECTcity,COUNT( * ) 部门个数
FROMdepartments dINNER JOIN locations l ON d.location_id = l.location_id
GROUP BYcity
HAVINGCOUNT( * ) > 3;-- 案例4:查询哪个部门的员工个数>3的部门名和员工个数,并按个数降序(添加排序)
SELECTdepartment_name,COUNT( * ) 员工个数
FROMdepartments dINNER JOIN employees e ON d.department_id = e.department_id
GROUP BYdepartment_name
HAVINGCOUNT( * ) > 3
ORDER BYCOUNT( * ) DESC;-- 案例5:查询员工名、部门名、工种名,并按部门名降序(添加三表连接)
SELECTlast_name,department_name,job_title
FROMemployees eINNER JOIN departments d ON e.department_id = d.department_idINNER JOIN jobs j ON e.job_id = j.job_id
ORDER BYdepartment_name DESC;-- 1.2 非等值连接-- 案例1:查询员工的工资级别
SELECTsalary,grade_level
FROMemployees eJOIN job_grades j ON e.salary BETWEEN j.lowest_sal AND j.highest_sal;-- 案例2:查询工资级别>20的个数,并且按工资级别降序
SELECTgrade_level,count( * ) 个数
FROMemployees eJOIN job_grades j ON e.salary BETWEEN j.lowest_sal AND j.highest_sal
GROUP BYgrade_level
HAVINGCOUNT( * ) > 20
ORDER BYgrade_level DESC;-- 1.3 自连接-- 案例1:查询员工的名字、上级的名字
SELECTe.last_name,m.last_name
FROMemployees eJOIN employees m ON e.manager_id = m.employee_id;-- 案例2:查询姓名中包含字符k的员工的名字、上级的名字
SELECTe.last_name,m.last_name
FROMemployees eJOIN employees m ON e.manager_id = m.employee_id
WHEREe.last_name LIKE '%k%';-- 2.外连接
/*
应用场景:用于查询一个表中有,另一个表没有的记录特点:1、外连接的查询结果为主表中的所有记录如果从表中有和它匹配的,则显示匹配的值如果从表中没有和它匹配的,则显示null外连接查询结果=内连接结果+主表中有,而从表中没有的记录2、左外连接,left join左边的是主表右外连接,right join右边的是主表3、左外和右外交换两个表的顺序,可以实现同样的效果 4、全外连接=内连接的结果+表1中有但表2没有的+表2中有但表1没有的
*/-- 案例1:查询男朋友 不在男神表的的女神名-- 左外连接
SELECTb.NAME
FROMbeauty bLEFT JOIN boys bo ON b.boyfriend_id = bo.id
WHEREbo.id IS NULL;-- 案例2:查询哪个部门没有员工-- 左外连接
SELECTd.*
FROMdepartments dLEFT JOIN employees e ON d.department_id = e.department_id
WHEREe.employee_id IS NULL;-- 右外连接
SELECTd.*
FROMemployees eRIGHT JOIN departments d ON d.department_id = e.department_id
WHEREe.employee_id IS NULL;-- 全外连接,mysql不支持
USE girls;
SELECTb.*,bo.*
FROMbeauty bFULL JOIN boys bo ON b.boyfriend_id = bo.id;-- 交叉连接,相当于笛卡尔乘积
SELECT b.*,bo.*
FROM beauty b
CROSS JOIN boys bo;-- sql92和sql99的区别
/*功能:sql99支持的较多可读性:sql99实现连接条件和筛选条件的分离,可读性较高
*/
5.8.1 sql99连接查询练习
-- 1.查询编号>3 的女神的男朋友信息,如果有则列出详细,如果没有,用 null 填充
USE girls;
SELECTb.id,b.NAME,bo.*
FROMbeauty bLEFT JOIN boys bo ON b.boyfriend_id = bo.id
WHEREb.id > 3;-- 2.查询哪个城市没有部门
USE myemployees;
SELECTl.city
FROMlocations lLEFT JOIN departments d ON l.location_id = d.location_id
WHEREd.department_id IS NULL;-- 3.查询部门名为 SAL 或 IT 的员工信息
SELECTd.department_name,e.*
FROMdepartments dLEFT JOIN employees e ON d.department_id = e.department_id
WHEREd.department_name IN ( 'SAL', 'IT' );
5.9 子查询
-- 进阶7:子查询
/*
含义:
出现在其他语句中的select语句,称为子查询或内查询
外部的查询语句,称为主查询或外查询分类:
按子查询出现的位置:select后面:仅仅支持标量子查询(结果集只有一行一列)from后面:支持表子查询where或having后面:★ (重点)标量子查询(结果集只有一行一列) √ (重点)列子查询 (结果集只有一列多行) √ (重点)行子查询(结果集有一行多列)exists后面(相关子查询)表子查询
按结果集的行列数不同:标量子查询(结果集只有一行一列)列子查询(结果集只有一列多行),也可以叫做多行子查询行子查询(结果集有一行多列)表子查询(结果集一般为多行多列)
*/-- 1.where或having后面
/*
1、标量子查询(单行子查询):结果集为一行一列
2、列子查询(多行子查询) :结果集为多行一列
3、行子查询(多列多行) :结果集为一行多列特点:
①子查询放在小括号内
②子查询一般放在条件的右侧
③标量子查询,一般搭配着单行操作符使用> < >= <= = <>列子查询,一般搭配着多行操作符使用in、any/some、all④子查询的执行优先于主查询执行,主查询的条件用到了子查询的结果
*/-- 1.1 标量子查询(单行子查询或一行一列)-- 案例1:谁的工资比 Abel 高?
-- ①查询Abel的工资
SELECTsalary
FROMemployees
WHERElast_name = 'Abel';-- ②查询员工的信息,满足 salary>①结果
SELECT*
FROMemployees
WHEREsalary > ( SELECT salary FROM employees WHERE last_name = 'Abel' );-- 案例2:返回job_id与141号员工相同,salary比143号员工多的员工 姓名,job_id 和工资
-- ①查询141号员工的job_id
SELECTjob_id
FROMemployees
WHEREemployee_id = 141-- ②查询143号员工的salary
SELECTsalary
FROMemployees
WHEREemployee_id = 143;-- ③查询员工的姓名,job_id 和工资,要求job_id=①并且salary>②
SELECTlast_name,job_id,salary
FROMemployees
WHEREjob_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
-- ①查询公司的 最低工资
SELECTMIN( salary )
FROMemployees;-- ②查询last_name,job_id和salary,要求salary=①
SELECTlast_name,job_id,salary
FROMemployees
WHEREsalary = ( SELECT MIN( salary ) FROM employees );-- 案例4:查询最低工资大于50号部门最低工资的部门id和其最低工资
-- ①查询50号部门的最低工资
SELECTMIN( salary )
FROMemployees
WHEREdepartment_id = 50;-- ②查询每个部门的最低工资
SELECTdepartment_id,MIN( salary )
FROMemployees
GROUP BYdepartment_id;-- ③ 在②基础上筛选,满足min(salary)>①
SELECTMIN( salary ),department_id
FROMemployees
GROUP BYdepartment_id
HAVINGMIN( salary ) > (SELECTMIN( salary ) FROMemployees WHEREdepartment_id = 50 );-- 非法使用标量子查询
SELECTMIN( salary ),department_id
FROMemployees
GROUP BYdepartment_id
HAVINGMIN( salary ) > ( SELECT salary FROM employees WHERE department_id = 250 );-- 1.2 列子查询(多行子查询)-- 案例1:返回location_id是1400或1700的部门中的所有员工姓名
-- ①查询location_id是1400或1700的部门编号
SELECT DISTINCTdepartment_id
FROMdepartments
WHERElocation_id IN ( 1400, 1700 );-- ②查询员工姓名,要求部门号是①列表中的某一个
SELECTlast_name
FROMemployees
WHEREdepartment_id IN (SELECT DISTINCTdepartment_id FROMdepartments WHERElocation_id IN ( 1400, 1700 ) );-- 或
SELECTlast_name
FROMemployees
WHEREdepartment_id = ANY (SELECT DISTINCTdepartment_id FROMdepartments WHERElocation_id IN ( 1400, 1700 ) );-- 案例2:返回其它工种中比job_id为‘IT_PROG’工种任一工资低的员工的员工号、姓名、job_id 以及salary-- ①查询job_id为‘IT_PROG’部门任一工资
SELECT DISTINCTsalary
FROMemployees
WHEREjob_id = 'IT_PROG';-- ②查询员工号、姓名、job_id 以及salary,salary<(①)的任意一个
SELECTemployee_id,last_name,job_id,salary
FROMemployees
WHEREsalary < ANY ( SELECT DISTINCT salary FROM employees WHERE job_id = 'IT_PROG' ) AND job_id <> 'IT_PROG';-- 或
/*
小于任意一个,应该是小于最大值
如果是小于所有的值,那就应该是小于最小值
*/
SELECTlast_name,employee_id,job_id,salary
FROMemployees
WHEREsalary < (SELECTMAX( salary ) FROMemployees WHEREjob_id = 'IT_PROG' ) AND job_id <> 'IT_PROG';-- 案例3:返回其它部门中比job_id为‘IT_PROG’部门所有工资都低的员工 的员工号、姓名、job_id 以及salary
SELECTemployee_id,last_name,job_id,salary
FROMemployees
WHEREsalary < ALL ( SELECT DISTINCT salary FROM employees WHERE job_id = 'IT_PROG' ) AND job_id <> 'IT_PROG';-- 或
SELECTlast_name,employee_id,job_id,salary
FROMemployees
WHEREsalary < (SELECTMIN( salary ) FROMemployees WHEREjob_id = 'IT_PROG' ) AND job_id <> 'IT_PROG';-- 1.3 行子查询(一行多列或多行多列)-- 案例1:查询员工编号最小并且工资最高的员工信息-- 方法一:
SELECT*
FROMemployees
WHERE( employee_id, salary ) = (SELECTMIN( employee_id ),MAX( salary ) FROMemployees );-- 方法二:-- ①查询最小的员工编号
SELECTMIN( employee_id )
FROMemployees;-- ②查询最高工资
SELECTMAX( salary )
FROMemployees;-- ③查询员工信息
SELECT*
FROMemployees
WHEREemployee_id = ( SELECT MIN( employee_id ) FROM employees ) AND salary = ( SELECT MAX( salary ) FROM employees );-- 2.select后面
/*
仅仅支持标量子查询
*/-- 案例1:查询每个部门的员工个数
SELECTd.*,(SELECTcount( * ) FROMemployees e WHEREe.department_id = d.department_id ) 员工数
FROMdepartments d;-- 案例2:查询员工号=102的部门名
SELECT(SELECTdepartment_name FROMdepartments dINNER JOIN employees e ON d.department_id = e.department_id WHEREe.employee_id = 102 ) 部门名;-- 3.from后面
/*
将子查询结果充当一张表,要求必须起别名
*/
-- 案例1:查询每个部门的平均工资的工资等级-- ①查询每个部门的平均工资
SELECTdepartment_id,AVG( salary )
FROMemployees
GROUP BYdepartment_id;-- ② 连接①的结果集和job_grades表,筛选条件平均工资 between lowest_sal and highest_sal
SELECTj.grade_level,ag_dep.*
FROM(SELECTdepartment_id,AVG( salary ) ag FROMemployees GROUP BYdepartment_id ) ag_depINNER JOIN job_grades j ON ag_dep.ag BETWEEN lowest_sal AND highest_sal;-- 4.exists后面(相关子查询)
/*
语法:
exists(完整的查询语句)
结果:
1或0
*/
SELECT EXISTS(SELECT employee_id FROM employees WHERE salary=300000);-- 案例1:查询有员工的部门名
-- in
SELECTdepartment_name
FROMdepartments d
WHEREd.department_id IN ( SELECT department_id FROM employees );-- exists
SELECTdepartment_name
FROMdepartments d
WHEREEXISTS (SELECT* FROMemployees e WHEREd.department_id = e.department_id );-- 案例2:查询没有女朋友的男神信息
-- in
USE girls;
SELECTbo.*
FROMboys bo
WHEREbo.id NOT IN (SELECTb.boyfriend_id FROMbeauty b WHEREbo.id = b.boyfriend_id );-- exists
USE girls;
SELECTbo.*
FROMboys bo
WHERENOT EXISTS (SELECT* FROMbeauty b WHEREb.boyfriend_id = bo.id );
5.9.1 子查询练习
-- 1. 查询和 Zlotkey 相同部门的员工姓名和工资-- ①查询Zlotkey的部门
SELECTdepartment_id
FROMemployees
WHERElast_name = 'Zlotkey';-- ②查询部门号=①的姓名和工资(标量子查询)
SELECTlast_name,salary
FROMemployees
WHEREdepartment_id = ( SELECT department_id FROM employees WHERE last_name = 'Zlotkey' );-- 2. 查询工资比公司平均工资高的员工的员工号,姓名和工资。-- ①查询平均工资
SELECTAVG( salary )
FROMemployees;-- ②查询工资>①的员工号,姓名和工资。
SELECTemployee_id,last_name,salary
FROMemployees
WHEREsalary > ( SELECT AVG( salary ) FROM employees );-- 3. 查询各部门中工资比本部门平均工资高的员工的员工号, 姓名和工资-- ①查询各部门的平均工资
SELECTdepartment_id,AVG( salary )
FROMemployees
GROUP BYdepartment_id;-- ②连接①的结果集和employees表,进行筛选
SELECTemployee_id,last_name,salary,e.department_id
FROMemployees eINNER JOIN (SELECTdepartment_id,AVG( salary ) s FROMemployees GROUP BYdepartment_id ) da ON da.department_id = e.department_id
WHEREe.salary > da.s;-- 4. 查询和姓名中包含字母 u 的员工在相同部门的员工的员工号和姓名-- ①查询姓名中包含字母u的员工的部门(一列多行)
SELECT DISTINCTdepartment_id
FROMemployees
WHERElast_name LIKE '%u%';-- ② 查询部门号=①中的任意一个的员工号和姓名
SELECTemployee_id,last_name
FROMemployees
WHEREdepartment_id IN ( SELECT DISTINCT department_id FROM employees WHERE last_name LIKE '%u%' );-- 5. 查询在部门的 location_id 为 1700 的部门工作的员工的员工号-- ①查询location_id为1700的部门(一列多行)
SELECTdepartment_id
FROMdepartments dINNER JOIN locations l ON d.location_id = l.location_id
WHEREd.location_id = 1700;-- ②查询部门号=①中的任意一个的员工号(使用=ANY,等价于使用in)
SELECTemployee_id
FROMemployees
WHEREdepartment_id = ANY (SELECTdepartment_id FROMdepartments dINNER JOIN locations l ON d.location_id = l.location_id WHEREd.location_id = 1700 );-- 6. 查询管理者是 K_ing 的员工姓名和工资-- ①查询姓名为K_ing的员工编号(一列多行)
SELECTemployee_id
FROMemployees
WHERElast_name = 'K_ing';-- ②查询哪个员工的manager_id = ①
SELECTlast_name,salary
FROMemployees
WHEREmanager_id IN ( SELECT employee_id FROM employees WHERE last_name = 'K_ing');-- 7. 查询工资最高的员工的姓名,要求 first_name 和 last_name 显示为一列,列名为 姓.-- ①查询最高工资(标量子查询)
SELECTMAX( salary )
FROMemployees;-- ②查询工资=①的姓.名
SELECTCONCAT( first_name, ' ', last_name ) 姓
FROMemployees
WHEREsalary = ( SELECT MAX( salary ) FROM employees );
-- 1. 查询工资最低的员工信息: last_name, salary-- ①查询最低的工资
SELECTMIN( salary )
FROMemployees;-- ②查询last_name,salary,要求salary=①
SELECTlast_name,salary
FROMemployees
WHEREsalary = ( SELECT MIN( salary ) FROM employees );-- 2. 查询平均工资最低的部门信息-- 方式一:
-- ①查询各部门的平均工资
SELECTdepartment_id,AVG( salary )
FROMemployees
GROUP BYdepartment_id;-- ② 查询①结果上的最低平均工资
SELECTMIN( s )
FROM(SELECTdepartment_id,AVG( salary ) s FROMemployees GROUP BYdepartment_id ) da;-- ③查询哪个部门的平均工资=②
SELECTdepartment_id,AVG( salary ) 平均工资
FROMemployees
GROUP BYdepartment_id
HAVING平均工资 = (SELECTMIN( s ) FROM(SELECTdepartment_id,AVG( salary ) s FROMemployees GROUP BYdepartment_id ) da );-- ④查询部门信息
SELECTd.*
FROMdepartments d
WHEREd.department_id = (SELECTdepartment_id FROMemployees GROUP BYdepartment_id HAVINGAVG( salary ) = (SELECTMIN( da.s ) FROM(SELECTdepartment_id,AVG( salary ) s FROMemployees GROUP BYdepartment_id ) da ) );-- 方式二:
-- ①各部门的平均工资
SELECTdepartment_id,AVG( salary )
FROMemployees
GROUP BYdepartment_id;-- ②求出最低平均工资的部门编号
SELECTdepartment_id
FROMemployees
GROUP BYdepartment_id
ORDER BYAVG( salary ) ASC LIMIT 1;-- ③查询部门信息
SELECT*
FROMdepartments
WHEREdepartment_id = (SELECTdepartment_id FROMemployees GROUP BYdepartment_id ORDER BYAVG( salary ) ASC LIMIT 1 );-- 3. 查询平均工资最低的部门信息和该部门的平均工资
-- ①各部门的平均工资,再筛选工资最低的部门编号
SELECTdepartment_id,AVG( salary )
FROMemployees
GROUP BYdepartment_id
ORDER BYAVG( salary ) ASC LIMIT 1;-- ② 根据①查询部门信息
SELECTd.*,ag
FROMdepartments dINNER JOIN (SELECTdepartment_id,AVG( salary ) ag FROMemployees GROUP BYdepartment_id ORDER BYAVG( salary ) ASC LIMIT 1 ) da ON d.department_id = da.department_id-- 4. 查询平均工资最高的 job 信息
-- ①查询最高的job的平均工资
SELECTAVG( salary ),job_id
FROMemployees
GROUP BYjob_id
ORDER BYAVG( salary ) DESC LIMIT 1;-- ②查询job信息
SELECT*
FROMjobs
WHEREjob_id = (SELECTjob_id FROMemployees GROUP BYjob_id ORDER BYAVG( salary ) DESC LIMIT 1 );-- 5. 查询平均工资高于公司平均工资的部门有哪些?-- ①查询公司的平均工资
SELECTAVG( salary )
FROMemployees;-- ②查询每个部门的平均工资
SELECTAVG( salary ),department_id
FROMemployees
GROUP BYdepartment_id;-- ③ 筛选②的结果集,满足平均工资>①
SELECTAVG( salary ),department_id
FROMemployees
GROUP BYdepartment_id
HAVINGAVG( salary ) > ( SELECT AVG( salary ) FROM employees );-- 6. 查询出公司中所有 manager 的详细信息.-- ①查询所有manager的员工编号
SELECT DISTINCTmanager_id
FROMemployees;-- ②查询详细信息,满足employee_id=①
SELECT*
FROMemployees
WHEREemployee_id IN ( SELECT DISTINCT manager_id FROM employees );-- 7. 各个部门中 最高工资中最低的那个部门的 最低工资是多少-- ①查询各部门的最高工资中最低的部门编号
SELECTdepartment_id,MAX( salary )
FROMemployees
GROUP BYdepartment_id
ORDER BYMAX( salary ) ASC LIMIT 1;-- ②查询①结果的那个部门的最低工资
SELECTMIN( salary )
FROMemployees e
WHEREdepartment_id = (SELECTdepartment_id FROMemployees GROUP BYdepartment_id ORDER BYMAX( salary ) ASC LIMIT 1 );-- 8. 查询平均工资最高的部门的 manager 的详细信息: last_name, department_id, email, salary-- ①查询平均工资最高的部门编号
SELECTdepartment_id
FROMemployees
GROUP BYdepartment_id
ORDER BYAVG( salary ) DESC LIMIT 1;-- ②将employees和departments连接查询,筛选条件是①
SELECTlast_name,e.department_id,email,salary
FROMemployees eINNER JOIN departments d ON e.employee_id = d.manager_id
WHEREd.department_id = (SELECTdepartment_id FROMemployees GROUP BYdepartment_id ORDER BYAVG( salary ) DESC LIMIT 1 );
5.10 分页查询
-- 进阶8:分页查询
/*
应用场景:当要显示的数据,一页显示不全,需要分页提交sql请求
语法:select 查询列表from 表[ join type join 表2on 连接条件where 筛选条件group by 分组字段having 分组后的筛选order by 排序的字段 ]limit [offset,] size;offset 要显示条目的起始索引(起始索引从0开始,默认也是从0开始)size 要显示的条目个数
特点:①limit语句放在查询语句的最后②公式要显示的页数 page,每页的条目数sizeselect 查询列表from 表limit (page-1)*size,size;(一定要掌握)
*/
-- 案例1:查询前五条员工信息
SELECT * FROM employees LIMIT 0,5;SELECT * FROM employees LIMIT 5;-- 案例2:查询第11条——第25条(条数 = 25 - 11 + 1)
SELECT * FROM employees LIMIT 10,15;-- 案例3:有奖金的员工信息,并且工资较高的前10名显示出来
SELECT*
FROMemployees
WHEREcommission_pct IS NOT NULL
ORDER BYsalary DESC LIMIT 10;
-- 查询语句中涉及到的所有关键字,以及执行的先后顺序
select 查询列表 ⑦
from 表 ①
连接类型 join 表2 ②
on 连接条件 ③
where 筛选条件 ④
group by 分组列表 ⑤
having 分组后的筛选 ⑥
order by 排序列表 ⑧
limit 偏移,条目数 ⑨
5.11 联合查询
-- 进阶9:联合查询
/*
union 联合 合并:将多条查询语句的结果合并成一个结果语法:
查询语句1
union
查询语句2
union
查询语句3
union
...应用场景:
要查询的结果来自于多个表,且多个表没有直接的连接关系,但查询的信息一致时特点:★
1、要求多条查询语句的查询列数是一致的!
2、要求多条查询语句查询的每一列的类型和顺序最好一致
3、union关键字默认去重,如果使用union all可以包含重复项
*/-- 引入的案例:查询部门编号>90或邮箱包含a的员工信息
SELECT * FROM employees WHERE department_id > 90 OR email LIKE '%a%';SELECT * FROM employees WHERE department_id > 90
UNION
SELECT * FROM employees WHERE email LIKE '%a%';
6. DML语言的学习
6.1 数据的增删改
-- DML语言
/*
数据操作语言:插入:insert修改:update删除:delete
*/-- 1.插入语句
-- 方式一:
/*
语法:
insert into 表名(列名,...) values(值1,...);
*/
USE girls;
SELECT * FROM beauty;-- 1.1 插入的值的类型要与列的类型一致或兼容
INSERT INTO beauty (id,`name`,sex,borndate,phone,photo,boyfriend_id
)
VALUES(13,'唐艺昕','女','1990-04-23','1898888888',NULL,2 );-- 1.2 不可以为null的列必须插入值。可以为null的列如何插入值?-- 方法一:字段的值用null表示,适合于该字段可以为空的
INSERT INTO beauty (id,`name`,sex,borndate,phone,photo,boyfriend_id
)
VALUES(13,'唐艺昕','女','1990-4-23','1898888888',NULL,2 );-- 方法二:该字段省略
INSERT INTO beauty ( id, `name`, sex, phone )
VALUES( 15, '娜扎', '女', '1388888888' );-- 1.3 列的顺序是否可以调换
INSERT INTO beauty ( `name`, sex, id, phone )
VALUES( '蒋欣', '女', 16, '110' );-- 1.4 列数和值的个数必须一致
INSERT INTO beauty ( NAME, sex, id, phone )
VALUES( '关晓彤', '女', 17, '110' );-- 1.5 可以省略列名,默认所有列,而且列的顺序和表中列的顺序一致,所以填充的值顺序也必须一致
INSERT INTO beauty
VALUES(18,'张飞','男',NULL,'119',NULL,NULL );-- 方式二:
/*
语法:
insert into 表名
set 列名=值,列名=值,...
*/
INSERT INTO beauty
SET id = 19,
`name` = '刘涛',
phone = '999';/*
两种方式对比
*/
-- 1.6 方式一支持插入多行,方式二不支持
INSERT INTO beauty
VALUES(23,'唐艺昕1','女','1990-4-23','1898888888',NULL,2 ),(24,'唐艺昕2','女','1990-4-23','1898888888',NULL,2 ),(25,'唐艺昕3','女','1990-4-23','1898888888',NULL,2 );-- 1.7 方式一支持子查询,方式二不支持
INSERT INTO beauty ( id, `name`, phone ) SELECT
26,
'宋茜',
'11809866';INSERT INTO beauty ( id, `name`, phone ) SELECT
id,
boyname,
'1234567'
FROMboys
WHEREid < 3;-- 2.修改语句
/*
1.修改单表的记录[重点]
语法:
update 表名
set 列=新值,列=新值,...
where 筛选条件;2.修改多表的记录[补充]语法:
sql92语法:
update 表1 别名,表2 别名
set 列=值,列=值,...
where 连接条件
and 筛选条件;sql99语法:
update 表1 别名
inner|left|right join 表2 别名
on 连接条件
set 列=值,...
where 筛选条件;
*/-- 2.1 修改单表的记录-- 案例1:修改beauty表中姓唐的女神的电话为13899888899
UPDATE beauty
SET `phone` = '13899888899'
WHERE`name` LIKE '唐%';-- 案例2:修改boys表中id为2的名称为张飞,魅力值 10
UPDATE boys
SET `boyname` = '张飞',
`usercp` = 10
WHEREid = 2;-- 2.2 修改多表的记录-- 案例1:修改张无忌的女朋友的手机号为114,并且张无忌的魅力值为1000
UPDATE boys bo
INNER JOIN beauty b ON bo.`id` = b.`boyfriend_id`
SET b.`phone` = '114',
bo.`userCP` = 1000
WHEREbo.`boyName` = '张无忌';-- 案例2:修改没有男朋友的女神的男朋友编号都为2号
UPDATE boys bo
RIGHT JOIN beauty b ON bo.`id` = b.`boyfriend_id`
SET b.`boyfriend_id` = 2
WHEREbo.id IS NULL;-- 3.删除语句
/*
方式一:delete
语法:
1、单表的删除[重点]
delete from 表名 [where 筛选条件] [limit 条目数]2、多表的删除[补充]sql92语法:
delete 表1的别名,表2的别名
from 表1 别名,表2 别名
where 连接条件
and 筛选条件;sql99语法:
delete 表1的别名,表2的别名
from 表1 别名
inner|left|right join 表2 别名 on 连接条件
where 筛选条件;方式二:truncate
语法:
truncate table 表名;
*/-- 方式一:delete
-- 3.1 单表的删除
-- 案例1:删除手机号以9结尾的女神信息
DELETE
FROMbeauty
WHEREphone LIKE '%9';-- 3.2 多表的删除
-- 案例1:删除张无忌的女朋友的信息
DELETE b
FROMbeauty bINNER JOIN boys bo ON b.boyfriend_id = bo.id
WHEREbo.`boyName` = '张无忌';-- 案例2:删除黄晓明的信息以及他女朋友的信息
DELETE b,
bo
FROMboys boINNER JOIN beauty b ON b.boyfriend_id = bo.id
WHEREbo.boyName = '黄晓明';-- 方式二:truncate语句:相当于清空表中的全部数据
-- 案例:将魅力值>100的男神信息删除(报错,不能加where语句)
TRUNCATE TABLE boys;-- delete 与 truncate的区别?(重点面试题)
/*
1.delete 可以加where条件,truncate不能加
2.truncate删除,效率高一丢丢
3.假如要删除的表中有自增长列,如果用delete删除后,再插入数据,自增长列的值从断点开始,而truncate删除后,再插入数据,自增长列的值从1开始。
4.truncate删除没有返回值,delete删除有返回受影响的行数
5.truncate删除不能回滚,delete删除可以回滚
*/DELETE FROM boys;
TRUNCATE TABLE boys;
INSERT INTO boys (boyname,usercp)
VALUES('张飞',100),('刘备',100),('关云长',100);
6.1.1 增删改练习
-- 对照test_lesson10 数据处理的练习-- 1.
CREATE TABLE my_employees (Id INT ( 10 ),First_name VARCHAR ( 10 ),Last_name VARCHAR ( 10 ),Userid VARCHAR ( 10 ),Salary DOUBLE ( 10, 2 )
);CREATE TABLE users (id INT,userid VARCHAR ( 10 ),
department_id INT
)-- 2.
DESC my_employees;-- 3.
-- 方式一:
INSERT INTO my_employees
VALUES (1,'patel','Ralph','Rpatel',895),
(2,'Dancs','Betty','Bdancs',860),
(3,'Biri','Ben','Bbiri',1100),
(4,'Newman','Chad','Cnewman',750),
(5,'Ropeburn','Audrey','Aropebur',1550);-- 方式二:
INSERT INTO my_employees
SELECT 1,'patel','Ralph','Rpatel',895 UNION
SELECT 2,'Dancs','Betty','Bdancs',860 UNION
SELECT 3,'Biri','Ben','Bbiri',1100 UNION
SELECT 4,'Newman','Chad','Cnewman',750 UNION
SELECT 5,'Ropeburn','Audrey','Aropebur',1550;-- 4.
INSERT INTO users
VALUES( 1, 'Rpatel', 10 ),( 2, 'Bdancs', 10 ),( 3, 'Bbiri', 20 ),( 4, 'Cnewman', 30 ),( 5, 'Aropebur', 40 );-- 5.
UPDATE my_employees
SET Last_name = 'drelxer';-- 6.
UPDATE my_employees
SET Salary = 1000
WHERESalary < 900;-- 7.
DELETE u,
m
FROMusers uINNER JOIN my_employees m ON u.userid = m.Userid
WHEREu.userid = 'Bbiri';-- 8.
DELETE FROM my_employees;
DELETE FROM users;-- 9.
SELECT * FROM my_employees;
SELECT * FROM users;-- 10.
TRUNCATE TABLE my_employees;
TRUNCATE TABLE users;
7. DDL语言的学习
7.1 库和表的管理
-- DDL语言(Data Definition Language)
/*
数据定义语言库和表的管理一、库的管理
创建、修改、删除
二、表的管理
创建、修改、删除创建: create
修改: alter
删除: drop
*/-- 1.库的管理-- 1.1 库的创建
/*
语法:
create database [if not exists] 库名 [character set 字符集名];
*/-- 案例:创建库Books
CREATE DATABASE
IFNOT EXISTS books;-- 1.2 库的修改(该语法被废弃了)
RENAME DATABASE books TO 新库名;-- 更改库的字符集
ALTER DATABASE books CHARACTER
SET gbk;-- 1.3 库的删除
/*
语法:drop database [if exists] 库名;
*/
DROP DATABASE
IFEXISTS books;-- 2.表的管理-- 2.1 表的创建
/*
语法:
create table 表名(列名 列的类型 [(长度) 约束],列名 列的类型 [(长度) 约束],列名 列的类型 [(长度) 约束],...列名 列的类型 [(长度) 约束]
)
*/
-- 案例:创建表Book
CREATE TABLE book(`id` INT,#编号`bName` VARCHAR(20),#图书名`price` DOUBLE,#价格`authorId` INT,#作者编号`publishDate` DATETIME#出版日期
);
DESC book;-- 案例:创建表author
CREATE TABLE IF NOT EXISTS author(id INT, #作者编号au_name VARCHAR(20), #作者姓名nation VARCHAR(10) #国籍
);
DESC author;-- 2.2 表的修改
/*
语法
alter table 表名 add|drop|modify|change column 列名 [列类型 约束];
add:添加
注意:column可以省略
drop:删除
modify:修改列的数据类型
change:修改列名
*/-- ①修改列名
ALTER TABLE book CHANGE COLUMN publishdate pubDate DATETIME;-- ②修改列的类型或约束
/*
alter table 表名 modify column 列名 新类型 [新约束];
*/
ALTER TABLE book MODIFY COLUMN pubdate TIMESTAMP;-- ③添加新列
/*
语法:alter table 表名 add column 列名 列类型 [first|after 字段名];
最后面的first表示把添加的列添加到表的第一列,或者哪一个列的后面,不加默认是添加到最后面
*/
ALTER TABLE author ADD COLUMN annual DOUBLE; -- ④删除列
/*
alter table 表名 drop column 列名
*/
ALTER TABLE author DROP COLUMN annual;-- ⑤修改表名
ALTER TABLE author RENAME TO book_author;DESC book;-- 2.3 表的删除
/*
drop table [if exists] 表名;
*/
DROP TABLE IF EXISTS book_author;SHOW TABLES; #查看当前库的所有表-- 通用的写法:
/*
DROP DATABASE IF EXISTS 旧库名;
CREATE DATABASE 新库名;DROP TABLE IF EXISTS 旧表名;
CREATE TABLE 表名();
*/-- 2.4 表的复制
INSERT INTO author VALUES
(1,'村上春树','日本'),
(2,'莫言','中国'),
(3,'冯唐','中国'),
(4,'金庸','中国');SELECT * FROM Author;
SELECT * FROM copy;-- ①仅仅复制表的结构
/*
create table 表名 like 旧表;
*/
CREATE TABLE copy LIKE author;-- ②复制表的结构+数据
/*
create table 表名 select 查询列表 from 旧表 [where 筛选];
*/
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; #也可以写成1=2
7.1.1 库和表的管理练习
-- 基于test_lesson11的练习
-- 1.
#把该表建在test库里
USE test;
CREATE TABLE dept1(id INT(7),name VARCHAR(25)
);-- 2.
CREATE TABLE dept2
SELECT department_id,department_name
FROM myemployees.departments;-- 3.
CREATE TABLE emp5(id INT(7),First_name VARCHAR(25),Last_name VARCHAR(25),dept_id INT(7)
);-- 4.
ALTER TABLE emp5 MODIFY COLUMN last_name VARCHAR(50);-- 5.
CREATE TABLE employees2 LIKE myemployees.employees;-- 6.
DROP TABLE IF EXISTS emp5;-- 7.
ALTER TABLE employees2 RENAME TO emp5;-- 8.
ALTER TABLE emp5 ADD COLUMN test_column INT;
ALTER TABLE dept ADD COLUMN test_column INT;--9.
ALTER TABLE emp5 DROP COLUMN dept_id;
7.2 常见数据类型
-- 常见的数据类型
/*
数值型:整型小数:定点数浮点数
字符型:较短的文本:char、varchar较长的文本:text、blob(较长的二进制数据)日期型:
*/-- 1.整型
/*
分类:
tinyint 、 smallint 、 mediumint 、 int/integer 、 bigint1 2 3 4 8 字节特点:
① 如果不设置无符号还是有符号,默认是有符号,如果想设置无符号,需要添加unsigned关键字
② 如果插入的数值超出了整型的范围,会报out of range异常,并且插入临界值
③ 如果不设置长度,会有默认的长度长度代表了显示的最大宽度,如果不够会用0在左边填充,但需要搭配zerofill使用,并且默认变为无符号整型!
*/-- 1.1 如何设置无符号和有符号
DROP TABLE IF EXISTS tab_int;
CREATE TABLE tab_int(t1 INT(7) ZEROFILL UNSIGNED,t2 INT(7) ZEROFILL
);INSERT INTO tab_int VALUES(-123456);
INSERT INTO tab_int VALUES(-123456,-123456);
INSERT INTO tab_int VALUES(2147483648,2147483648);INSERT INTO tab_int VALUES(123,123);-- 2.小数
/*
分类:
1.浮点型
float(M,D) 4个字节
double(M,D) 8个字节
2.定点型
dec(M,D)
decimal(M,D)特点:
①
M:整数部位+小数部位的总个数
D:小数部位,相当于保留几位小数
如果超过范围,则显示临界值②
M和D都可以省略
如果是decimal,则M默认为10,D默认为0
如果是float和double,则会根据插入的数值的精度来决定精度③定点型的精确度较高,如果要求插入数值的精度较高,如:货币运算等可以考虑使用原则:所选择的类型越简单越好,能保存数值的类型越小越好
*/-- 测试M和DDROP TABLE tab_float;
CREATE TABLE tab_float(f1 FLOAT,f2 DOUBLE,f3 DECIMAL
);
SELECT * FROM tab_float;
DESC tab_float;INSERT INTO tab_float VALUES(123.4523,123.4523,123.4523);
INSERT INTO tab_float VALUES(123.456,123.456,123.456);
INSERT INTO tab_float VALUES(123.4,123.4,123.4);
INSERT INTO tab_float VALUES(1523.4,1523.4,1523.4);-- 3.字符型
/*
较短的文本:char
varchar其他:binary和varbinary用于保存较短的二进制
enum用于保存枚举
set用于保存集合较长的文本:
text
blob(较大的二进制)特点:写法 M的意思 特点 空间的耗费 效率
char char(M) 最大长度不超过M,可以省略,默认为1 固定长度的字符 比较耗费 高varchar varchar(M) 最大长度不超过M,不可以省略 可变长度的字符 比较节省 低
*/-- 3.1 枚举
CREATE TABLE tab_char(c1 ENUM('a','b','c')
);INSERT INTO tab_char VALUES('a');
INSERT INTO tab_char VALUES('c');
INSERT INTO tab_char VALUES('b');
INSERT INTO tab_char VALUES('M'); #报错
INSERT INTO tab_char VALUES('A'); #报错SELECT * FROM tab_char;-- 3.2 set集合
CREATE TABLE tab_set(s1 SET('a','b','c','d')
);INSERT INTO tab_set VALUES('a');
INSERT INTO tab_set VALUES('A,B'); #报错
INSERT INTO tab_set VALUES('a,c,d');SELECT * FROM tab_set;-- 4.日期型
/*分类:
date只保存日期
time 只保存时间
year只保存年datetime保存日期+时间
timestamp保存日期+时间特点:字节 范围 时区等的影响
datetime 8 1000——9999 不受
timestamp 4 1970-2038 受*/
CREATE TABLE tab_date(t1 DATETIME,t2 TIMESTAMP
);INSERT INTO tab_date VALUES(NOW(),NOW());SELECT * FROM tab_date;SHOW VARIABLES LIKE 'time_zone';SET time_zone='+9:00';
7.3 常见约束
-- 常见约束/*
含义:一种限制,用于限制表中的数据,为了保证表中的数据的准确和可靠性分类:六大约束1.NOT NULL:非空,用于保证该字段的值不能为空比如姓名、学号等2.DEFAULT:默认,用于保证该字段有默认值比如性别3.PRIMARY KEY:主键,用于保证该字段的值具有唯一性(不可重复),并且非空比如学号、员工编号等4.UNIQUE:唯一,用于保证该字段的值具有唯一性(不可重复),可以为空比如座位号5.CHECK:检查约束 [mysql中不支持]比如年龄、性别6.FOREIGN KEY:外键,用于限制两个表的关系,用于保证该字段的值必须来自于主表的关联列的值在从表添加外键约束,用于引用主表中某列的值比如学生表的专业编号,员工表的部门编号,员工表的工种编号添加约束的时机:1.创建表时2.修改表时约束的添加分类:列级约束:六大约束语法上都支持,但外键约束没有效果表级约束:除了非空、默认外,其他的都支持主键(PRIMARY KEY)和唯一(UNIQUE)的大对比:保证唯一性 是否允许为空 一个表中可以有多少个 是否允许组合
主键 √ × 至多有1个 √,但不推荐
唯一 √ √ 可以有多个 √,但不推荐外键:1、要求在从表设置外键关系2、从表的外键列的类型和主表的关联列的类型要求一致或兼容,名称无要求3、主表中的关联列必须是一个key(一般是主键或唯一键)4、插入数据时,先插入主表,再插入从表删除数据时,先删除从表,再删除主表
*/CREATE TABLE 表名(字段名 字段类型 列级约束,字段名 字段类型,表级约束
)CREATE DATABASE students;
use students;
-- 1.创建表时添加约束-- 1.1 添加列级约束
/*
语法:直接在字段名和字段类型后面 追加约束类型即可只支持:默认、非空、主键、唯一
*/
CREATE TABLE stuinfo(id INT PRIMARY KEY, #主键约束stuName VARCHAR(20) NOT NULL, #非空约束gender CHAR(1) CHECK(gender = '男' OR gender = '女'), #检查约束seat INT UNIQUE, #唯一约束,可以为空age INT DEFAULT 18, #默认约束majorId INT REFERENCES major(id) #外键,引用major表的id字段
);CREATE TABLE major(id INT PRIMARY KEY,majorName VARCHAR(20)
);
-- 查看表结构
DESC stuinfo;
-- 查看表中所有的索引,包括主键、外键、唯一
SHOW INDEX FROM stuinfo;-- 1.2 添加表级约束
/*
语法:在各个字段的最下面[constraint 约束名] 约束类型(字段名)
*/
-- 方式一:
DROP TABLE IF EXISTS stuinfo;
CREATE TABLE stuinfo(id INT,stuName VARCHAR(20),gender CHAR(1),seat INT,majorid INT,CONSTRAINT pk PRIMARY KEY(id), #主键CONSTRAINT uq UNIQUE(seat), #唯一键CONSTRAINT ck CHECK(gender = '男' OR gender = '女'), #检查约束CONSTRAINT fk_stuinfo_major FOREIGN KEY(majorid) REFERENCES major(id) #外键
);-- 方式二:省略 CONSTRAINT 约束名
DROP TABLE IF EXISTS stuinfo;
CREATE TABLE stuinfo(id INT,stuName VARCHAR(20),gender CHAR(1),seat INT,majorid INT,PRIMARY KEY(id), #主键UNIQUE(seat), #唯一键CHECK(gender = '男' OR gender = '女'), #检查约束FOREIGN KEY(majorid) REFERENCES major(id) #外键
);SHOW INDEX FROM stuinfo;-- 通用的写法
CREATE TABLE IF NOT EXISTS stuinfo(id INT PRIMARY KEY, #主键stuname VARCHAR(20) NOT NULL, sex CHAR(1),age INT DEFAULT 18, #默认18seat INT UNIQUE, #唯一键majorid INT,CONSTRAINT fk_stuinfo_major FOREIGN KEY(majorid) REFERENCES major(id) #外键
);-- 2.修改表时添加约束
/*
1、添加列级约束
alter table 表名 modify column 字段名 字段类型 新约束;2、添加表级约束
alter table 表名 add [constraint 约束名] 约束类型(字段名) [外键的引用];
*/
DROP TABLE IF EXISTS stuinfo;
CREATE TABLE stuinfo(id INT,stuname VARCHAR(20),gender CHAR(1),seat INT,age INT,majorid INT
);
DESC stuinfo;-- 2.1 添加非空约束
ALTER TABLE stuinfo MODIFY COLUMN stuname VARCHAR(20) NOT NULL;-- 2.2 添加默认约束
ALTER TABLE stuinfo MODIFY COLUMN age INT DEFAULT 18;-- 2.3 添加主键
-- ①列级约束
ALTER TABLE stuinfo MODIFY COLUMN id INT PRIMARY KEY;
-- ②表级约束
ALTER TABLE stuinfo ADD PRIMARY KEY(id);-- 2.4 添加唯一键
-- ①列级约束
ALTER TABLE stuinfo MODIFY COLUMN seat INT UNIQUE;
-- ②表级约束
ALTER TABLE stuinfo ADD UNIQUE(seat);-- 2.5 添加外键(CONSTRAINT 键名,也可以省略)
ALTER TABLE stuinfo ADD CONSTRAINT fk_stuinfo_major FOREIGN KEY ( majorid ) REFERENCES major ( id );-- 2.5.1 添加外键时,添加级联删除(ON DELETE CASCADE)
/*
添加级联删除后,删除主表的记录,与之关联的从表的记录也会被一起删除
*/
ALTER TABLE stuinfo ADD CONSTRAINT fk_stuinfo_major FOREIGN KEY ( majorid ) REFERENCES major ( id ) ON DELETE CASCADE;-- 2.5.2 添加外键时,添加级联置空(ON DELETE SET NULL)
/*
添加级联置空后,删除主表的记录,与之关联的从表的字段会被置空
*/
ALTER TABLE stuinfo ADD CONSTRAINT fk_stuinfo_major FOREIGN KEY ( majorid ) REFERENCES major ( id ) ON DELETE SET NULL;-- 3.修改表时删除约束-- 3.1 删除非空约束
ALTER TABLE stuinfo MODIFY COLUMN stuname VARCHAR(20) [NULL];-- 3.2 删除默认约束
ALTER TABLE stuinfo MODIFY COLUMN age INT ;-- 3.3 删除主键
ALTER TABLE stuinfo DROP PRIMARY KEY;-- 3.4 删除唯一
/*
alter table 表名 drop index 索引名;
*/
ALTER TABLE stuinfo DROP INDEX seat;-- 3.5 删除外键
/*
alter table 表名 drop foreign key 约束名
*/
ALTER TABLE stuinfo DROP FOREIGN KEY fk_stuinfo_major;SHOW INDEX FROM stuinfo;
7.3.1 常见约束练习
-- 1. 向表 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);-- 2. 向表 dept2 的 id 列中添加 PRIMARY KEY 约束(my_dept_id_pk)
ALTER TABLE dept2 MODIFY COLUMN id INT PRIMARY KEY;
ALTER TABLE dept2 ADD CONSTRAINT my_dept_id_pk PRIMARY KEY(id);-- 3. 向表 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);/*位置 支持的约束类型 是否可以起约束名
列级约束: 列的后面 语法都支持,但外键没效果 不可以
表级约束: 所有列的下面 默认和非空不支持,其他支持 可以(但是对主键没效果,主键键名默认就是PRIMARY KEY)
*/
7.4 标识列
-- 标识列
/*
又称为自增长列
含义:可以不用手动的插入值,系统提供默认的序列值特点:
1、标识列必须和主键搭配吗?不一定,但要求是一个key
2、一个表可以有几个标识列?至多一个!
3、标识列的类型只能是数值型
4、标识列可以通过 SET auto_increment_increment=3;设置步长
5、可以通过首次手动插入值,设置起始值
*/
-- 1.创建表时设置标识列DROP TABLE IF EXISTS tab_identity;
CREATE TABLE tab_identity(id INT PRIMARY KEY,NAME FLOAT UNIQUE AUTO_INCREMENT, seat INT
);TRUNCATE TABLE tab_identity;INSERT INTO tab_identity(id,NAME) VALUES(NULL,'john');
INSERT INTO tab_identity(NAME) VALUES('lucy');
SELECT * FROM tab_identity;SHOW VARIABLES LIKE '%auto_increment%';-- 设置每次自动增长的步长
SET auto_increment_increment=3;-- 2.修改表时设置标识列
/*
alter table 表名 modify column 字段名 字段类型 约束 auto_increment;
*/
ALTER TABLE tab_identity MODIFY COLUMN id INT PRIMARY KEY AUTO_INCREMENT;-- 3.修改表时删除标识列
-- 删除表字段id的主键,因为一张表只能有一个主键,所以主键可以默认不写
ALTER TABLE tab_identity MODIFY COLUMN id int;
8. TCL语言的学习
8.1 事务
-- 事务
/*
Transaction Control Language 事务控制语言事务:
一个或一组sql语句组成一个执行单元,这个执行单元要么全部执行,要么全部不执行。案例:转账张三丰 1000
郭襄 1000update 表 set 张三丰的余额=500 where name='张三丰'
意外
update 表 set 郭襄的余额=1500 where name='郭襄'事务的特性:
ACID
原子性(Atomicity):一个事务是不可再分割的,要么都执行要么都不执行
一致性(Consistency):一个事务执行会使数据从一个一致状态切换到另外一个一致状态
隔离性(Isolation):一个事务的执行不受其他事务的干扰,多个事务互相隔离
持久性(Durability):一个事务一旦提交,则会永久的持久化到本地事务的创建
1.隐式事务:事务没有明显的开启和结束的标记
比如insert、update、delete语句delete from 表 where id =1;2.显式事务:事务具有明显的开启和结束的标记
前提:必须先设置自动提交功能为禁用-- 关闭当前事务的自动提交
set autocommit=0;具体步骤:
步骤1:开启事务
set autocommit=0;
start transaction; 可以省略的
步骤2:编写事务中的sql语句(select insert update delete)
语句1;
语句2;
...步骤3:结束事务
commit; 提交事务
rollback; 回滚事务savepoint 节点名; 设置保存点
一般搭配rollback to 节点名;事务的隔离级别:脏读 不可重复读 幻读
read uncommitted(读未提交): √ √ √
read committed(读已提交): × √ √
repeatable read(可重复读): × × √
serializable(可串行化): × × ×脏读:一个事务读取了其他事务还没有提交的数据,读到的是其他事物"更新"的数据
不可重复读:一个事务多次读取数据,结果都不一样
幻读:一个事务读取了其他事务还没有提交的数据,读到的是其他事物"插入"的数据mysql中默认 第三个隔离级别 repeatable read
oracle中默认第二个隔离级别 read committed
查看隔离级别(mysql8.0+)
select @@transaction_isolation;
查看隔离级别(mysql 5.7)
select @@tx_isolation;
设置隔离级别
set session transaction isolation level 隔离级别;开启事务的语句;
update 表 set 张三丰的余额=500 where name='张三丰'update 表 set 郭襄的余额=1500 where name='郭襄'
结束事务的语句;
*/-- 查看mysql的存储引擎
SHOW ENGINES;-- 查看自动提交的状态
SHOW VARIABLES LIKE 'autocommit';/*
创建表和插入数据
USE test;DROP TABLE IF EXISTS account;CREATE TABLE account(id INT PRIMARY KEY AUTO_INCREMENT,username VARCHAR(20),balance DOUBLE
);INSERT INTO account(username,balance)
VALUES ('张无忌',1000),('赵敏',1000);
*/
-- 1.演示事务的使用步骤-- 1.1 开启事务
SET autocommit = 0;
START TRANSACTION;
-- 1.2 编写一组事务的语句
UPDATE account SET balance = 1000 WHERE username = '张无忌';
UPDATE account SET balance = 1000 WHERE username = '赵敏';
-- 1.3 结束事务
ROLLBACK; #回滚事务
COMMIT; #提交事务SELECT * FROM account;-- 2.演示事务对于delete和truncate的处理区别-- 2.1 演示delete
SET autocommit=0;
START TRANSACTION;
DELETE FROM account;
ROLLBACK; #delete支持回滚,回滚后数据还存在-- 2.2 演示truncate
SET autocommit=0;
START TRANSACTION;
TRUNCATE TABLE account;
ROLLBACK; #truncate不支持回滚,回滚后数据也是删除了-- 3.演示savepoint的使用
SET autocommit=0;
START TRANSACTION;
DELETE FROM account WHERE id = 1;
SAVEPOINT a; #设置保存点
DELETE FROM account WHERE id = 2;ROLLBACK TO a; #回滚到保存点处,也就是说id=1的信息会被删除,而id=2的信息会被保存下来SELECT * FROM account;
9.视图
-- 视图
/*
含义:虚拟表,和普通表一样使用
mysql5.1版本出现的新特性,本身是一个虚拟表,它的数据来自于表,通过执行时动态生成
好处:
1、简化sql语句
2、提高了sql的重用性
3、保护基表的数据,提高了安全性比如:类似于java中的方法创建语法的关键字 是否实际占用物理空间 使用视图 create view 只是保存了sql逻辑 一般用于查询表 create table 保存了数据 增删改查
*/-- 案例:查询姓张的学生名和专业名
SELECT stuname,majorname FROM stuinfo s
INNER JOIN major m ON s.majorid = m.id
WHERE s.stuname LIKE '张%';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 '张%';-- 1.创建视图
/*
语法:create view 视图名as查询语句;
*/-- 案例1:查询姓名中包含a字符的员工名、部门名和工种信息
-- ①创建视图
CREATE VIEW myv1
AS
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 j.job_id = e.job_id;-- ②使用视图
SELECT * FROM myv1 WHERE Last_name LIKE '%a%';-- 案例2:查询各部门的平均工资级别
-- ①创建视图,查看每个部门的平均工资
CREATE VIEW myv2
AS
SELECT AVG(salary) ag,department_id
FROM employees
GROUP BY department_id;-- ②使用视图
SELECT myv2.ag,j.grade_level
FROM myv2
INNER JOIN job_grades j
ON myv2.ag BETWEEN j.lowest_sal AND j.highest_sal;-- 案例3:查询平均工资最低的部门信息
SELECT * FROM myv2 ORDER BY ag ASC LIMIT 1;-- 案例4:查询平均工资最低的部门名和工资
CREATE VIEW myv3
AS
SELECT * FROM myv2 ORDER BY ag ASC LIMIT 1;SELECT d.* FROM myv3 m
INNER JOIN departments d
ON m.department_id = d.department_id;-- 2.视图的修改-- 2.1 方式一:
/*
create or replace view 视图名
as
查询语句;
*/
SELECT * FROM myv3;CREATE OR REPLACE VIEW myv3
AS
SELECT AVG(salary),job_id
FROM employees
GROUP BY job_id;-- 2.2 方式二:
/*
语法:
alter view 视图名
as
查询语句;
*/
ALTER VIEW myv3
AS
SELECT * FROM employees;-- 3.删除视图
/*
语法:drop view 视图名,视图名,...;
*/
DROP VIEW emp_v1,emp_v2,myv3;-- 4.查看视图
DESC myv3;SHOW CREATE VIEW myv3;-- 5.视图的更新
CREATE OR REPLACE VIEW myv1
AS
SELECT last_name,email,salary*12*(1+IFNULL(commission_pct,0)) "annual salary"
FROM employees;CREATE OR REPLACE VIEW myv1
AS
SELECT last_name,email
FROM employees;SELECT * FROM myv1
SELECT * FROM employees;-- 5.1 插入数据
INSERT INTO myv1 VALUES('张飞','zf@qq.com');-- 5.2 修改数据
UPDATE myv1 SET last_name = '张无忌' WHERE last_name='张飞';-- 5.3 删除数据
DELETE FROM myv1 WHERE last_name = '张无忌';-- 5.4 具备以下特点的视图不允许更新-- 5.4.1 包含以下关键字的sql语句:分组函数、distinct、group by、having、union或者union all-- 案例:group by
CREATE OR REPLACE VIEW myv1
AS
SELECT MAX(salary) m,department_id
FROM employees
GROUP BY department_id;SELECT * FROM myv1;-- 更新
UPDATE myv1 SET m=9000 WHERE department_id=10; #报错,视图包含了group by-- 5.4.2 常量视图
CREATE OR REPLACE VIEW myv2
AS
SELECT 'john' NAME;SELECT * FROM myv2;-- 下面的sql语句也可以算是常量视图
SELECT (SELECT MAX(salary) FROM employees) 最高工资;-- 更新
UPDATE myv2 SET NAME='lucy'; #报错,视图里面包含常量-- 5.4.3 select中包含子查询
CREATE OR REPLACE VIEW myv3
AS
SELECT department_id,(SELECT MAX(salary) FROM employees) 最高工资
FROM departments;SELECT * FROM myv3;-- 更新
UPDATE myv3 SET 最高工资=100000; #报错,视图包含子查询-- 5.4.4 join关键字
CREATE OR REPLACE VIEW myv4
AS
SELECT last_name,department_name
FROM employees e
JOIN departments d
ON e.department_id = d.department_id;SELECT * FROM myv4;-- 更新
UPDATE myv4 SET last_name = '张飞' WHERE last_name='Whalen'; #可以更新
INSERT INTO myv4 VALUES('陈真','xxxx'); #报错,语句包含join-- 5.4.5 from后面加一个不能更新的视图
CREATE OR REPLACE VIEW myv5
AS
SELECT * FROM myv3;SELECT * FROM myv5;-- 更新
UPDATE myv5 SET 最高工资=10000 WHERE department_id=60; #报错-- 5.4.6 where子句的子查询引用了from子句中的表
CREATE OR REPLACE VIEW myv6
AS
SELECT last_name,email,salary
FROM employees
WHERE employee_id IN(SELECT manager_idFROM employeesWHERE manager_id IS NOT NULL
);SELECT * FROM myv6;-- 更新
UPDATE myv6 SET salary=10000 WHERE last_name = 'k_ing'; #报错
10.变量
-- 变量
/*
系统变量:全局变量会话变量自定义变量:用户变量局部变量
*/-- 1.系统变量
/*
说明:变量由系统定义,不是用户定义,属于服务器层面,必须拥有super权限才能为系统变量赋值,作用域为整个服务器
注意:全局变量需要添加global关键字,会话变量需要添加session关键字,如果不写,默认会话级别
使用步骤:
1、查看所有系统变量
show global|[session] variables;
2、查看满足条件的部分系统变量
show global|[session] variables like '%char%';
3、查看指定的系统变量的值
select @@global|[session] 系统变量名;
4、为某个系统变量赋值
方式一:
set global|[session] 系统变量名=值;
方式二:
set @@global|[session] 系统变量名=值;
*/-- 1.1 全局变量
/*
服务器每次启动都将为所有的全局变量初始化值
作用域:针对于所有会话(连接)有效,但不能跨重启
*/
-- ①查看所有全局变量
SHOW GLOBAL VARIABLES;
-- ②查看满足条件的部分系统变量
SHOW GLOBAL VARIABLES LIKE '%char%';
-- ③查看指定的系统变量的值
SELECT @@global.autocommit;
select @@transaction_isolation; #查看隔离级别
-- ④为某个系统变量赋值
SET @@global.autocommit=0;
SET GLOBAL autocommit=0;-- 1.2 会话变量
/*
服务器为每一个连接的客户端都提供了系统变量
作用域:针对于当前会话(连接)有效
*/
-- ①查看所有会话变量
SHOW SESSION VARIABLES;
-- ②查看满足条件的部分会话变量
SHOW SESSION VARIABLES LIKE '%char%';
-- ③查看指定的会话变量的值
SELECT @@autocommit;
SELECT @@session.transaction_isolation;
SELECT @@transaction_isolation;
-- ④为某个会话变量赋值
SET @@session.transaction_isolation='read-uncommitted';
SET SESSION transaction_isolation='read-committed';-- 2.自定义变量
/*
说明:变量由用户自定义,而不是系统提供的
使用步骤:1、声明2、赋值3、使用(查看、比较、运算等)
*/-- 2.1 用户变量
/*
作用域:针对于当前会话(连接)有效,作用域和会话变量一样
*/
-- 赋值操作符:=或:=
-- ①声明并初始化
SET @变量名=值;
SET @变量名:=值;
SELECT @变量名:=值;-- ②赋值(更新变量的值)
-- 方式一:SET @变量名=值;SET @变量名:=值;SELECT @变量名:=值;
-- 方式二:SELECT 字段 INTO @变量名FROM 表;
-- ③使用(查看变量的值)
SELECT @用户变量名;-- 案例:
/*
set @count = 1;
*/
SELECT COUNT(*) INTO @count
FROM employees;SELECT @count; #107-- 2.2 局部变量
/*
作用域:仅仅在定义它的begin end块中有效
应用在 begin end中的第一句话
*/
-- 步骤:
-- ①声明
DECLARE 变量名 类型;
DECLARE 变量名 类型 [DEFAULT 值];
-- ②赋值(更新变量的值)
-- 方式一:SET 局部变量名=值;SET 局部变量名:=值;SELECT @局部变量名:=值;
-- 方式二:SELECT 字段 INTO 局部变量名FROM 表;
-- ③使用(查看变量的值)
SELECT 局部变量名;-- 案例:声明两个变量,求和并打印-- 用户变量
SET @m=1;
SET @n=1;
SET @sum=@m+@n;
SELECT @sum;-- 局部变量,报错
DECLARE m INT DEFAULT 1;
DECLARE n INT DEFAULT 1;
DECLARE SUM INT;
SET SUM=m+n;
SELECT SUM;/*
用户变量和局部变量的对比作用域 定义位置 语法
用户变量 当前会话 会话的任何地方 加@符号,不用指定类型
局部变量 定义它的BEGIN END中 BEGIN END的第一句话 一般不用加@,需要指定类型
*/
11.存储过程
-- 存储过程和函数
/*
存储过程和函数:类似于java中的方法
好处:
1、提高代码的重用性
2、简化操作
*/-- 存储过程
/*
含义:一组预先编译好的SQL语句的集合,理解成批处理语句
1、提高代码的重用性
2、简化操作
3、减少了编译次数并且减少了和数据库服务器的连接次数,提高了效率
*/-- 1.创建语法
/*
CREATE PROCEDURE 存储过程名(参数列表)
BEGIN存储过程体(一组合法的SQL语句)
END
*/
-- 注意:
/*
1、参数列表包含三部分
参数模式 参数名 参数类型
举例:
in stuname varchar(20)参数模式:
in:该参数可以作为输入,也就是该参数需要调用方传入值
out:该参数可以作为输出,也就是该参数可以作为返回值
inout:该参数既可以作为输入又可以作为输出,也就是该参数既需要传入值,又可以返回值2、如果存储过程体仅仅只有一句话,begin end可以省略
存储过程体中的每条sql语句的结尾要求必须加分号。
存储过程的结尾可以使用 delimiter 重新设置
语法:
delimiter 结束标记
案例:
delimiter $
*/-- 2.调用语法
CALL 存储过程名(实参列表);-- 3.案例演示
-- 3.1 空参列表
-- 案例:插入到admin表中五条记录
SELECT * FROM admin;delimiter $ #自定义结束标记符
CREATE PROCEDURE myp1()
BEGIN
INSERT INTO admin(username,`password`)
VALUE ('john1','0000'),('lily','0000'),('rose','0000'),('jack','0000'),('tom','0000');
END $-- 调用
CALL myp1()$-- 3.2 创建带in模式参数的存储过程
-- 案例1:创建存储过程实现 根据女神名,查询对应的男神信息delimiter $ #自定义结束标记符
CREATE PROCEDURE myp2(IN beautyName VARCHAR(20))
BEGIN
SELECT b.*,bo.* FROM boys bo
RIGHT JOIN beauty b ON bo.id = b.boyfriend_id
WHERE b.`name` = beautyName;
END $-- 调用
CALL myp2('柳岩')$
CALL myp2('小昭')$-- 案例2:创建存储过程实现,用户是否登录成功
delimiter $ #自定义结束标记符
CREATE PROCEDURE myp3(IN `username` 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 myp3('张飞','8888')$-- 3.3 创建带out模式参数的存储过程
-- 案例1:根据输入的女神名,返回对应的男神名
delimiter $ #自定义结束标记符
CREATE PROCEDURE myp5(IN `beautyName` VARCHAR(20),OUT `boyName` VARCHAR(20))
BEGIN
SELECT bo.boyName INTO `boyName`
FROM boys bo
INNER JOIN beauty b ON bo.id = b.boyfriend_id
WHERE b.`name` = `beautyName`;
END $-- 调用
SET @bName$ #自定义用户变量
CALL myp5('小昭',@bName)$
SELECT @bName$ #使用变量-- 案例2:根据输入的女神名,返回对应的男神名和魅力值
delimiter $ #自定义结束标记符
CREATE PROCEDURE myp6(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 $-- 调用
CALL myp6('小昭',@bName,@usercp)$
SELECT @bName,@usercp$ #使用变量-- 3.4 创建带inout模式参数的存储过程
-- 案例1:传入a和b两个值,最终a和b都翻倍并返回
delimiter $ #自定义结束标记符
CREATE PROCEDURE myp7(INOUT a INT,INOUT b INT)
BEGIN
SET a = a * 2; #局部变量赋值
SET b = b * 2;
END $-- 调用
SET @m=10$ #定义用户变量
SET @n=20$
CALL myp7(@m,@n)$
SELECT @m,@n$ #使用变量-- 4.删除存储过程
/*
语法:drop procedure 存储过程名
*/
DROP PROCEDURE test_pro3;
DROP PROCEDURE p2,p3; #报错,不能一次删除多个-- 5.查看存储过程的信息
DESC myp2; #报错
SHOW CREATE PROCEDURE myp2;
11.1 存储过程练习
-- 1.创建存储过程实现传入用户名和密码,插入到admin表中
delimiter $ #自定义结束标记符
CREATE PROCEDURE test_pro1(IN `username` VARCHAR(20),IN `loginPwd` VARCHAR(20))
BEGIN
INSERT INTO admin(admin.username,admin.`password`)
VALUES(username,loginPwd);
END $-- 调用
CALL test_pro1('xiexu','283619')$-- 2.创建存储过程实现传入女神编号,返回女神名称和女神电话
delimiter $ #自定义结束标记符
CREATE PROCEDURE test_pro2(IN `bid` INT,OUT `uname` VARCHAR(20),OUT `uphone` VARCHAR(20))
BEGIN
SELECT b.name,b.phone INTO `uname`,`uphone`
FROM beauty b
WHERE b.id = `bid`;
END $-- 调用
CALL test_pro2(2,@uname,@uphone)$
SELECT @uname,@uphone$-- 3.创建存储过程或函数实现传入两个女神生日,返回大小
delimiter $ #自定义结束标记符
CREATE PROCEDURE test_pro3(IN `birth1` DATETIME,IN `birth2` DATETIME,OUT `result` INT)
BEGIN
SELECT DATEDIFF(`birth1`,`birth2`) INTO `result`;
END $-- 调用
CALL test_pro3('1987-12-30',now(),@m)$
SELECT @m$-- 4.创建存储过程或函数实现传入一个日期,格式化成xx年xx月xx日并返回
delimiter $ #自定义结束标记符
CREATE PROCEDURE test_pro4(IN `mydate` DATETIME,OUT `strDate` VARCHAR(10))
BEGIN
SELECT DATE_FORMAT(`mydate`,'%y年%m月%d日') INTO `strDate`;
END $-- 调用
CALL test_pro4(now(),@str)$
SELECT @str$-- 5.创建存储过程或函数实现传入女神名称,返回:女神 and 男神 格式的字符串
/*
如 传入 :小昭
返回: 小昭 AND 张无忌
*/
delimiter $ #自定义结束标记符
CREATE PROCEDURE test_pro5(IN `beautyName` VARCHAR(20),OUT `str` VARCHAR(50))
BEGIN
SELECT CONCAT(`beautyName`,' and ',IFNULL(bo.boyName,'NULL')) INTO `str`
FROM boys bo
RIGHT JOIN beauty b ON b.boyfriend_id = bo.id
WHERE b.name = `beautyName`;
END $-- 调用
CALL test_pro5('柳岩',@str)$
SELECT @str $-- 6.创建存储过程或函数,根据传入的条目数和起始索引,查询beauty表的记录
delimiter $ #自定义结束标记符
CREATE PROCEDURE test_pro6(IN `startIndex` INT,IN `size` INT)
BEGIN
SELECT * FROM beauty LIMIT `startIndex`,`size`;
END $-- 调用
CALL test_pro6(3,5)$
12.函数
-- 函数
/*
含义:一组预先编译好的SQL语句的集合,理解成批处理语句
1、提高代码的重用性
2、简化操作
3、减少了编译次数并且减少了和数据库服务器的连接次数,提高了效率区别:
存储过程:可以有0个返回,也可以有多个返回,适合做批量插入、批量更新
函数:有且仅有1个返回,适合做处理数据后返回一个结果
*/-- 1.创建语法
/*
CREATE FUNCTION 函数名(参数列表) RETURNS 返回类型
BEGIN函数体
END注意:
1.参数列表 包含两部分:参数名 参数类型2.函数体:肯定会有return语句,如果没有会报错
如果return语句没有放在函数体的最后也不报错,但不建议return 值;
3.函数体中仅有一句话,则可以省略begin end
4.使用delimiter语句设置结束标记
*/-- 2.调用语法
/*
SELECT 函数名(参数列表)
*/-- 3.案例演示-- 3.1 无参有返回
-- 案例:返回公司的员工个数
delimiter $ #自定义结束标记符
CREATE FUNCTION myf1() RETURNS INT
BEGIN
DECLARE c INT DEFAULT 0; #定义局部变量,并且加上默认值0SELECT count(*) INTO c #为局部变量赋值
FROM employees;
RETURN c;
END $-- 调用
SELECT myf1()$-- 3.2 有参有返回
-- 案例1:根据员工名,返回它的工资
delimiter $ #自定义结束标记符
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('Kochhar')$-- 案例2:根据部门名,返回该部门的平均工资
delimiter $ #自定义结束标记符
CREATE FUNCTION myf3(`deptName` VARCHAR(20)) RETURNS DOUBLE
BEGIN
DECLARE av DOUBLE; #定义局部变量SELECT AVG(salary) INTO av #为局部变量赋值
FROM employees e
INNER JOIN departments d ON e.department_id = d.department_id
WHERE d.department_name = `deptName`;RETURN av;
END $-- 调用
SELECT myf3('IT')$-- 4.查看函数
SHOW CREATE FUNCTION myf3;-- 5.删除函数
DROP FUNCTION myf3;-- 案例:创建函数,实现传入两个float,返回二者之和
delimiter $ #自定义结束标记符
CREATE FUNCTION test_fun1(`num1` FLOAT,`num2` FLOAT) RETURNS FLOAT
BEGINDECLARE SUM FLOAT DEFAULT 0; #定义局部变量,并且有默认值0SET SUM=num1+num2;RETURN SUM;
END $SELECT test_fun1(1,2)$
13.流程控制结构
-- 流程控制结构
/*
顺序结构:程序从上往下依次执行
分支结构:程序从两条或多条路径中选择一条去执行
循环结构:程序在满足一定条件的基础上,重复执行一段代码
*/-- 1.分支结构-- 1.1 case结构
/*
情况一:类似于switch,一般用于实现等值判断
语法:
case 变量或表达式
when 值1 then 语句1;
when 值2 then 语句2;
...
else 语句n;
end case;情况2:类似于多重if语句,一般用于实现区间判断。
语法:
case
when 条件1 then 语句1;
when 条件2 then 语句2;
...
else 语句n;
end case;特点:
①可以作为表达式,嵌套在其他语句中使用。可以放在任何地方,BEGIN END 中或BEGIN END 的外面
②可以作为独立的语句去使用,只能放在BEGIN END中如果when中的值满足或条件成立,
则执行对应的then后面的语句,并且结束CASE如果都不满足,则执行E1SE中的语句或值。③ELSE可以省略,如果ELSE省略了,并且所有WHEN条件都不满足,则返回NULL。位置:
可以放在任何位置,
如果放在begin end 外面,作为表达式结合着其他语句使用
如果放在begin end 里面,一般作为独立的语句使用
*/-- 案例:创建存储过程,根据传入的成绩,来显示等级,比如传入的成绩:90-100, 显示A,80-90,显示B,60-80,显示c,否则,显示D
delimiter $ #自定义结束标记符
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(55)$-- 1.2 if结构
/*
语法:
if 条件1 then 语句1;
elseif 条件2 then 语句2;
....
[else 语句n;]
end if;功能:类似于多重if
位置:只能应用在begin end中
*/-- 案例:创建函数,实现传入成绩,如果成绩>90,返回A,如果成绩>80,返回B,如果成绩>60,返回C,否则返回D
delimiter $ #自定义结束标记符
CREATE FUNCTION test_if(score INT) RETURNS CHAR
BEGIN
if score>=90 AND score<=100 THEN RETURN 'A';
ELSEIF score>=80 THEN RETURN 'B';
ELSEIF score>=60 THEN RETURN 'C';
ELSE RETURN 'D';
END IF;END $-- 调用
SELECT test_if(86)$-- 2.循环结构
/*
分类:
while、loop、repeat循环控制:
iterate类似于continue,继续,结束本次循环,继续下一次
leave 类似于break,跳出,结束当前所在的循环
*/-- 2.1 while
/*
语法:
[标签:]while 循环条件 do循环体;
end while [标签];联想:
while(循环条件){循环体;
}
*/-- 没有添加循环控制语句
-- 案例1:批量插入,根据次数插入到admin表中多条记录
delimiter $ #自定义结束标记符
CREATE PROCEDURE pro_while1(IN `insertCount` INT)
BEGIN
DECLARE i INT DEFAULT 1; #定义局部变量,并且有默认值1WHILE i<=`insertCount` DO
INSERT INTO admin(username,`password`) VALUES (CONCAT('Rose',i),'666');
SET i=i+1;
END WHILE;END $-- 调用
CALL pro_while1(100)$SELECT * FROM admin$-- 添加leave语句
-- 案例2:批量插入,根据次数插入到admin表中多条记录,如果次数大于20则停止
TRUNCATE TABLE admin$ #删除admin表中的全部数据delimiter $ #自定义结束标记符
CREATE PROCEDURE pro_while2(IN `insertCount` INT)
BEGIN
DECLARE i INT DEFAULT 1; #定义局部变量,并且有默认值1a:WHILE i<=`insertCount` DO
INSERT INTO admin(username,`password`) VALUES (CONCAT('xiaohua',i),'666');
IF i>=20 THEN LEAVE a; #如果i>=20,就结束当前所在的循环,类似于break
END IF;
SET i=i+1;
END WHILE a;END $-- 调用
CALL pro_while2(100)$-- 添加iterate语句
-- 案例:批量插入,根据次数插入到admin表中多条记录,只插入偶数次
TRUNCATE TABLE admin$ #删除admin表中的全部数据delimiter $ #自定义结束标记符
CREATE PROCEDURE pro_while3(IN `insertCount` INT)
BEGIN
DECLARE i INT DEFAULT 0; #定义局部变量,并且有默认值1a:WHILE i<=`insertCount` DO
SET i=i+1;
IF MOD(i,2)!=0 THEN ITERATE a; #如果i%2!=0,就结束此次循环,继续执行下一次循环,类似于continue
END IF;INSERT INTO admin(username,`password`) VALUES (CONCAT('xiaohua',i),'000');END WHILE a;END $-- 调用
CALL pro_while3(100)$-- 2.2 loop
/*
语法:
[标签:]loop循环体;
end loop [标签];可以用来模拟简单的死循环
*/-- 2.3 repeat
/*
语法:
[标签:]repeat循环体;
until 结束循环的条件
end repeat [标签];
*/
13.1 流程控制结构练习
/*
已知表stringcontent
其中字段:
id 自增长
content varchar(20)向该表插入指定个数的,随机的字符串
*/DROP TABLE IF EXISTS stringcontent;-- 创建表stringcontent
CREATE TABLE stringcontent(id INT PRIMARY KEY AUTO_INCREMENT,content VARCHAR(20)
);-- 操作
delimiter $ #自定义结束标记符
CREATE PROCEDURE test_randstr_insert(IN `insertCount` INT)
BEGIN
#定义一个循环变量i,表示插入次数
DECLARE i INT DEFAULT 1;
#定义一个具有26个字母的字符串
DECLARE str VARCHAR(26) DEFAULT 'abcdefghijklmnopqrstuvwxyz';
#代表初始索引
DECLARE startIndex INT;
#代表截取的字符长度
DECLARE len INT;WHILE i<=`insertCount` DO
#floor表示向下取整,rand()*26+1表示产生[1,27)之间的随机数
SET startIndex=FLOOR(RAND()*26+1); #代表初始索引,随机范围1-26
#因为content定义varchar(20),所以最多只能截取20个
#代表截取长度,随机范围 1 - (20-startIndex+1)
SET len=FLOOR(RAND()*(20-startIndex+1)+1);INSERT INTO stringcontent(content) VALUES(SUBSTR(str,startIndex,len));SET i=i+1; #循环变量更新
END WHILE;END $-- 调用
CALL test_randstr_insert(10)$
学习MySQL看这一篇就够了相关推荐
- nginx学习,看这一篇就够了:下载、安装。使用:正向代理、反向代理、负载均衡。常用命令和配置文件,很全
文章目录 前言 一.nginx简介 1. 什么是 nginx 和可以做什么事情 2.Nginx 作为 web 服务器 3. 正向代理 4. 反向代理 5. 负载均衡 6.动静分离 二.Nginx 的安 ...
- 惊呆!学习MySQL真的这一篇就够了!太全了
这是我见过学习MySQL最全的一篇文章! https://caochenlei.blog.csdn.net/article/details/107640904 目录 第一章 数据库概述 1.1.数据库 ...
- 《JavaWeb篇》01.Mysql看这一篇就够了
目录 一.MySQL基础 资源分享 1,数据库相关概念 1.1 数据库 1.2 数据库管理系统 1.3 常见的数据库管理系统 1.4 SQL 2,MySQL 2.5 MySQL数据模型 3,SQL概述 ...
- python 股票自动交易助手_学习 Python 看这一篇就够了!
2019.08.05 「Python 技术」公众号发出了第一篇文章,时至今日,已经快一年了.期间我们累积发文 260+ 篇,52 周除去周末我们基本做到了日更,这一路走来磕磕碰碰有太多的不容易,会有为 ...
- 50多岁学python_学习 Python 看这一篇就够了!
2019.08.05 「Python 技术」公众号发出了第一篇文章,时至今日,已经快一年了.期间我们累积发文 260+ 篇,52 周除去周末我们基本做到了日更,这一路走来磕磕碰碰有太多的不容易,会有为 ...
- [转]nginx学习,看这一篇就够了:下载、安装。使用:正向代理、反向代理、负载均衡。常用命令和配置文件
文章目录 前言 一.nginx简介 1. 什么是 nginx 和可以做什么事情 2.Nginx 作为 web 服务器 3. 正向代理 4. 反向代理 5. 负载均衡 6.动静分离 二.Nginx 的安 ...
- nginx学习,看这一篇就够了(转)
文章目录 前言 一.nginx简介 1. 什么是 nginx 和可以做什么事情 2.Nginx 作为 web 服务器 3. 正向代理 4. 反向代理 5. 负载均衡 6.动静分离 二.Nginx 的安 ...
- TSN时间敏感网络|学习笔记-看这一篇就够了
近年来,随着汽车电子电气架构的演进,车载以太网以其高带宽.技术成熟和灵活部署等优势成功占据汽车主干网地位,但是传统以太网具有的时间不确定性,对自动驾驶.智能网联等前沿需求带来巨大挑战.为此,IEEE ...
- mysql客户端栏目变灰色,MySQL看这一篇就够了
No.1 数据库概念 什么是数据库? 数据库就是一种特殊的文件,内部存储着需要的数据 RDBMS 所谓关系数据库,是建立在关系模型基础的数据库,借助于集合代数等数学概念和方法来处理数据库中的数据 SQ ...
最新文章
- 面试官问:消息被重复消费,怎么避免?有什么好的解决方案?
- Kubernetes对象模型
- 百度Apollo发布中国首个自动驾驶安全报告,L3级别产品2020年量产上市
- Expected a default value of type Tensor on parameter residual:
- 使用Spring Data JPA进行分页和排序
- C# XML格式化显示
- 企业微信:腾讯的“佛系”办公江湖
- 直播行业运维关注的流程图
- polycom安卓手机客户端_Spark,安卓上最好用的邮件客户端来了!附App下载
- 第二章:09流程控制[2switch]
- 有趣的Windows之mysql的zip安装及配置
- 计算机四级少选给分吗,计算机四级:考高分的有效途径(转载)
- 超级保镖计算机管理系统
- 从编程当中走向创业之路
- BugkuCTF writeup
- Worthington胰蛋白酶解决方案
- 【用es6写个机选彩票】
- 桥 Gym100712H Bridges
- 【Spring】普通类获取Spring容器的bean的方法
- 直流电机/步进电机/伺服电机 简介
热门文章
- java自行车起源_公路自行车赛的起源、发展及历史
- ASP.NET Core MVC中的viewmodel
- Warning: Class ‘com.xxx.xxx‘ not found in module ‘xxxx‘
- Ubuntu下快捷键操作
- STM32的介绍及MDK
- JavaCV的配置及使用
- 详解超声波测距模块HC-SR04的使用
- java折木棍_蓝桥杯算法训练 Sticks(木棍)问题(JAVA)
- HTML XHTML CS3 JS网页制作(IT培训网站设计+当当网首页设计)
- 百胜中国2020年第三季度总收入为23.5亿美元,同比增加1%