MySQL服务的启动和停止
方式一:计算机 - 右击管理 - 服务
方式二:以管理员身份运行命令行
net start 服务名(启动服务)
net stop 服务名(停止服务)
MySQL服务的登陆和退出
方式一:通过MySQL自带的客户端(有局限性,只限于root用户)
方式二:通过windows自带的客户端(以管理员身份运行命令行)
登陆:
mysql [-h主机名 -P端口号] -u用户名 -p密码
(注意:如果是本机,-h主机名 -P端口号可以省略,-p密码之间不允许有空格,其它可以有空格,也可无空格)
退出:
exit 或 ctrl + c(我尝试ctrl+c不管用) 或 \q 或 quit
注意:如果执行 mysql [-h主机名 -P端口号] -u用户名 -p密码 命令,结果显示:
【 "mysql" 不是内部或外部命令,也不是可运行的程序或批处理文件】
则需要把MySQL的安装的bin目录配置到path环境变量中.
MySQL的常见命令
1、查看当前所有的数据库
show databases;
2、打开指定的库
use 库名;
3、查看当前库的所有表
show tables;
4、查看其它库的所有表
show tables from 库名;
(注意:此命令是在当前库查看其它库的所有表)
5、查看当前位于哪个库
select database();
6、 创建表
create table 表名(
列名 列类型,
列名 列类型,
.......
);
7、查看表结构
desc 表名;
8、查看服务器的版本
方式一:登陆到mysql 服务端
select version();
方式二:没有登陆mysql服务端(以管理员身份运行命令行)
mysql --version
或
mysql -V
MySQL的语法规范
1、不区分大小写,但建议关键字大写,表名、列名小写
2、每条命令最好用分号结尾
3、每条命令根据需要,可以进行缩进 或换行
4、MySQL中可以使用单引号也可以使用双引号
5、注释
单行注释:#注释文字 或者 -- 空格 注释文字
多行注释:/* 注释文字 */
SQL的语言分类
DQL (Data Query Language):数据查询语言 【select】
DML (Data Manipulate Language):数据操作语言 【insert 、update、delete】
DDL (Data Define Language):数据定义语言 【create、drop、alter】
TCL (Transaction Control Language):事务控制语言 【commit、rollback】
DQL语言的学习
进阶一:基础查询
特点:
①通过select查询完的结果 ,是一个虚拟的表格,不是真实存在
② 要查询的东西 可以是常量值、可以是表达式、可以是字段、可以是函数
1、查询单个字段、多个字段、所有字段;
2、查询常量值: select 100; select 'join';
注意:字符型和日期型的常量值必须用单引号括起来,数值型不需要;
3、查询表达式: select 90 * 100;
4、查询函数(必须要有返回值): select version();
5、起别名:AS 或者 空格
例如: select 100 % 98 AS 结果;
select 100 % 98 结果;
select 100 % 98 AS "OUT PUT";
6、DISTINCT :去重
7、MYSQL中 + 的作用:仅仅只有一个功能,即运算符
①、两个操作数都为数值,则做加法运算;
select 100 + 90;
②、如果其中一方为字符型,试图将字符型数值转换成数值型,
如果转换成功,则继续做加法运算; select '123' + 90; ---> 213
如果转换失败,则将字符型数值转换为0进行加法运算; select 'join' + 90; ---> 90
③、如果其中一方为null,则结果肯定为null ; select null + 10; ---> null
8、使用CONCAT函数实现字符连接:select CONCAT('a','b','c') as 结果; ---> abc
select CONCAT('a','null','c') as 结果; ---> anullc
select CONCAT('a',null,'c') as 结果; ---> null 只要有一个值为null,则结果为null
9、ifnull 函数功能:判断某字段或表达式的值是否为null,如果为null,返回指定的值,否则返回原本的值
select ifnull(commission_pct, 0) from employees; -->如果将近率commission_pct为null,则返回0,如果不为null,则返回原本的值
10、isnull 函数功能:判断某字段或表达式的值是否为null,如果为null,则返回1(表示true),否则返回0(表示false)
select isnull(commission_pct) from employees;
进阶二:条件查询
1、条件查询:根据条件过滤原始表的数据,查询到想要的数据
2、语法:
select 要查询的字段|表达式|常量值|函数
from 表
where 条件 ;
3、分类:
一、条件表达式 示例:salary>10000
条件运算符: >、 <、 >=、 <=、 =、 !=、 <>
二、逻辑表达式 示例:salary>10000 && salary<20000
逻辑运算符:
and(&&):两个条件如果同时成立,结果为true,否则为false
or(||):两个条件只要有一个成立,结果为true,否则为false
not(!):如果条件成立,则not后为false,否则为true
三、模糊查询 :like、between and 、in 、is null 或 is not null
* like特点:
①、一般和通配符搭配使用,可以判断字符型或者数值型
通配符:
% :任意多个字符,包含0个字符
_ : 任意单个字符
示例:last_name like 'a%';
或者
department_id like '2%';
或者
last_name like '_$_%' ESCAPE '$'; 转义字符,第二个字符为_
或者
last_name like '_\_%' ; 转义字符,第二个字符为_
* between and 特点:
①、包含临界值,等价于 >= and <= ,所以两个临界值之间顺序不可以互换
* is null 或 is not null 特点:
①、= 或 <> 不能用于判断 null 值;
②、is null 或 is not null 只能用于判断 null 值;
* <=> 表示安全等于,既可以用于判断null值,也可以用于判断普通的数值,可读性较低
示例:1、查询没有奖金的员工
select * from employees where commission_pct is null;
或
select * from employees where commission_pct <=> null;
2、查询工资为12000的员工
select * from employees where salary<=> 12000;
或
select * from employees where salary = 12000;
案例:
1、查询员工号为176的员工的姓名和部门号以及年薪
select employee_id, department_id, salary*12*(1 + IFNULL(commission,0)) from employees where employee_id = 176
2、经典面试题
①、试问 select * from employees; 和 select * from employees where commission_pct like '%%' and last_name like '%%';结果是否一样,请说明原因
不一样,因为commission_pct 可能为null
②、 试问 select * from employees; 和 select * from employees where commission_pct like '%%' or last_name like '%%' or employee_id like '%%';结果是否一样,请说明原因
一样,因为是用or 连接,总有一个字段是没有null值的
进阶三:排序查询
语法:
select 查询列表
from 表名
where 条件
order by 排序的字段(单个或者多个字段) | 表达式 | 函数 | 别名 【asc|desc】
特点:
1、asc 代表升序,desc代表降序,如果不写,默认为升序
2、order by 子句一般放在查询语句的最后面,limit 子句除外
进阶四:常见函数
一、单行函数
1、字符函数
concat(str1, str2, str3, str4......):拼接字符
substr / substring:截取字符 【 注意:索引是从1开始的】
upper(str):把参数值转换成大写
lower(str):把参数值转换成小写
trim:去除前后指定的空格和字符
例如:
select trim(' 张三 '); ---> 去除前后空格
select trim('a' from 'aaaaa张aaaa三aaaaaa'); ---> 去除前后指定字符a,结果为:张aaaa三
ltrim:去左边空格
rtrim:去右边空格
replace(str, from_str, to_str):替换,把 str 中所有的 from_str 替换成 to_str
lpad(str, len, padstr):用指定的字符padstr 左填充 str 到指定的长度 len【注意是字符个数,不是字节个数】,如果str 超过了指定的长度len,则对str 进行右截取
rpad(str, len, padstr):用指定的字符padstr 右填充 str 到指定的长度 len【注意是字符个数,不是字节个数】,如果str 超过了指定的长度len,则对str 进行右截取
instr(str, substr):返回子串 substr 在 str 中第一次出现的索引,如果没有找到,则返回0
length(str): 获取参数值的字节个数(对于中文,utf8 -> 一个汉字3个字节,GBK -> 一个汉字2个字节)
2、数学函数
round :四舍五入
例如:select round(1.46); ---> 1
select round(-1.56); ---> -2 (如果是负数,先取绝对值进行四舍五入,然后再加上负号)
select round(1.678, 2); ---> 小数点后保留2位,结果为:1.68
rand :rand函数用于产生0(包含)到1(不包含)的随机数
rand有两种形式:
1、rand(),即无参数的,此时产生的随机数是随机的,不可重复的;
2、rand(n),即有参数的,如rand(2),相当于指定随机数生产的种子,那么这种情况产生的随机数是可重复的。
floor向下取整,返回小于等于该参数的最大整数
例如: select floor(1.99); ---> 1
select floor(-9.99); ---> -10
ceil(x):向上取整,返回大于等于该参数的最小整数
例如: select ceil(1.002); ---> 2
select ceil(1.00); ---> 1
select ceil(-1.002); ---> -1
mod(n, m):取余(n - n / m * m) 【注意:如果n 为负数,则结果为负数,如果n为正数,则结果为正数】
例如:select mod(10, 3); ---> 1
select mod(-10, -3); ---> -1
select mod(10, -3); ---> 1
truncate(X, D):截断
例如: select truncate(1.6999, 1); --->表示小数点后保留1位,其余截断,即:1.6
3、日期函数
now:返回当前系统的日期+时间 select now();
curdate:返回当前系统的日期,不包含时间 select curdate();
curtime:返回当前系统的时间,不包含日期 select curtime();
可以获取指定的部分,比如:年、月、日、时、分、秒
select year(now()) 年,month(now()) 月 ,day(now()) 日,hour(now()) 时 ,minute(now()) 分 ,second(now()) 秒;
select monthname(now()) 月; --->获取月份的英文名称
str_to_date: 将日期格式的字符转换成指定格式的日期
例如:select str_to_date('4-3 1993', '%c-%d %y');
格式符 功能
%Y 四位的年份
%y 2位的年份
%m 月份(01, 02, ... 11, 12)
%c 月份(1, 2, ... 11, 12)
%d 日(01, 02, ...)
%H 小时(24小时制)
%h 小时(12小时制)
%i 分钟(00, 01, ... 59)
%s 秒(00, 01, ... 59)
date_format(date, format):将日期转换成字符
例如:select date_format(now(), '%y年%m月%d日');
datediff(expr,expr2):求两个日期之间相差的天数
4、流程控制函数
①、if(expr1, expr2, expr3) : 处理双分支,相当于if else 的效果,对于表达式expr1,如果表达式成立为true,则返回expr2的值,否则返回expr3的值;
例如:select if(10 > 5, '正确', '错误');
②、case语句 :处理多分支
情况1:处理等值判断
语法:
case 要判断的字段或表达式
when 常量1 then 要显示的值1或语句1【如果是语句,要加分号,如果是值,则不加分号】
when 常量2 then 要显示的值2或语句2
.....
else 要显示的值n 或 语句n
end
例如:查询员工的工资,要求,如果部门号=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;
情况2:处理条件判断
语法:
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、其他函数
version:版本 select version();
database:当前库 select database();
user:当前连接用户 select user();
password('字符'):返回该字符的加密形式
md5('字符'):返回该字符的md5加密形式
二、分组函数,用做统计使用,又称为 统计函数 或 聚合函数 或 组函数
sum :求和
max :最大值
min :最小值
avg :平均值
count :计数
特点:
1、以上五个分组函数都忽略null值,除了count(*)
2、sum 和 avg 一般用于处理数值型, max、min、count 可以处理任何数据类型
3、都可以搭配distinct使用,用于统计去重后的结果
4、count的参数可以支持: 字段、*、常量值,一般放1
5、和分组函数一同查询的字段要求是group by 后的字段
建议使用 count(*)
进阶五:分组查询
语法:
select 分组函数, 查询的字段(要求必须出现才group by 后面的)
from 表
【where 筛选条件】
group by 分组的字段
【order by 子句】
注意: 查询列表比较特殊,要求是分组函数和 group by 后面的出现的字段
特点:
1、和分组函数一同查询的字段最好是分组后的字段
2、分组查询中的筛选条件分为两类
针对的表 位置 关键字
分组前筛选: 原始表 group by子句的前面 where
分组后筛选: 分组后的结果集 group by子句的后面 having
①、分组函数做条件肯定是放在having子句中
②、能用分组前筛选的就优先考虑使用分组前筛选的
3、group by 子句可以支持按单个字段分组, 也可以支持按多个字段分组, 字段之间用逗号隔开, 没有顺序要求,也可以支持表达式或函数分组
4、可以支持排序(排序放在整个分组查询的最后)
5、having 、order by 后可以支持别名
进阶六:连接查询
1、连接查询又称为多表查询,当查询的字段来自于多个表时,就会用到连接查询
2、笛卡尔乘积现象:表1 有 m 行,表2有 n 行,结果有 m*n 行
* 发生的原因:没有有效的连接条件
* 如何避免:添加有效的连接条件
3、分类
* 按年代分类:
①、sql 92标准:在MySQL中仅仅支持内连接
* 内连接
等值连接:
- 多表等值连接的结果为多表的交集部分
- n 表连接,至少需要 n - 1 个连接条件
- 多表的顺序没有要求, 多表没有主次
- 一般需要为表起别名, 提高阅读性和性能
- 可以搭配比如:排序、分组、筛选等子句使用
语法:
select 查询列表
from 表1 别名, 表2 别名
where 表1.key = 表2.key
【and 筛选条件】
【group by 筛选条件】
【having 筛选条件】
【order by 排序字段】
例如:查询每个工种的工种名和员工的个数,并且按员工个数降序
SELECT job_title,COUNT(*)
FROM employees e,jobs j
WHERE e.`job_id`=j.`job_id`
GROUP BY job_title
ORDER BY COUNT(*) DESC;
非等值连接:
语法:
select 查询列表
from 表1 别名, 表2 别名
where 非等值的连接条件
【and 筛选条件】
【group by 筛选条件】
【having 筛选条件】
【order by 排序字段】
例如:查询员工的工资和工资级别
SELECT salary,grade_level
FROM employees e,job_grades g
WHERE salary BETWEEN g.`lowest_sal` AND g.`highest_sal`
AND g.`grade_level`='A';
自连接:
语法:
select 查询列表
from 表 别名1, 表 别名2
where 等值的连接条件
【and 筛选条件】
【group by 筛选条件】
【having 筛选条件】
【order by 排序字段】
案例:查询员工名和上级的名称
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 标准(推荐):支持内连接、外连接(左外连接+右外连接,不支持全外连接)、交叉连接
语法:
select 查询列表
from 表1 别名
【连接类型 inner|left outer|right outer|cross】 join 表2 别名 on 连接条件
【连接类型 inner|left outer|right outer|cross】 join 表3 别名 on 连接条件
【where 筛选条件】
【group by 分组】
【having 筛选条件】
【order by 排序列表】
* 内连接 : inner
特点:
1、 可以添加排序、分组和筛选等;
2、inner 可以省略;
3、筛选条件放在where后面,连接条件放在on后面,提高分离性,便于阅读;
4、inner join 连接和sql92 语法中的等值连接效果是一样的,都是查询多表的交集部分
- 等值连接:
举例:
1、查询哪个部门的员工个数>3的部门名和员工个数,并按个数降序(添加排序)
SELECT COUNT(*) 个数,department_name
FROM employees e
INNER JOIN departments d
ON e.`department_id`=d.`department_id`
GROUP BY department_name
HAVING COUNT(*)>3
ORDER BY COUNT(*) DESC;
2、三表连接:查询员工名、部门名、工种名,并按部门名降序
SELECT last_name,department_name,job_title
FROM employees e
INNER JOIN departments d ON e.`department_id`=d.`department_id`
INNER JOIN jobs j ON e.`job_id` = j.`job_id`
ORDER BY department_name DESC;
- 非等值连接:
举例:查询工资级别的个数>20的个数,并且按工资级别降序
SELECT COUNT(*),grade_level
FROM employees e
JOIN job_grades g
ON e.`salary` BETWEEN g.`lowest_sal` AND g.`highest_sal`
GROUP BY grade_level
HAVING COUNT(*)>20
ORDER BY grade_level DESC;
- 自连接:
举例:查询姓名中包含字符k的员工的名字、上级的名字
SELECT e.last_name,m.last_name
FROM employees e
JOIN employees m
ON e.`manager_id`= m.`employee_id`
WHERE e.`last_name` LIKE '%k%';
* 外连接
应用场景:用于查询一个表中有,另一个表没有的记录
特点:
1、外连接的查询结果为主表中的所有记录
如果从表中有和它匹配的,则显示匹配的值
如果从表中没有和它匹配的,则显示null
外连接查询结果=内连接结果+主表中有而从表没有的记录
2、左外连接,left join左边的是主表
右外连接,right join右边的是主表
3、左外和右外交换两个表的顺序,可以实现同样的效果
4、全外连接=内连接的结果 + 表1中有但表2没有的 + 表2中有但表1没有的
左外连接 : left 【outer】
右外连接 : right 【outer】
案例:查询哪个部门没有员工
#左外
SELECT d.*,e.employee_id
FROM departments d
LEFT OUTER JOIN employees e
ON d.`department_id` = e.`department_id`
WHERE e.`employee_id` IS NULL;
#右外
SELECT d.*,e.employee_id
FROM employees e
RIGHT OUTER JOIN departments d
ON d.`department_id` = e.`department_id`
WHERE e.`employee_id` IS NULL;
全外连接 : full 【outer】
* 交叉连接 :cross (sql 99语法中的笛卡尔乘积)
举例 :
SELECT b.*,bo.*
FROM beauty b
CROSS JOIN boys bo;
* 按功能分类
①、内连接
②、外连接
左外连接
右外连接
全外连接
③、交叉连接
进阶七:子查询
1、含义:出现在其他语句中的select语句,称为子查询或内查询
外部的查询语句,称为主查询或外查询
2、分类:
* 按子查询出现的位置:
select后面:仅仅支持标量子查询
#案例:查询每个部门的员工个数
SELECT d.*,(
SELECT COUNT(*)
FROM employees e
WHERE e.department_id = d.`department_id`
) 个数
FROM departments d;
from后面:支持表子查询, 将子查询结果充当一张表,要求必须起别名
#案例:查询每个部门的平均工资的工资等级
#①查询每个部门的平均工资
SELECT AVG(salary),department_id
FROM employees
GROUP BY department_id
#②连接①的结果集和job_grades表,筛选条件平均工资 between lowest_sal and highest_sal
SELECT ag_dep.*,g.`grade_level`
FROM (
SELECT AVG(salary) ag,department_id
FROM employees
GROUP BY department_id
) ag_dep
INNER JOIN job_grades g
ON ag_dep.ag BETWEEN lowest_sal AND highest_sal;
where或having后面:
标量子查询(单行子查询) √
列子查询 (多行子查询) √
行子查询 (结果集为一行多列 或 多行多列)
特点:
①、子查询放在小括号内
②、子查询一般放在条件的右侧
③、标量子查询,一般搭配着单行操作符使用 >、 < 、>=、 <=、 =、 <>
列子查询,一般搭配着多行操作符使用 in、any/some、all
例如:> any/some(子查询); 意思是大于子查询中的最小值即可【可以使用MIN()函数代替】
> all(子查询); 意思是大于子查询中的最大值即可【可以使用MAX()函数代替】
④、子查询的执行优先于主查询执行,主查询的条件用到了子查询的结果
#1.标量子查询(单行子查询)
案例1:返回job_id与141号员工相同,salary比143号员工多的员工 姓名,job_id 和工资
#①查询141号员工的job_id
SELECT job_id
FROM employees
WHERE employee_id = 141
#②查询143号员工的salary
SELECT salary
FROM employees
WHERE employee_id = 143
#③查询员工的姓名,job_id 和工资,要求job_id=①并且salary>②
SELECT last_name,job_id,salary
FROM employees
WHERE job_id = (
SELECT job_id
FROM employees
WHERE employee_id = 141
) AND salary>(
SELECT salary
FROM employees
WHERE employee_id = 143
);
案例2:查询最低工资大于50号部门最低工资的部门id和其最低工资
①查询50号部门的最低工资
SELECT MIN(salary)
FROM employees
WHERE department_id = 50
②查询每个部门的最低工资
SELECT MIN(salary),department_id
FROM employees
GROUP BY department_id
③ 在②基础上筛选,满足min(salary)>①
SELECT MIN(salary),department_id
FROM employees
GROUP BY department_id
HAVING MIN(salary)>(
SELECT MIN(salary)
FROM employees
WHERE department_id = 50
);
#2、列子查询(多行子查询)
案例1:返回location_id是1400或1700的部门中的所有员工姓名
①查询location_id是1400或1700的部门编号
SELECT DISTINCT department_id
FROM departments
WHERE location_id IN(1400,1700);
②查询员工姓名,要求部门号是①列表中的某一个
SELECT last_name
FROM employees
WHERE department_id in (
SELECT DISTINCT department_id
FROM departments
WHERE location_id IN(1400,1700)
);
# 等价于
SELECT last_name
FROM employees
WHERE department_id =any (
SELECT DISTINCT department_id
FROM departments
WHERE location_id IN(1400,1700)
);
#注意:in 等价于 =any 、 not in 等价于 <>all、<any 等价于 < max()、<all 等价于 <min()、>any 等价于 > min()、>all 等价于 >max()
案例2:返回其它工种中比job_id为‘IT_PROG’工种任一工资低的员工的员工号、姓名、job_id 以及salary
#①查询job_id为‘IT_PROG’部门任一工资
SELECT DISTINCT salary
FROM employees
WHERE job_id = 'IT_PROG'
#②查询员工号、姓名、job_id 以及salary,salary<(①)的任意一个
SELECT last_name,employee_id,job_id,salary
FROM employees
WHERE salary <ANY(
SELECT DISTINCT salary
FROM employees
WHERE job_id = 'IT_PROG'
) AND job_id<>'IT_PROG';
# 等价于
SELECT last_name,employee_id,job_id,salary
FROM employees
WHERE salary < (
SELECT max(salary)
FROM employees
WHERE job_id = 'IT_PROG'
) AND job_id<>'IT_PROG';
案例3:返回其它部门中比job_id为‘IT_PROG’部门所有工资都低的员工 的员工号、姓名、job_id 以及salary
SELECT last_name,employee_id,job_id,salary
FROM employees
WHERE salary<ALL(
SELECT DISTINCT salary
FROM employees
WHERE job_id = 'IT_PROG'
) AND job_id<>'IT_PROG';
# 等价于
SELECT last_name,employee_id,job_id,salary
FROM employees
WHERE salary < (
SELECT min(salary)
FROM employees
WHERE job_id = 'IT_PROG'
) AND job_id<>'IT_PROG';
#3、行子查询(结果集为 一行多列 或者 多行多列)
案例:查询员工编号最小并且工资最高的员工信息
①查询最小的员工编号
SELECT MIN(employee_id)
FROM employees
②查询最高工资
SELECT MAX(salary)
FROM employees
③查询员工信息
SELECT *
FROM employees
WHERE employee_id=(
SELECT MIN(employee_id)
FROM employees
)AND salary=(
SELECT MAX(salary)
FROM employees
);
# 采用行子查询:
SELECT *
FROM employees
WHERE (employee_id,salary)=(
SELECT MIN(employee_id),MAX(salary)
FROM employees
);
exists后面(相关子查询):支持表子查询
语法:
exists(完整的查询语句)
结果:1或0
#案例1:查询有员工的部门名
#in
SELECT department_name
FROM departments d
WHERE d.`department_id` IN(
SELECT department_id
FROM employees
);
#exists
SELECT department_name
FROM departments d
WHERE EXISTS(
SELECT *
FROM employees e
WHERE d.`department_id`=e.`department_id`
);
#案例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、 应用场景:当要显示的数据,一页显示不全,需要分页提交sql请求
2、 语法:
select 查询列表
from 表
【join type join 表2
on 连接条件
where 筛选条件
group by 分组字段
having 分组后的筛选
order by 排序的字段】
limit 【offset,】size;
* offset要显示条目的起始索引(起始索引从0开始)
* size 要显示的条目个数
3、特点:
①limit语句放在查询语句的最后
②公式: limit (page-1)*size,size; 【要显示的页数 page,每页的条目数size】
select 查询列表
from 表
limit (page-1)*size,size;
#案例1:查询前五条员工信息
SELECT * FROM employees LIMIT 0,5;
SELECT * FROM employees LIMIT 5;
#案例2:查询第11条——第25条
SELECT * FROM employees LIMIT 10,15;
#案例3:有奖金的员工信息,并且工资较高的前10名显示出来
SELECT * FROM employees
WHERE commission_pct IS NOT NULL
ORDER BY salary DESC
LIMIT 10 ;
进阶九:联合查询
1、union 联合 合并:将多条查询语句的结果合并成一个结果
2、语法:
查询语句1
union
查询语句2
union
...
3、应用场景:
要查询的结果来自于多个表,且多个表没有直接的连接关系,但查询的信息一致时
4、特点:
① 、要求多条查询语句的查询列数是一致的!
② 、要求多条查询语句的查询的每一列的类型和顺序最好一致
③ 、union关键字默认去重,如果使用union all 可以包含重复项
#引入的案例:查询部门编号>90或邮箱包含a的员工信息
SELECT * FROM employees WHERE email LIKE '%a%' OR department_id>90;;
SELECT * FROM employees WHERE email LIKE '%a%'
UNION
SELECT * FROM employees WHERE department_id>90;
#案例:查询中国用户中男性的信息以及外国用户中年男性的用户信息
SELECT id,cname FROM t_ca WHERE csex='男'
UNION ALL
SELECT t_id,tname FROM t_ua WHERE tGender='male';
DML语言的学习
DML (数据操作语言):
插入:insert
修改:update
删除:delete
一、插入语句
方式一:经典的插入
1、 语法:
insert into 表名(列名,...) values(值1,...);
2、特点:
①、字段类型和值类型必须一致或兼容,而且要一一对应
②、可以为空的字段,可以不用插入值,或用null填充;不可以为空的字段,必须插入值
③、列的顺序可以调换,但必须一一对应
④、字段个数和值的个数必须一致
⑤、列名可以省略,但默认所有列名的顺序和表中的存储顺序一致
方式二:
1、 语法:
insert into 表名 set 列名=值,列名=值,... ;
两种方式大pk
#1、方式一支持插入多行,方式二不支持
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);
#2、方式一支持子查询,方式二不支持
INSERT INTO beauty(id,NAME,phone)
SELECT 26,'宋茜','11809866';
或
INSERT INTO beauty(id,NAME,phone)
SELECT id,boyname,'1234567'
FROM boys WHERE id<3;
二、修改语句
1、修改单表的记录
语法:
update 表名
set 列=新值,列=新值,...
where 筛选条件;
2、修改多表的记录【补充】
sql92语法:
update 表1 别名,表2 别名
set 列=值,...
where 连接条件
and 筛选条件;
sql99语法:
update 表1 别名
inner|left|right join 表2 别名
on 连接条件
set 列=值,...
where 筛选条件;
#案例2:修改没有男朋友的女神的男朋友编号都为2号
UPDATE boys bo
RIGHT JOIN beauty b ON bo.`id`=b.`boyfriend_id`
SET b.`boyfriend_id`=2
WHERE bo.`id` IS NULL;
三、删除语句
方式一: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 筛选条件;
#案例:删除张无忌的女朋友的信息
DELETE b
FROM beauty b
INNER JOIN boys bo ON b.`boyfriend_id` = bo.`id`
WHERE bo.`boyName`='张无忌';
#案例:删除黄晓明的信息以及他女朋友的信息
DELETE b,bo
FROM beauty b
INNER JOIN boys bo ON b.`boyfriend_id`=bo.`id`
WHERE bo.`boyName`='黄晓明';
方式二:truncate
语法:
truncate table 表名; 【不可以加where 条件】
* delete pk truncate【面试题】
1.delete 可以加筛选[where] 条件,truncate不能加where 条件
2.truncate删除,效率高一丢丢
3.假如要删除的表中有自增长列,
如果用delete删除后,再插入数据,自增长列的值从断点开始,
而truncate删除后,再插入数据,自增长列的值从1开始。
4.truncate删除没有返回值,delete删除有返回值,返回受影响的行数
5.truncate删除不能回滚,delete删除可以回滚.
DDL语言的学习
DDL(数据定义语言):用于库和表的管理
* 库的管理:创建(create)、修改(alter)、删除(drop)
* 表的管理:创建(create)、修改(alter)、删除(drop)
一、库的管理
1、库的创建
(1)、第一种写法:
create [if not exists] database 数据库名;
(2)、第二种写法:
create [if not exists] database 数据库名 default character set 编码集;
(3)、第三种写法:
create [if not exists] database 数据库名 default character set 编码集 COLLATE 校验集;
例如:
create database mysql1;
create database mysql2 character set utf8; //指定字符集
create database mys1l3 character set utf8 collate utf8_general_ci; //指定字符集和校验集
2、库名的修改【以前可以使用,现在不可以,因为可能导致库中数据的丢失】
RENAME DATABASE books TO 新库名;
3、修改数据库(了解):
(1)、修改数据库的编码与校验集:
alter database 数据库名 character set 字符编码集 collate 校验集;
(2)、切换数据库:
use 数据库名;
(3)、查看当前所使用的数据库:
select database();
4、库的删除
DROP DATABASE IF EXISTS 数据库名;
5、查看数据库:
show databases; //查看数据库服务器下的所有数据库
6、显示数据库的创建语句:
show create database 数据库名; //可以看到数据库创建时指定的相关信息
二、表的管理
1.表的创建
语法:
create table 表名(
列名 列的类型【(长度) 约束】,
列名 列的类型【(长度) 约束】,
列名 列的类型【(长度) 约束】,
...
列名 列的类型【(长度) 约束】
)engine=引擎名 default charset=字符集;
#案例:创建表user
create table user( #规范的创建SQL语句
id int(3) primary key auto_increment, #int(3)中的3和tinyint(1)中的1代表的宽度而不是长度
account varchar(22) not null default '',
password varchar(100) not null default '',
create_time datetime not null default current_timestamp,
update_time datetime not null default current_timestamp on update current_timestamp,
record_status tinyint(1) not null default 1
) engine=innoDB default charset=utf8; #创建引擎和默认编码
2.表的修改
语法:
alter table 表名 add|drop|modify|change column 列名 【列类型 约束】;
①、修改列名
ALTER TABLE 表名 CHANGE COLUMN 旧列名 新列名 列类型;
②、修改列的类型或约束
ALTER TABLE 表名 MODIFY COLUMN 列名 列类型;
③、添加新列
ALTER TABLE 表名 ADD COLUMN 列名 列类型 【first | after 字段名】; 【添加到表的前面第一个字段或者指定字段名的后面 】
④、删除列
ALTER TABLE 表名 DROP COLUMN 列名 ;
⑤、修改表名
ALTER TABLE 表名 RENAME 【TO】 新表名;
⑥、修改表的字符集
ALTER TABLE 表名 CONVERT TO CHARACTER SET 字符集 COLLATE 校验集;
⑦、修改字段的字符集
ALTER TABLE 表名 CHANGE 字段名 字段名 该字段原来的数据类型 CHARACTER SET 字符集 COLLATE 校验集;
3.表的删除
语法:
DROP TABLE 【IF EXISTS 】 表名;
#通用的写法:
DROP DATABASE IF EXISTS 旧库名;
CREATE DATABASE 新库名;
DROP TABLE IF EXISTS 旧表名;
CREATE TABLE 表名();
4.表的复制
①、仅仅复制表的结构
CREATE TABLE 要创建的表名 LIKE 已存在的表名;
②、复制表的结构+数据
CREATE TABLE 要创建的表名 SELECT * FROM 已存在的表名;
③、只复制部分数据
CREATE TABLE 要创建的表名
SELECT 要复制的字段 FROM 已存在的表名 WHERE 筛选条件;
④、仅仅复制某些字段,不要数据
CREATE TABLE 要创建的表名
SELECT 要复制的字段 FROM 已存在的表名 WHERE 筛选条件; 【如果只想复制某些字段而不想要数据,则筛选条件可以随便写一个不成立的即可,比如 0 或者 1=2 等】
三、MySQL 创建用户并授权
1、创建用户:
命令:CREATE USER 'username'@'host' IDENTIFIED BY 'password';
说明:username - 你将创建的用户名,
host - 指定该用户在哪个主机上可以登陆,如果是本地用户可用localhost, 如果想让该用户可以从任意远程主机登陆,可以使用通配符%.
password - 该用户的登陆密码,密码可以为空,如果为空则该用户可以不需要密码登陆服务器.
例子: CREATE USER 'dog'@'localhost' IDENTIFIED BY '123456';
CREATE USER 'pig'@'192.168.1.101_' IDENDIFIED BY '123456';
CREATE USER 'pig'@'%' IDENTIFIED BY '123456';
CREATE USER 'pig'@'%' IDENTIFIED BY '';
CREATE USER 'pig'@'%';
2、授权:
命令:GRANT privileges ON databasename.tablename TO 'username'@'host'
说明: privileges - 用户的操作权限,如SELECT , INSERT , UPDATE 等.如果要授予所的权限则使用ALL.;
databasename - 数据库名,
tablename-表名,如果要授予该用户对所有数据库和表的相应操作权限则可用*表示, 如*.*.
例子: GRANT SELECT, INSERT ON test.user TO 'pig'@'%';
GRANT ALL ON *.* TO 'pig'@'%';
【注意:】用以上命令授权的用户不能给其它用户授权,如果想让该用户可以授权,用以下命令:
GRANT privileges ON databasename.tablename TO 'username'@'host' WITH GRANT OPTION;
* 授权的数据库不要用mysql自带的数据库,否则不起作用。
3、设置与更改用户密码
命令:SET PASSWORD FOR 'username'@'host' = PASSWORD('newpassword');
如果是当前登陆用户用SET PASSWORD = PASSWORD("newpassword");
例子: SET PASSWORD FOR 'pig'@'%' = PASSWORD("123456");
4、撤销用户权限
命令: REVOKE privilege ON databasename.tablename FROM 'username'@'host';
例子: REVOKE SELECT ON *.* FROM 'pig'@'%';
【注意】: 假如你在给用户'pig'@'%'授权的时候是这样的(或类似的):
GRANT SELECT ON test.user TO 'pig'@'%', 则在使用REVOKE SELECT ON *.* FROM 'pig'@'%';命令并不能撤销该用户对test数据库中user表的SELECT 操作.
相反,如果授权使用的是GRANT SELECT ON *.* TO 'pig'@'%';则REVOKE SELECT ON test.user FROM 'pig'@'%';命令也不能撤销该用户对test数据库中user表的Select 权限.
具体信息可以用命令SHOW GRANTS FOR 'pig'@'%'; 查看.
5、删除用户
命令: DROP USER 'username'@'host';
MySQL中支持emoji表情的存储
正常使用uft-8方式存储是不能存储emoji表情文字的,主要原因是utf8编码的一个字符最多3个字节,但是一个emoji表情为4个字节,所以utf8不支持存储emoji表情。
但是utf8的超集utf8mb4一个字符最多能有4字节,所以能支持emoji表情的存储。下面说说具体操作步骤:
1、需要你的mysql数据库版本在5.5以上;
2、更改你的数据库,表,以及需要存储emoji列的编码方式为utf8mb4 ;
# 对每一个数据库:
ALTER DATABASE 数据库名字 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci;
# 对每一个表:
ALTER TABLE 表名字 CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
# 对存储emoji表情的字段:
ALTER TABLE 表名字 CHANGE 字段名字 字段名字 该字段的类型 CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
【注意】:utf8mb4完全向后兼容utf8,无乱码或其他数据丢失的形式出现。理论上是可以放心修改,如果不放心修改,可以备份数据
3、修改my.ini数据库配置【Linux系统中的配置文件为my.cnf,Winows中的配置文件为my.ini】
[client]
default-character-set = utf8mb4
[mysqld]
character-set-client-handshake = FALSE
character-set-server = utf8mb4
collation-server = utf8mb4_unicode_ci
init_connect=’SET NAMES utf8mb4'
[mysql]
default-character-set = utf8mb4
修改完成成,wq保存并退出
4、重启mysql
如果使用 service mysql restart,最后发现这条命令并不管用,重启没有成功,导致后面查看字符集的时候,并没有达到想要的字符集的状态时,可以采用下面的方法才可以正确的重启mysql:
①、停止msql的运行
通过/etc/init.d/mysql执行stop命令
②、启动mysql
通过/etc/init.d/mysql执行start命令
5、检查字符集:
进入mysql中,用
SHOW VARIABLES WHERE Variable_name LIKE 'character\_set\_%' ;
OR
Variable_name LIKE 'collation%'; 命令查看字符集的情况
6、确认mysql驱动、连接串:
①、确保mysql connection版本高于5.1.13,否则仍然不能使用utf8mb4
②、确认服务器端的db配置文件中的字符集是否修改过来?
jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://主机名:端口/数据库?useUnicode=true&characterEncoding=utf8mb4&autoReconnect=true&rewriteBatchedStatements=TRUE
7、带有emoji表情的sql文件的导入与导出(主要为windows中的导出)
①、导出
在进行把后缀名为.sql的文件,且文件数据中包含emoji表情的数据,进行备份导出的时候,此时不要使用第三方软件进行导出,而是使用命令行的形式执行该导出动作,
其主要原因是使用第三方导出该文件时,由于其默认的导出的编码格式为utf-8,该编码格式最多只支持3个字节,而一个emoji表情有4个字节,这将导致emoji表情的数据变成乱码。
所以在本地导出的时候具体操作步骤如下:
* 打开cmd,先找到mysqldump这个执行文件所在的路径【即mysql安装的bin目录】;
* 在路径后输入mysqldump –default-character-set-utf8mb4 –u 用户名 –p 数据库名 > 导出该文件的物理路径,按“Enter”,即可完成导出功能,在导出的物理路径中即可找到已被导出的该文件。
②、导入
* 执行 mysql -u 用户名 -h 主机名 -P 端口号 -p密码 进入mysql数据库;
* 创建要导入sql的数据库 create database 数据库名;
* use 上一步创建号的数据库名;
* source 要导入的sql文件全路径
常见的数据类型
一、数值型:
* 整型:
①、分类:
类型 tinyint、smallint、mediumint、int/integer、bigint
字节数 1 2 3 4 8
②、特点:
1、如果不设置无符号还是有符号,默认是有符号,如果想设置无符号,需要添加unsigned关键字
2、如果插入的数值超出了整型的范围,会报out of range异常,并且插入的是临界值
3、如果不设置长度,会有默认的长度,长度代表了显示结果中该列的最大宽度,如果不够会用0在左边填充,但必须搭配zerofill使用才会使用0在左边填充
【对于整型,它的范围是由前面类型决定的】
4、如果使用了zerofill 关键字,则默认就是无符号的,所以无需添加unsigned 关键字
* 小数:
1、分类
①、 定点数
dec(M,D)
decimal(M,D)
②、浮点数
float(M,D)
double(M,D)
2、特点:
①、M:整数部位+小数部位 一共有M位
D:小数部位的位数
如果超过范围,则插入临界值
②、M和D都可以省略
如果是decimal,则M默认为10,D默认为0
如果是float和double,则会根据插入的数值的精度来决定精度
③、定点型的精确度较高,如果要求插入数值的精度较高,如货币运算等则考虑使用
#原则:
所选择的类型越简单越好,能保存数值的类型越小越好
二、字符型:
1、分类:
较短的文本:char、varchar
其它还有:
binary和varbinary用于保存较短的二进制
enum用于保存枚举
set用于保存集合
较长的文本:text、blob(较长的二进制数据)
举例:
①、枚举:
CREATE TABLE tab_char(
c1 ENUM('a','b','c')
);
INSERT INTO tab_char VALUES('a'); 正确
INSERT INTO tab_char VALUES('b'); 正确
INSERT INTO tab_char VALUES('c'); 正确
INSERT INTO tab_char VALUES('m'); 为空【因为不包含在枚举中,所以为空】
INSERT INTO tab_char VALUES('A'); 正确 【插入的为a,不区分大小写】
②、集合:
CREATE TABLE tab_set(
s1 SET('a','b','c','d')
);
INSERT INTO tab_set VALUES('a,A'); 显示 a 【唯一,不重复】
INSERT INTO tab_set VALUES('d,A,B'); 不区分大小写,显示 a,b,d 【排序】
INSERT INTO tab_set VALUES('g'); 集合中没有,显示空
INSERT INTO tab_set VALUES('b,c,g'); 显示 b,c 【集合中有则显示,没有则不显示】
2、特点:
写法 M的意思 特点 空间的耗费 效率
char char(M) 最大的字符数,可以省略,默认为1 固定长度的字符 比较耗费 高
varchar varchar(M) 最大的字符数,不可以省略 可变长度的字符 比较节省 低
3、说明:char(M) 和 varchar(M) 中的 M 表示可以存储的最大字符数,如果超过了这个数,则会从左边进行截取,截取长度为M。【因为表示的是字符数,所以一个汉字,一个字母都算一个字符】
三、日期型:
1、分类:
date(4个字节):只保存日期
time (3个字节):只保存时间
year(1个字节):只保存年
datetime:保存日期+时间
timestamp:保存日期+时间
2、特点:
字节 范围 时区等的影响
datetime 8 1000——9999 不受
timestamp 4 1970-2038 受
示例:
查看时区:
SHOW VARIABLES LIKE 'time_zone';
设置时区:
SET time_zone='+9:00';
常见约束
一、含义:一种限制,用于限制表中的数据,为了保证表中的数据的准确和可靠性
二、分类:六大约束
1、NOT NULL:非空,用于保证该字段的值不能为空
比如姓名、学号等
2、DEFAULT: 默认,用于保证该字段有默认值
比如性别
3、PRIMARY KEY: 主键,用于保证该字段的值具有唯一性,并且非空
比如学号、员工编号等
4、UNIQUE: 唯一,用于保证该字段的值具有唯一性,可以为空
比如座位号
5、CHECK: 检查约束【mysql中不支持,即添加上不报错,但是没有效果】
比如年龄、性别
6、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 UNIQUE, #唯一
age INT DEFAULT 18, #默认约束
majorId INT REFERENCES major(id) #外键
);
CREATE TABLE major(
id INT PRIMARY KEY,
majorName VARCHAR(20)
);
#查看stuinfo中的所有索引,包括主键、外键、唯一以及自己创建的索引
SHOW INDEX FROM stuinfo;
2、表级约束:
语法上不支持非空、默认,其他的都支持,但是检查语法支持,实际添加上也没有作用
①、语法:在各个字段的最下面添加 【constraint 约束名】 约束类型(字段名)
CREATE TABLE stuinfo(
id INT,
stuname VARCHAR(20),
gender CHAR(1),
seat INT,
age INT,
majorid INT,
CONSTRAINT pk PRIMARY KEY(id), #主键
# 【1、对于主键,就算起了名字pk,也是没有效果的,因为mysql默认主键的名字为primary
# 2、列级约束是没有办法给约束起名字的,只有表级约束才可以】
CONSTRAINT uq UNIQUE(seat), #唯一键
CONSTRAINT ck CHECK(gender ='男' OR gender = '女'), #检查
CONSTRAINT fk_stuinfo_major FOREIGN KEY(majorid) REFERENCES major(id) #外键
);
#通用的写法:
CREATE TABLE IF NOT EXISTS stuinfo(
id INT PRIMARY KEY, #主键
stuname VARCHAR(20) NOT NULL, #非空
sex CHAR(1),
age INT DEFAULT 18, #默认约束
seat INT UNIQUE, #唯一键
majorid INT,
CONSTRAINT fk_stuinfo_major FOREIGN KEY(majorid) REFERENCES major(id) #外键
);
#【注意】
支持类型 可以起约束名
列级约束 除了外键 不可以
表级约束 除了非空和默认 可以
五、主键和唯一的大对比:
保证唯一性 是否允许为空 一个表中可以有多少个 是否允许组合
主键 √ × 至多有1个 √,但不推荐
唯一 √ √ 可以有多个 √,但不推荐
【注意】
①、因为主键和唯一是保证唯一性的,所以设置了主键和唯一约束的字段值只能有一个,不能重复,包括null值,也只允许出现一个;
②、主键和唯一约束都允许组合使用,意思是可以设置多个字段组合为主键,如果设置了之后,只有设置的多个字段同时值相同才会看作是重复,才会起作用,单个字段是可以重复的,但是不可以为空
CONSTRAINT pk PRIMARY KEY(id, stuname...), #主键
CONSTRAINT uq UNIQUE(seat, seat2,....), #唯一键
六、外键:
1、要求在从表设置外键关系
2、从表的外键列的类型和主表的关联列的类型要求一致或兼容,名称无要求
3、主表的关联列必须是一个key(一般是主键或唯一)
4、插入数据时,先插入主表,再插入从表
删除数据时,先删除从表,再删除主表
5、一个字段可以设置多个约束类型,中间用空格隔开
例如:stuname VARCHAR(20) NOT NULL UNIQUE ... , #非空 #唯一 ...
# 可以通过以下两种方式删除主表的记录:
方式一:级联删除
ALTER TABLE 表名 ADD constraint 外键约束名 foreign key(从表字段) references 主表(字段) ON DELETE CASCADE;
方式二:级联置空
ALTER TABLE 表名 ADD constraint 外键约束名 foreign key(从表字段) references 主表(字段) ON DELETE set null;
七、修改表时添加约束
1、添加列级约束
alter table 表名 modify column 字段名 字段类型 新约束;
2、添加表级约束
alter table 表名 add 【constraint 约束名】 约束类型(字段名) 【外键的引用】;
举例:
#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);
#5.添加外键
ALTER TABLE stuinfo ADD CONSTRAINT fk_stuinfo_major FOREIGN KEY(majorid) REFERENCES major(id);
八、修改表时删除约束
#1.删除非空约束
ALTER TABLE stuinfo MODIFY COLUMN 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 fk_stuinfo_major;
位置 支持的约束类型 (检查约束除外) 是否可以起约束名
列级约束: 列的后面 语法都支持,但外键没有效果 不可以
表级约束: 所有列的下面 默认和非空不支持,其他支持 可以(主键没有效果)
标识列 [AUTO_INCREMENT]
1、标识列:又称为自增长列, 可以不用手动的插入值, 系统提供默认的序列值, 初始默认值为1, 即从1开始自增
2、特点:
①、标识列必须和主键搭配吗? 不一定,但要求是一个key
②、一个表可以有几个标识列? 至多一个!
③、标识列的类型只能是数值型(整型、浮点型)
④、标识列可以通过 SET auto_increment_increment=3;设置步长
MySQL 不可以通过: SET auto_increment_offset=3; 修改起始值,即使设置了,也不会有效果,但是可以通过 手动插入值,设置起始值【第一条数据可以手动插入你想要的起始值,后面无需再添加,就会自动从你插入的起始值自增】
#查看自增长列相关的设置【有起始值和步长,默认都是1】
SHOW VARIABLES LIKE '%auto_increment%';
3、修改表时设置自增长列
ALTER TABLE 表名 MODIFY COLUMN 字段名 字段类型 约束 AUTO_INCREMENT;
删除自增长列
ALTER TABLE 表名 MODIFY COLUMN 字段名 字段类型 ;
事务
1、TCL语言:Transaction Control Language 事务控制语言
2、事务:一个或一组sql语句组成一个执行单元,这个执行单元要么全部执行,要么全部不执行。
案例:转账
3、事务的特性:ACID
原子性:一个事务不可再分割,要么都执行要么都不执行
一致性:一个事务执行会使数据从一个一致状态切换到另外一个一致状态
隔离性:一个事务的执行不受其他事务的干扰
持久性:一个事务一旦提交,则会永久的改变数据库的数据.
4、事务的创建
①、隐式事务:事务没有明显的开启和结束的标记
比如insert、update、delete语句
②、显式事务:事务具有明显的开启和结束的标记
前提:必须先设置自动提交功能为禁用 set autocommit=0;
查看变量: SHOW VARIABLES LIKE 'autocommit'; MySQL默认为ON,开启自动提交(即隐式事务)
5、使用事务的步骤:
步骤1:开启事务
set autocommit=0;
start transaction;可选的
步骤2:编写事务中的sql语句(select insert update delete)
语句1;
语句2;
...
步骤3:结束事务
commit;提交事务
rollback;回滚事务
6、事务的隔离级别:
对于同时运行的多个事务, 当这些事务访问数据库中相同的数据时, 如果没有采取必要的隔离机制, 就会导致各种并发问题:
脏读: 对于两个事务 T1, T2, T1 读取了已经被 T2 更新但还没有被提交的字段之后, 若 T2 回滚, T1读取的内容就是临时且无效的.
不可重复读: 对于两个事务T1, T2, T1 读取了一个字段, 然后 T2 更新了该字段. 之后, T1再次读取同一个字段, 值就不同了.
幻读: 对于两个事务T1, T2, T1 从一个表中读取了一个字段, 然后 T2 在该表中插入了一些新的行. 之后, 如果 T1 再次读取同一个表, 就会多出几行
脏读 不可重复读 幻读
read uncommitted: √ √ √
read committed: × √ √
repeatable read: × × √
serializable: × × ×
①、 Mysql 支持 4 种事务隔离级别.mysql中默认的隔离级别是 repeatable read
Oracle 支持2 种事务隔离级别:READ COMMITED, SERIALIZABLE。默认的隔离级别是 read committed
②、查看隔离级别
select @@tx_isolation;
③、设置当前MYSQL的连接 / 数据库系统的全局 隔离级别
set session|global transaction isolation level 隔离级别;
7、savepoint 节点名:设置保存点, 只能搭配rollback 使用
示例:只删除了id为25的,id为28的回滚了,没有删除成功
SET autocommit=0;
START TRANSACTION;
DELETE FROM account WHERE id=25;
SAVEPOINT a; #设置保存点
DELETE FROM account WHERE id=28;
ROLLBACK TO a; #回滚到保存点
视图
一、含义:mysql5.1版本出现的新特性,一种虚拟存在的表,行和列的数据来自定义视图的查询中使用的表,并且是在使用视图时动态生成的,
只保存了sql逻辑,不保存查询结果
* 应用场景:
– 多个地方用到同样的查询结果
– 该查询结果使用的sql语句较复杂
* 使用视图的好处:
• 重用sql语句
• 简化复杂的sql操作,不必知道它的查询细节
• 保护数据,提高安全性
二、视图与表的对比:
创建语法的关键字 是否实际占用物理空间 使用
视图 create view 只是保存了sql逻辑 增删改查,只是一般不能增删改,主要用于查
表 create table 保存了数据 增删改查
三、创建视图
1、语法:
create view 视图名
as
查询语句;
案例:#1、查询各部门的平均工资级别
#①创建视图查看每个部门的平均工资
CREATE VIEW myv2
AS
SELECT AVG(salary) ag,department_id
FROM employees
GROUP BY department_id;
#②使用
SELECT myv2.`ag`,g.grade_level
FROM myv2
JOIN job_grades g
ON myv2.`ag` BETWEEN g.`lowest_sal` AND g.`highest_sal`;
#2、查询平均工资最低的部门名和工资
CREATE VIEW myv3
AS
SELECT * FROM myv2 ORDER BY ag LIMIT 1;
SELECT d.*,m.ag
FROM myv3 m
JOIN departments d
ON m.`department_id`=d.`department_id`;
四、修改视图
方式一:
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
查询语句;
示例: ALTER VIEW myv3
AS
SELECT * FROM employees;
五、删除视图
语法:drop view 视图名,视图名,...;
DROP VIEW emp_v1,emp_v2,myv3;
六、查看视图结构
DESC myv3;
SHOW CREATE VIEW myv3; #可以查看更加详细的信息,如创建的语句,字符集等
七、视图的更新
1.插入
INSERT INTO myv1 VALUES('张飞','zf@qq.com');
2.修改
UPDATE myv1 SET last_name = '张无忌' WHERE last_name='张飞';
3.删除
DELETE FROM myv1 WHERE last_name = '张无忌';
#具备以下特点的视图不允许更新
①包含以下关键字的sql语句:分组函数、distinct、group by、having、union或者union all
②常量视图
CREATE OR REPLACE VIEW myv2
AS
SELECT 'john' NAME;
#查看
SELECT * FROM myv2;
#更新
UPDATE myv2 SET NAME='lucy'; #不能更新
③Select中包含子查询
④join
⑤from一个不能更新的视图
CREATE OR REPLACE VIEW myv5
AS
SELECT * FROM myv3; #myv3视图不能更新
⑥where子句的子查询引用了from子句中的表
CREATE OR REPLACE VIEW myv6
AS
SELECT last_name,email,salary
FROM employees
WHERE employee_id IN(
SELECT manager_id
FROM employees
WHERE manager_id IS NOT NULL
);
变量
一、分类:
* 系统变量:
全局变量
会话变量
* 自定义变量:
用户变量
局部变量
二、系统变量
说明:变量由系统定义,不是用户定义,属于服务器层面
注意:全局变量需要添加global关键字,会话变量需要添加session关键字,如果不写,默认会话级别
①、使用步骤:
1、查看所有系统变量
show global|【session】variables;
2、查看满足条件的部分系统变量
show global|【session】 variables like '%char%';
3、查看指定的系统变量的值
select @@global.系统变量名; --->全局的
select @@系统变量名; --->会话的
4、为某个系统变量赋值
方式一:
set global|【session】 系统变量名 = 值;
方式二:
set @@global|session.系统变量名 = 值;
、全局变量
作用域:针对于所有会话(连接)有效,但不能跨重启
①、查看所有全局变量
SHOW GLOBAL VARIABLES;
②、查看满足条件的部分系统变量
SHOW GLOBAL VARIABLES LIKE '%char%';
③、查看指定的系统变量的值
SELECT @@global.autocommit;
④、为某个系统变量赋值
SET @@global.autocommit=0; 或 SET GLOBAL autocommit=0;
、会话变量
作用域:针对于当前会话(连接)有效
①、查看所有会话变量
SHOW SESSION VARIABLES;
②、查看满足条件的部分会话变量
SHOW SESSION VARIABLES LIKE '%char%';
③、查看指定的会话变量的值
SELECT @@autocommit; 或 SELECT @@session.tx_isolation;
④、为某个会话变量赋值
SET @@session.tx_isolation='read-uncommitted'; 或 SET SESSION tx_isolation='read-committed';
三、自定义变量
说明:变量由用户自定义,而不是系统提供的
①、使用步骤:
1、声明
2、赋值
3、使用(查看、比较、运算等)
、用户变量
1、作用域:针对于当前会话(连接)有效,作用域同于会话变量,可以放在任何地方【begin end里面或者外面都可以】。
2、使用步骤:【赋值操作符: = 或 :=】
①声明并初始化
SET @变量名=值;
SET @变量名:=值;
SELECT @变量名:=值;
②赋值(更新变量的值)
#方式一:通过set 或 select
SET @变量名=值;
SET @变量名:=值;
SELECT @变量名:=值;
#方式二:通过select into
SELECT 字段 INTO @变量名
FROM 表;
③使用(查看变量的值)
SELECT @变量名;
、局部变量
1、作用域:仅仅在定义它的begin end块中有效, 必须应用在 begin end中的第一句话
2、使用步骤:
①声明
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中的第一句话 一般不用加@,需要指定类型
存储过程和函数
一、存储过程和函数:类似于java中的方法
二、好处:
1、提高代码的重用性
2、简化操作
、存储过程
一、含义:一组预先编译好的SQL语句的集合,理解成批处理语句
二、好处:
1、提高代码的重用性
2、简化操作
3、减少了编译次数并且减少了和数据库服务器的连接次数,提高了效率
三、创建语法
CREATE PROCEDURE 存储过程名(参数列表)
BEGIN
存储过程体(一组合法的SQL语句)
END
#注意:
1、参数列表包含三部分:参数模式 参数名 参数类型
举例:
in stuname varchar(20)
参数模式:
in:该参数可以作为输入,也就是该参数需要调用方传入值
out:该参数可以作为输出,也就是该参数可以作为返回值
inout:该参数既可以作为输入又可以作为输出,也就是该参数既需要传入值,又可以返回值
2、如果存储过程体仅仅只有一句话,begin end可以省略
存储过程体中的每条sql语句的结尾要求必须加分号。
存储过程的结尾可以使用 delimiter 重新设置
语法:
delimiter 结束标记
案例:
delimiter $
四、调用语法
CALL 存储过程名(实参列表);
#--------------------------------案例演示-----------------------------------
* 1、空参列表
#案例:插入到admin表中五条记录
DELIMITER $
CREATE PROCEDURE myp1()
BEGIN
INSERT INTO admin(username,`password`)
VALUES('john1','0000'),('lily','0000'),('rose','0000'),('jack','0000'),('tom','0000');
END $
#调用
CALL myp1()$
* 2、创建带in模式参数的存储过程
#案例1:创建存储过程实现 根据女神名,查询对应的男神信息
CREATE PROCEDURE myp2(IN beautyName VARCHAR(20))
BEGIN
SELECT bo.*
FROM boys bo
RIGHT JOIN beauty b ON bo.id = b.boyfriend_id
WHERE b.name=beautyName;
END $
#调用
CALL myp2('柳岩')$
#案例2 :创建存储过程实现,用户是否登录成功
CREATE PROCEDURE myp4(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、创建out 模式参数的存储过程
#案例1:根据输入的女神名,返回对应的男神名
CREATE PROCEDURE myp6(IN beautyName VARCHAR(20),OUT boyName VARCHAR(20))
BEGIN
SELECT bo.boyname INTO boyname
FROM boys bo
RIGHT JOIN
beauty b ON b.boyfriend_id = bo.id
WHERE b.name=beautyName ;
END $
#案例2:根据输入的女神名,返回对应的男神名和魅力值
CREATE PROCEDURE myp7(IN beautyName VARCHAR(20),OUT boyName VARCHAR(20),OUT usercp INT)
BEGIN
SELECT boys.boyname ,boys.usercp INTO boyname,usercp
FROM boys
RIGHT JOIN
beauty b ON b.boyfriend_id = boys.id
WHERE b.name=beautyName ;
END $
#调用
CALL myp7('小昭',@name,@cp)$
SELECT @name,@cp$
* 4、创建带inout模式参数的存储过程
#案例1:传入a和b两个值,最终a和b都翻倍并返回
CREATE PROCEDURE myp8(INOUT a INT ,INOUT b INT)
BEGIN
SET a=a*2;
SET b=b*2;
END $
#调用
SET @m=10$
SET @n=20$
CALL myp8(@m,@n)$
SELECT @m,@n$
、总结:
①、空参列表:调用方法 ---> call 存储过程名() 结束符
例如: CALL myp3()$
②、带in模式参数的存储过程:调用方法 ---> call 存储过程名(直接输入需要的参数) 结束符
例如: CALL myp3('张飞','8888')$
③、带out 模式参数的存储过程:调用方法 ---> call 存储过程名(自定义用户变量) 结束符
例如: CALL myp7('小昭',@name,@cp)$ ----> 调用
SELECT @name,@cp$ ---->查看
④、带inout模式参数的存储过程:调用方法 ---> call 存储过程名(定义用户变量并赋值) 结束符
例如: SET @m=10$ ----> 定义用户变量并赋值
SET @n=20$ ----> 定义用户变量并赋值
CALL myp8(@m,@n)$ ----> 调用
SELECT @m,@n$ ---->查看
五、删除存储过程
语法:drop procedure 存储过程名
示例: DROP PROCEDURE p1;
DROP PROCEDURE p2,p3; #这种写法错误,一次只可以删除一个存储过程
六、查看存储过程的信息
DESC myp2; #这种写法错误,不可以使用desc 查看
SHOW CREATE PROCEDURE myp2;
、函数
一、含义:一组预先编译好的SQL语句的集合,理解成批处理语句
二、好处:
1、提高代码的重用性
2、简化操作
3、减少了编译次数并且减少了和数据库服务器的连接次数,提高了效率
三、区别:
存储过程:可以有0个返回,也可以有多个返回,适合做批量插入、批量更新
函数:有且仅有1 个返回,适合做处理数据后返回一个结果
四、创建语法
CREATE FUNCTION 函数名(参数列表) RETURNS 返回类型
BEGIN
函数体
END
#注意:
1.参数列表包含两部分:
参数名 参数类型
2.函数体:肯定会有return语句,如果没有会报错
如果return语句没有放在函数体的最后也不报错,但不建议
写法:return 值;
3.函数体中仅有一句话,则可以省略begin end
4.使用 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、有参有返回
#案例1:根据员工名,返回它的工资
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') $
#案例2:根据部门名,返回该部门的平均工资
CREATE FUNCTION myf3(deptName VARCHAR(20)) RETURNS DOUBLE
BEGIN
DECLARE sal DOUBLE ; #定义局部变量
SELECT AVG(salary) INTO sal
FROM employees e
JOIN departments d ON e.department_id = d.department_id
WHERE d.department_name=deptName;
RETURN sal;
END $
SELECT myf3('IT')$
六、查看函数
SHOW CREATE FUNCTION myf3;
七、删除函数
DROP FUNCTION myf3;
#案例
#一、创建函数,实现传入两个float,返回二者之和
CREATE FUNCTION test_fun1(num1 FLOAT,num2 FLOAT) RETURNS FLOAT
BEGIN
DECLARE SUM FLOAT DEFAULT 0;
SET SUM=num1+num2;
RETURN SUM;
END $
SELECT test_fun1(1,2)$
流程控制结构 【顺序、分支、循环】
流程控制结构
顺序结构:程序从上往下依次执行
分支结构:程序从两条或多条路径中选择一条去执行
循环结构:程序在满足一定条件的基础上,重复执行一段代码
一、分支结构
1、IF 函数
①、功能:实现简单的双分支
②、语法:
if(表达式1,表达式2,表达式3)
执行顺序:
如果表达式1成立,则if 函数返回表达式2的值,否则返回表达式3的值
③、应用:
任何地方(可以放在begin end 中,也可以放在begin end 外)
2.case结构
①、情况1:类似于Java中的switch语句,一般用于实现等值判断
语法:
如果作为表达式使用,则语法如下: 【注意:此情况下,可以放在begin end 中,也可以放在begin end 外】
case 变量|表达式|字段
when 要判断的值1 then 返回的值1
when 要判断的值2 then 返回的值2
...
else 要返回的值n
end;
如果作为独立的语句执行,则语法如下: 【注意:此情况下,只可以放在begin end 中】
case 变量|表达式|字段
when 要判断的值1 then 语句1;
when 要判断的值2 then 语句2;
...
else 要返回的语句n;
end case;
②、情况2:类似于Java中的多重if语句,一般用于实现区间判断
语法:
如果作为表达式使用,则语法如下: 【注意:此情况下,可以放在begin end 中,也可以放在begin end 外】
case
when 要判断的条件1 then 返回的值1
when 要判断的条件2 then 返回的值2
...
else 要返回的值n
end;
如果作为独立的语句执行,则语法如下: 【注意:此情况下,只可以放在begin end 中】
case
when 要判断的条件1 then 语句1;
when 要判断的条件2 then 语句2;
...
else 要返回的语句n;
end case;
特点:
①、可以作为表达式,嵌套在其它语句中使用,可以放在任何地方,begin end 中或begin end 的外面
可以作为独立的语句使用,只能放在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(90)$
3.if结构
①、语法:
if 条件1 then 语句1;
elseif 条件2 then 语句2;
....
else 语句n; 【注意,else 语句可以省略】
end if;
②、功能:类似于多重if
③、应用场景:只能应用在begin end 中
#案例1:创建函数,实现传入成绩,如果成绩>90,返回A,如果成绩>80,返回B,如果成绩>60,返回C,否则返回D
CREATE FUNCTION test_if(score FLOAT) RETURNS CHAR
BEGIN
DECLARE ch CHAR DEFAULT 'A';
IF score>90 THEN SET ch='A';
ELSEIF score>80 THEN SET ch='B';
ELSEIF score>60 THEN SET ch='C';
ELSE SET ch='D';
END IF;
RETURN ch;
END $
SELECT test_if(87)$
#案例2:创建存储过程,如果工资<2000,则删除,如果5000>工资>2000,则涨工资1000,否则涨工资500
CREATE PROCEDURE test_if_pro(IN sal DOUBLE)
BEGIN
IF sal<2000 THEN DELETE FROM employees WHERE employees.salary=sal;
ELSEIF sal>=2000 AND sal<5000 THEN UPDATE employees SET salary=salary+1000 WHERE employees.`salary`=sal;
ELSE UPDATE employees SET salary=salary+500 WHERE employees.`salary`=sal;
END IF;
END $
CALL test_if_pro(2100)$
#案例1:创建函数,实现传入成绩,如果成绩>90,返回A,如果成绩>80,返回B,如果成绩>60,返回C,否则返回D
CREATE FUNCTION test_case(score FLOAT) RETURNS CHAR
BEGIN
DECLARE ch CHAR DEFAULT 'A';
CASE
WHEN score>90 THEN SET ch='A';
WHEN score>80 THEN SET ch='B';
WHEN score>60 THEN SET ch='C';
LSE SET ch='D';
END CASE;
RETURN ch;
END $
SELECT test_case(56)$
二、循环结构
分类:
while、loop、repeat
循环控制:
iterate类似于 continue,继续,结束本次循环,继续下一次
leave 类似于 break,跳出,结束当前所在的循环
1、while
①、语法:
【标签:】while 循环条件 do
循环体;
end while【 标签】;
②、特点:先判断后执行
③、位置:begin end 中
2、loop
①、 语法:
【标签:】loop
循环体;
end loop 【标签】;
②、特点:没有条件的死循环(可以模拟简单的死循环)
③、位置:begin end 中
3、repeat
①、 语法:
【标签:】repeat
循环体;
until 结束循环的条件
end repeat 【标签】;
②、特点:先执行后判断
③、位置:begin end 中
#1.没有添加循环控制语句
#案例:批量插入,根据次数插入到admin表中多条记录
DROP PROCEDURE pro_while1$
CREATE PROCEDURE pro_while1(IN insertCount INT)
BEGIN
DECLARE i INT DEFAULT 1;
WHILE i<=insertCount DO
INSERT INTO admin(username,`password`) VALUES(CONCAT('Rose',i),'666');
SET i=i+1;
END WHILE;
END $
CALL pro_while1(100)$
/*
int i=1;
while(i<=insertcount){
//插入
i++;
}
*/
#2.添加leave语句
#案例:批量插入,根据次数插入到admin表中多条记录,如果次数>20则停止
TRUNCATE TABLE admin$
DROP PROCEDURE test_while1$
CREATE PROCEDURE test_while1(IN insertCount INT)
BEGIN
DECLARE i INT DEFAULT 1;
a:WHILE i<=insertCount DO
INSERT INTO admin(username,`password`) VALUES(CONCAT('xiaohua',i),'0000');
IF i>=20 THEN LEAVE a;
END IF;
SET i=i+1;
END WHILE a;
END $
CALL test_while1(100)$
#3.添加iterate语句
#案例:批量插入,根据次数插入到admin表中多条记录,只插入偶数次
TRUNCATE TABLE admin$
DROP PROCEDURE test_while1$
CREATE PROCEDURE test_while1(IN insertCount INT)
BEGIN
DECLARE i INT DEFAULT 0;
a:WHILE i<=insertCount DO
SET i=i+1;
IF MOD(i,2)!=0 THEN ITERATE a;
END IF;
INSERT INTO admin(username,`password`) VALUES(CONCAT('xiaohua',i),'0000');
END WHILE a;
END $
CALL test_while1(100)$
/*
int i=0;
while(i<=insertCount){
i++;
if(i%2==0){
continue;
}
插入
}
*/
流程控制经典案例:
一、已知表stringcontent
其中字段:
id 自增长
content varchar(20)
向该表插入指定个数的,随机的字符串
DROP TABLE IF EXISTS stringcontent;
CREATE TABLE stringcontent(
id INT PRIMARY KEY AUTO_INCREMENT,
content VARCHAR(20)
);
DELIMITER $
CREATE PROCEDURE test_randstr_insert(IN insertCount INT)
BEGIN
DECLARE i INT DEFAULT 1;
DECLARE str VARCHAR(26) DEFAULT 'abcdefghijklmnopqrstuvwxyz';
DECLARE startIndex INT; #代表初始索引
DECLARE len INT; #代表截取的字符长度
WHILE i<=insertcount DO
SET startIndex=FLOOR(RAND()*26+1); #代表初始索引,随机范围1-26
SET len=FLOOR(RAND()*(20-startIndex+1)+1); #代表截取长度,随机范围1-(26-startIndex+1) 【 content 要求长度为20,所以26取不到,因此最终结果:1 -(20-startIndex+1)】
INSERT INTO stringcontent(content) VALUES(SUBSTR(str,startIndex,len));
SET i=i+1;
END WHILE;
END $
CALL test_randstr_insert(10)$