Mysql入门学习笔记,包含简单查询、常用函数、分组查询、多表查询、(嵌套)子查询、分页查询、联合查询、表中数据的增删改(DML)、表和库的增删改(DDL)、数据类型、常见约束、标识列、事务(TCL)与视图、变量、存储过程、函数和流程控制等相关内容。

根据b站上视频整理,作为入门级的资料,带有案例库和练习原码,方便实际操练,与大家交流学习。

b站视频网址:https://www.bilibili.com/video/BV12b411K7Zu?from=search&seid=8595952504919475801

一、简单查询

show databases;#查看所有库
use myemployees;#调用myemployees库#  基础查询  select命令 select...from...
SELECT last_name FROM employees;
SELECT last_name,salary,email FROM employees;
SELECT `department_name`,`department_name` FROM departments; #查询效果
SELECT 100;
SELECT 'join'; #打印效果
SELECT 100*99;
SELECT 100%99;  #求余数
SELECT VERSION(); #查询版本函数
DESC departments; #desc 描述表# 字段起别名
SELECT 100*99 AS 结果;  # as或用空格 起别名
SELECT last_name AS 姓,first_name AS 名 FROM employees;
SELECT last_name 姓,first_name 名 FROM employees;
SELECT salary AS 'out put' FROM `employees`;# distinct 去重
SELECT DISTINCT department_id FROM `employees`;#  加号的作用:仅为运算符
SELECT 100+999 结果;
SELECT 'join'+99 打印;
SELECT NULL+99 结果;  # 只要有一方为null,结果为null# concat()拼接函数,+号无法拼接
SELECT `last_name`+`first_name` 姓名 FROM employees;
SELECT CONCAT(`last_name`,',',`first_name`) 姓名 FROM employees; # 用逗号隔开
# ifnull()函数 如果为null,作为0,否则正常
SELECT IFNULL(`commission_pct`,0) AS 奖金率,commission_pct
FROMemployees;#  条件查询  select...from...where...
/* where后面的筛选条件有:条件运算符: > < = <> != >= <=逻辑运算符: and or not模糊查询:   like between andinis null
*/
# 一、条件运算符
#  查询工资大于12000的员工信息
SELECT * FROM employees WHERE salary>12000;
#  查询部门编号≠90的员工姓名和部门编号
SELECT CONCAT(`first_name`,`last_name`),`department_id`
FROM employees
WHERE `department_id`<>90;
#  二、逻辑运算符
#  查询工资在10000到20000之间的员工名、工资以及奖金
SELECT `last_name`,`salary`,`commission_pct`
FROMemployees
WHERE`salary`>10000 AND 20000;
#  查询部门编号不在90到110之间,或者工资高于15000的员工
SELECT`last_name`
FROMemployees
WHERENOT(`department_id`>=90 AND `department_id`<=110) OR (`salary`>15000);
#  三、模糊查询
#  查询员工名中包含字符a的员工信息
SELECT * FROM employees WHERE `last_name` LIKE '%a%';
#  查询员工名中第三个字符为c,第五个字符为a的员工信息
SELECT *
FROM employees
WHERE last_name LIKE '__c_a%';
#  查询员工名中第二个字符为_的员工信息
SELECT *
FROM employees
WHERE last_name LIKE '_\_%';
# 查询员工编号在100到120内的员工信息
SELECT *
FROM employees
WHERE employee_id BETWEEN 100 AND 120; # between...and...顺序不能颠倒
# 查询工作种类是PU_CLERK和ST_MAN的员工信息
SELECT *
FROM employees
WHERE job_id IN ('PU_CLERK','ST_MAN');
# 查询奖金为null的员工名和奖金
SELECT last_name,commission_pct
FROM employees
WHERE commission_pct  IS NULL;
# 安全等于 <=>
SELECT last_name,commission_pct
FROM employees
WHERE commission_pct  <=> NULL;# 排序查询
/* select 查询列表(3)
from 表(1)
where 筛选条件(2)
order by 排序列表 [asc/desc](4)
*/
SELECT * FROM employees ORDER BY salary DESC; # desc降序
SELECT * FROM employees ORDER BY salary ASC;  # asc升序
#  按年薪将序
SELECT * ,salary*12*(1+IFNULL(commission_pct,0)) 年薪
FROM employees
ORDER BY 年薪 DESC;
#  按函数排序
SELECT LENGTH(last_name) 字节长度,last_name,salary
FROM employees
ORDER BY LENGTH(last_name) DESC;
#  多个字段排序
SELECT *
FROM employees
ORDER BY salary ASC,employee_id DESC;#----------------------------------------------------------------------

二、常用函数

/* 1.单行函数:length,concat,ifnull,isnull (传入一个值传出一个值)2.分组函数:做统计使用(传入多个值传出一个值,如求均值) */
#-------------------------------单行函数-----------------------------------
# 一、常见函数
# length 长度
SELECT LENGTH('aa'); #2
SELECT LENGTH('对a');#3+1=4
SHOW VARIABLES LIKE '%char%';
# concat 拼接
SELECT CONCAT(last_name,'_',first_name) 姓名
FROM employees;
# upper、lower 大小写
SELECT UPPER('john');#JOHN
SELECT LOWER('joHn');#john
SELECT # 姓大写,名小写,两者拼接CONCAT(UPPER(last_name),'_',LOWER(first_name)) 姓名
FROM employees;
# substr 字符串截取
#截取从指定索引处后所有的字符
SELECT SUBSTRING('李莫愁爱上了陆展元',7) output;#陆展元
#截取从指定索引处后指定长度的字符,注意,都是字符,而不是字节
SELECT SUBSTRING('李莫愁爱上了陆展元',1,3) output;#李莫愁
# instr 返回子串第一次出现的索引,如果找不到,返回0
SELECT INSTR('杨不殷爱上殷六侠','殷六侠') AS output;
# trim 删除两端指定字符
SELECT TRIM("   zhang   ") AS output; #删除两端空格
SELECT TRIM('a' FROM "aaaaazhang aaa") AS output; #删除两端指定值a
# lpad 用指定字符实现左填充指定长度
SELECT LPAD('殷素数',10,'*') AS output; #长度不足,左填充
SELECT LPAD('殷素数',2,'*') AS output;  #长度超过,截取
# rpad 用指定字符实现右填充指定长度
SELECT RPAD('殷素数',10,'*') AS output; #长度不足,右填充
SELECT RPAD('殷素数',2,'*') AS output;  #长度超过,截取
# replace 替换
SELECT REPLACE("张无忌爱上周芷若,周芷若",'周芷若','赵敏');# 二、数学函数
# round 四舍五入
SELECT ROUND(-1.50);# -2
SELECT ROUND(1.567,2);# 指定取两位小数
# ceil 向上取整
SELECT CEIL(1.0);#1
SELECT CEIL(1.2);#2
SELECT CEIL(-1.2);#-1
# floor 向下取整
SELECT FLOOR(9.9);#9
SELECT FLOOR(-9.9);#-10
SELECT CEIL(1.0);#1
# truncate 截断
SELECT TRUNCATE(1.999,1);# 小数点后保留1位(不进行四舍五入)
# mod 取余数
SELECT MOD(10,3); # 10/3余数为1
# rand 随机数
SELECT RAND(); 区间取0不取1 [0,1)# 三、日期函数
SELECT NOW(); #日期+时间
SELECT CURDATE(); # 只有日期
SELECT CURTIME(); # 只有时间
# 获取指定部分年,月,日,小时,分钟,秒
SELECT YEAR(NOW());#年
SELECT YEAR(hiredate) 年 FROM employees; # 表中的年
SELECT MONTH(NOW());# 月
SELECT MONTHNAME(NOW()); # 英文显示月份
SELECT DAY(NOW());# 日
SELECT HOUR(NOW());# 小时
SELECT MINUTE(NOW());# 分钟
SELECT SECOND(NOW());# 秒
# str_to_date 将字符串转化为时间
SELECT STR_TO_DATE('1998-3-2','%Y-%c-%d') AS output; # Y四位数年,c月,d日
SELECT * FROM employees WHERE hiredate=STR_TO_DATE('4-3 1992','%c-%d %Y');
# date_format 将时间转化为字符串
SELECT DATE_FORMAT(NOW(),'%y年%m月%d日') AS output;# y二位数年,m月,d日
SELECT last_name,DATE_FORMAT(hiredate,'%m月/%d日 %y年') 入职日期
FROM employees
WHERE commission_pct IS NOT NULL;# 四、其他函数
SELECT VERSION(); # 显示当前系统版本
SELECT DATABASE(); # 显示当前数据库
SELECT USER(); # 显示当前用户#五、流程控制函数
# if函数 :if else效果
SELECT IF(10>5,'大','小');
SELECT `last_name`,IF(`commission_pct` IS NULL,'没奖金','有奖金') FROM employees;
# case函数     (判断的字段在case后)
/* 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;
# case 做多重if使用 (判断的字段在when后)
/* case when 条件1 then 要显示的值1或语句1when 条件2 then 要显示的值2或语句2...else 要显示的值n或语句n end   */
/* 案例 : 查询员工的工资情况如果工资>20000,显示A级别如果工资>15000,显示B级别如果工资>10000,显示C级别否则,显示D级别 */
SELECT `last_name`,`salary`,
CASE
WHEN salary>20000 THEN 'A级别'
WHEN salary>15000 THEN 'B级别'
WHEN salary>10000 THEN 'C级别'
ELSE 'D级别'
END AS 工资级别
FROM employees;
#--------------------------------练习练习练习---------------------------------------------
# 显示系统时间(日期+时间)
SELECT NOW();
# 查询员工号、姓名、工资以及工资提高百分之20%后的结果
SELECT `employee_id`,`last_name`,`salary`,`salary`*1.2 新工资 FROM employees;
# 将员工的姓名按首字母排序,并写出姓名长度
SELECT LENGTH(last_name) 长度, SUBSTR(`last_name`,1,1) 首字符
FROM employees
ORDER BY SUBSTR(`last_name`,1,1);
#  使用case-when
SELECT job_id,
CASE job_id
WHEN 'AD_PRES' THEN 'A'
WHEN 'ST_MAN' THEN 'B'
WHEN 'IT_PROG' THEN 'C'
ELSE job_id
END
FROM employees;
#-----------------------------------分组函数---------------------------------------------
# 简单使用
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; # 计数
/* 1、sum、avg一般用于处理数值型 (不计算null值)2、min、max、count支持任何类型 3、和分组函数一同查询的字段要求是group by后的字段  */
# 和distinct搭配
SELECT SUM(DISTINCT salary),SUM(salary) FROM employees;
SELECT COUNT(DISTINCT `commission_pct`),COUNT(`commission_pct`) FROM employees;
# count函数的详细命令
SELECT COUNT(*) FROM employees; # 统计行数
SELECT COUNT(1) FROM employees; # 与上同
#----------------------------------练习练习练习------------------------------------------
# 查询公司员工工资的最大、最小、平均值,求总和
SELECT MAX(`salary`),MIN(`salary`),AVG(`salary`),SUM(`salary`) FROM employees;
# 查询员工表中的最大入职时间和最小入职时间的相差天数
SELECT DATEDIFF(MAX(`hiredate`),MIN(`hiredate`)) FROM employees;
SELECT DATEDIFF(NOW(),'1996-5-29'); # 查看自己活了多少天
# 查询部门编号为90的员工个数
SELECT COUNT(*) FROM employees WHERE `department_id`=90;
#---------------------------------------------------------------------------------------

三、分组查询

/* # 分组查询 group byselect 分组函数,列(要求出现在group by后面)from 表where 筛选条件(原始表源)group by 分组的列(单个、多个字段都可以)having 条件 (分组后结果集)order by 排序子句 */
# 查询每个工种的最高工资
SELECT MAX(`salary`),`job_id`
FROM employees
GROUP BY `job_id`;
# 查询每个位置上的部门个数
SELECT COUNT(*),`location_id`
FROM departments
GROUP BY `location_id`;
# 查询邮箱中包含a字符的,每个部门的平均工资
SELECT AVG(`salary`),`department_id`
FROM employees
WHERE `email` LIKE '%a%'
GROUP BY `department_id`;
# 查询有奖金的每个领导手下员工的最高工资
SELECT MAX(`salary`),`manager_id`
FROM employees
WHERE `commission_pct` IS NOT NULL
GROUP BY `manager_id`;
# 查询哪个部门的员工个数>2
SELECT COUNT(*),`department_id`
FROM employees
GROUP BY `department_id`# 查询每个部门的员工数
HAVING COUNT(*)>2; # having 找出个数>2的
# 查询每个工种有奖金的员工的最高工资>12000的工种编号和最高工资
SELECT MAX(`salary`),`job_id`
FROM employees
WHERE `commission_pct` IS NOT NULL
GROUP BY `job_id`
HAVING MAX(`salary`) > 12000;
# 查询领导编号>102的每个领导手下的最低工资>5000的领导编号是哪个
SELECT MIN(`salary`),`manager_id`
FROM employees
WHERE `manager_id` > 102
GROUP BY `manager_id`
HAVING MIN(`salary`) > 5000;# 按表达式或函数分组
# 按员工姓名的长度分组,查询每一组的员工个数,筛选员工个数>5的有哪些
SELECT COUNT(*),LENGTH(`last_name`)
FROM employees
GROUP BY LENGTH(`last_name`)
HAVING COUNT(*)>5;# 按多个字段分组
# 查询每个部门每个工种的平均工资
SELECT AVG(`salary`) AS 工资,`department_id`,`job_id`
FROM employees
GROUP BY `department_id`,`job_id`;# 添加排序
# 查询每个部门每个工种的平均工资,按平均工资的高低显示出来
SELECT AVG(`salary`) AS 工资,`department_id`,`job_id`
FROM employees
GROUP BY `department_id`,`job_id`
ORDER BY AVG(`salary`) DESC;#---------------------------------练习练习练习-------------------------------------------
# 查询各job_id的员工工资的最大、最小、平均值、总和,并按job_id升序
SELECT MAX(`salary`),MIN(`salary`),AVG(`salary`),SUM(`salary`),`job_id`
FROM employees
GROUP BY `job_id`
ORDER BY `job_id`;
# 查询员工最高工资和最低工资的差距
SELECT MAX(`salary`)-MIN(`salary`) FROM employees;
# 查询各个管理者手下员工的最低工资,其中最低工资不能低于6000,没有管理者的员工不计算在内
SELECT MIN(`salary`),`manager_id`
FROM employees
WHERE `manager_id` IS NOT NULL
GROUP BY `manager_id`
HAVING MIN(`salary`) > 6000;
# 查询所有部门的编号,员工数量和工资平均值,并按平均工资降序
SELECT AVG(`salary`) 平均工资,COUNT(*) 员工数量,`department_id`
FROM employees
GROUP BY `department_id`
ORDER BY 平均工资 DESC;
# 选择具有各个job_id的员工人数
SELECT COUNT(*) 人数,`job_id`
FROM employees
GROUP BY `job_id`;
#---------------------------------------------------------------------------------------

四、多表查询

/* 多表查询:查询的字段来自多个表 select...from...where(连接条件)...笛卡尔乘积现象:表1有m行,表2有n行,结果为m*n行发生原因:没有有效的连接条件如何避免:添加有效的连接条件分类:     按年代分类:sql92标准(内连接)、sql99标准(内连接+左右外连接+交叉连接)按功能分类:内连接:等值连接、非等值连接、自连接外连接:左外连接、右外连接、全外连接交叉连接
*/
SELECT * FROM beauty;
SELECT * FROM boys;
# 一、sq192标准
/*1、等值连接①、多张表等值连接的结果为多表的交集部分②、n表连接至少需要n-1个连接条件③、多表的顺序没有要求④、一般需要起别名  */
# 查询女神名和对应的男神名
SELECT NAME,boyName
FROM beauty,boys
WHERE beauty.boyfriend_id = boys.id;
# 查询员工名和对应部门名
SELECT `last_name`,`department_name`
FROM employees,departments
WHERE employees.`department_id`=departments.`department_id`;
# 为表起别名,提高简洁度
# 查询员工名、工种号、工种名
SELECT `last_name`,e.`job_id`,j.`job_title`
FROM employees e,jobs j
WHERE e.`job_id`=j.`job_id`;# 加筛选
# 查询有奖金的员工名、部门名、奖金
SELECT `last_name`,`department_name`,`commission_pct`
FROM employees e,departments d
WHERE e.`department_id`=d.`department_id` AND `commission_pct` IS NOT NULL;
# 查询城市名中第二个字符为o的部门名和城市名
SELECT department_name,city
FROM departments d,locations l
WHERE d.`location_id`=l.`location_id` AND city LIKE '_o%';# 加分组
# 查询每个城市的部门个数
SELECT COUNT(*),l.city
FROM departments d,locations l
WHERE d.`location_id`=l.`location_id`
GROUP BY city;
# 查询有奖金的每个部门的部门名、领导编号和该部门的最低工资
SELECT MIN(salary),d.`manager_id`,d.`department_name`
FROM employees e,departments d
WHERE e.`department_id`= d.`department_id` AND `commission_pct` IS NOT NULL
GROUP BY d.`department_name`,d.`manager_id`;# 加排序
# 查询每个工种的工种名和员工个数,并且按员工个数降序
SELECT COUNT(*),j.`job_title`
FROM employees e,jobs j
WHERE e.`job_id` = j.`job_id`
GROUP BY `job_title`
ORDER BY COUNT(*) DESC;# 实现三表连接
# 查询员工名、部门名和所在城市
SELECT `last_name`,`department_name`,`city`
FROM employees e,departments d,locations l
WHERE e.`department_id`=d.`department_id` AND d.`location_id`=l.`location_id`;# 2、非等值连接
# 查询员工的工资和工资级别
SELECT salary,`grade_level` 等级
FROM employees e,job_grades g
WHERE salary BETWEEN g.`grade_level` AND g.`highest_sal`; # 提前查看表中结构# 3、自连接
# 查询员工名和上级的名称
SELECT e.`employee_id` '上级ID',e.`last_name` '上级名',m.`employee_id`,m.`last_name`
FROM employees e,employees m # 两张一样的表,一张叫e,一张叫m
WHERE e.`employee_id`=m.`manager_id`;#--------------------------------练习练习练习----------------------------------------
# 显示员工表的最大工资、工资平均值
SELECT MAX(`salary`),AVG(`salary`) FROM employees;
# 查询员工表的`employee_id`、`job_id`、`last_name`,按`department_id`降序,`salary`升序
SELECT `employee_id`,`job_id`,`last_name`
FROM employees
ORDER BY `department_id` DESC,`salary`;
# 查询员工表的`job_id`中包含a和e的,并且a在e前面
SELECT `job_id`
FROM employees
WHERE `job_id` LIKE '%a%e%';
# 显示所有员工的姓名、部门号和部门名称
SELECT `last_name`,d.`department_id`,d.`department_name`
FROM employees e,departments d
WHERE e.`department_id`=d.`department_id`;
# 查询90号部门员工的`job_id`和90号部门的`location_id`
SELECT `job_id`,`location_id`
FROM employees e,departments d
WHERE e.`department_id`=d.`department_id` AND d.`department_id`=90;
# 选择所有有奖金员工的`last_name`,`department_name`,`location_id`,`city`
SELECT `last_name`,`department_name`,d.`location_id`,`city`
FROM employees e,departments d,locations l
WHERE e.`department_id`=d.`department_id` AND d.`location_id`=l.`location_id`
AND e.`commission_pct` IS NOT NULL;
# 选择city在Toronto工作的员工的`last_name`,`job_id`,`department_id`,`department_name`
SELECT `last_name`,`job_id`,e.`department_id`,`department_name`
FROM employees e,departments d,locations l
WHERE e.`department_id`=d.`department_id`
AND d.`location_id`=l.`location_id`
AND l.`city`='Toronto';
# 查询每个工种、每个部门的部门名、工种名和最低工资
SELECT `department_id`,`job_title`,MIN(`salary`)
FROM employees e,departments d,jobs j
WHERE e.`department_id`=d.`department_id` AND e.`job_id`=j.`job_id`
GROUP BY `job_title`,`department_name`;
# 查询每个国家下的部门个数大于2的国家编号
SELECT `country_id`,COUNT(*)
FROM departments d,locations l
WHERE d.`location_id`=l.`location_id`
GROUP BY `country_id`
HAVING COUNT(*)>2;
/* 选择指定员工的姓名、员工号,以及他的管理者的姓名和员工号,结果类似下面形式
employees    Emp#     manager Mgr#
kochhar      101     king    100   */
SELECT e.`last_name` 'employees',e.`employee_id` 'Emp#',m.`last_name` 'manager',m.`employee_id` 'Mgr#'
FROM employees e,employees m
WHERE e.`manager_id`=m.`employee_id`
AND e.`last_name` = 'kochhar';
#---------------------------------------------------------------------------------------
/* 二、sql99语法select 查询列表from 表1 别名【连接类型】join 表2 别名on 连接条件where 筛选条件group by 分组having ...order by ...分类(放在【连接类型】中):
1、内连接(不分主子表):inner
2、外连接(分主子表):           左外:left右外:right全外:full
3、交叉连接:cross
*/
/* 1、内连接select 查询列表from 表1 别名inner join 表2 别名on 连接条件分类:等值非等值自连接特点:①inner可以省略②筛选条件放where后面,连接条件放on后面③inner join连接和sql92语法中的等值连接效果一样
*/
# 等值连接
# 查询员工名、部门名
SELECT `last_name`,`department_name`
FROM employees e INNER JOIN departments d
ON e.`department_id`=d.`department_id`;
# 查询名字中包含e的员工名和工种名
SELECT `last_name`,`job_title`
FROM employees e INNER JOIN jobs j
ON e.`job_id`=j.`job_id`
WHERE last_name LIKE '%e%';
# 查询部门个数>3的城市名和部门个数
SELECT `city`,COUNT(*)
FROM departments d INNER JOIN locations l
ON d.`location_id`=l.`location_id`
GROUP BY `city`
HAVING COUNT(*)>3;
# 查询哪个部门的员工个数>3的部门名和员工个数,并按个数降序
SELECT `department_name`,COUNT(*)
FROM departments d INNER JOIN employees e
ON d.`department_id`=e.`department_id`
GROUP BY d.`department_name`
HAVING COUNT(*) > 3
ORDER BY COUNT(*) DESC;
# 查询员工名、部门名、工种名,并按部门名降序
SELECT `last_name`,d.`department_name`,`job_title`
FROM employees e INNER JOIN departments d
ON e.`department_id`=d.`department_id`
INNER JOIN jobs j
ON e.`job_id`=j.`job_id`
ORDER BY `department_name` DESC;# 非等值连接
# 查询员工的工资级别
SELECT `salary`,`grade_level`
FROM employees e INNER JOIN job_grades g
ON e.`salary` BETWEEN g.`lowest_sal` AND g.`highest_sal`;
# 查询工资级别个数>20的个数,并且按工资级别降序
SELECT `grade_level` 级别,COUNT(*) 个数
FROM employees e INNER JOIN job_grades g
ON `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 INNER JOIN employees m
ON e.`employee_id` = m.`manager_id`
WHERE m.`last_name` LIKE '%k%';/* 2、外连接应用场景:用于查询一个表中有,另一个表中没有的记录外连接的查询结果为主表中的所有记录如果有匹配的显示值;如果没匹配的显示null左外连接,left join左边的是主表右外连接,right join右边的是主表*/
# 查询没有男朋友的女神名(左外连接)
SELECT b.`name`,bo.`boyName`
FROM beauty b
LEFT JOIN boys bo
ON b.`boyfriend_id`= bo.`id`
WHERE bo.`id` IS NULL;
# 查询没有男朋友的女神名(右外连接,结果与上同)
SELECT b.`name`,bo.`boyName`
FROM boys bo
RIGHT JOIN beauty b
ON b.`boyfriend_id`= bo.`id`
WHERE bo.`id` IS NULL;
# 查询那个部门没有员工(左外连接)
SELECT `department_name`,`employee_id`
FROM departments d
LEFT JOIN employees e
ON d.`department_id`=e.`department_id`
WHERE e.`employee_id` IS NULL;
# 查询那个部门没有员工(右外连接)
SELECT `department_name`,`employee_id`
FROM employees e
RIGHT JOIN departments d
ON d.`department_id`=e.`department_id`
WHERE e.`employee_id` IS NULL;
/*左右外连接:主表数据到子表数据的映射,没有匹配的数据为null全外连接:不分主子表,互相映射,没有匹配的数据为null  */
SELECT b.*,bo.* # full join
FROM beauty b
FULL JOIN boys bo
ON b.`boyfriend_id`=bo.id; # 代码无法执行,掌握原理即可
# 交叉连接(笛卡尔乘积) cross join
SELECT b.*,bo.*
FROM beauty b
CROSS JOIN boys bo;# 表1行数与表2行数相乘,每一条数据都笛卡尔分配
#---------------------------------练习练习练习-------------------------------------------
# 查询编号>3的女神的男朋友信息,如果有则列出详细,如果没有用null填充
SELECT b.`name`,bo.*
FROM beauty b
LEFT JOIN boys bo
ON b.`boyfriend_id`=bo.`id`
WHERE b.`id` > 3;
# 查询哪些城市没有部门
SELECT `city`
FROM departments d
RIGHT JOIN locations l
ON d.`location_id`=l.`location_id`
WHERE d.`department_id` IS NULL;
# 查询部门名为SAL或IT的员工信息
SELECT d.`department_name` 部门名,e.*
FROM employees e
RIGHT JOIN departments d
ON e.`department_id`=d.`department_id`    # 内连接不分主子表,外连接要分主子表
WHERE d.`department_name` IN('SAL','IT'); # 可用内连接,查看效果
#---------------------------------------------------------------------------------------

五、子查询

/* 子查询含义:出现在其他语句中的select语句,称为子查询或内查询外部的查询语句,称为主查询或外查询  分类:按子查询出现的位置:select后面(仅支持标量子查询)from后面(支持表子查询)where或having后面(支持标量、列、行子查询)☆exists后面(相关表子查询)按结果集的行列数不同:标量子查询(结果集只有一行一列)列子查询(结果集只有一列多行)行子查询(结果集有一行多列)表子查询(结果集一般为多行多列)*//* 一、where或having后面特点:①子查询放在小括号内②子查询一般放在条件右侧③标量子查询,一般搭配着单行操作符使用(单行操作符:>,<,=,<>)④列子查询,一般搭配着多行操作符使用(多行操作符:in,any,some,all)⑤子查询比主查询先运行 */
# 1、标量子查询(单行子查询)
# 查询谁的工资比Abel高?
SELECT `last_name`
FROM employees
WHERE salary > (SELECT salary FROM employees WHERE last_name='Abel');
# 返回`job_id`与141号员工相同,且`salary`比143号员工多的员工姓名、`job_id`和工资
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);
# 返回公司工资最少的员工的`last_name`,`job_id`和`salary`
SELECT `last_name`,`job_id`,`salary`
FROM employees
WHERE `salary`=(SELECT MIN(`salary`) FROM employees);
# 查询最低工资大于50号部门最低工资的部门id和其最低工资
SELECT `department_id`,MIN(`salary`)
FROM employees
GROUP BY `department_id`
HAVING MIN(`salary`) > (SELECT MIN(`salary`) FROM employees WHERE `department_id`=50);# 2、列子查询(多行子查询)
# 返回`location_id`是1400或1700的部门中的所有员工姓名
SELECT `last_name`
FROM employees
WHERE `department_id` IN(SELECT `department_id` FROM departments WHERE `location_id` IN(1400,1700));
# 返回其它工种中比`job_id`为‘IT_PROG’部门任一工资低的员工的员工工号、姓名、`job_id`和salary
# ① 查询`job_id`为'IT_PROG'部门任一工资
SELECT DISTINCT(`salary`)
FROM employees
WHERE `job_id` = 'IT_PROG';
# ② 查询比①中工资低的员工工号、姓名、`job_id`和salary
SELECT `employee_id`,`last_name`,`job_id`,`salary`
FROM employees
WHERE salary < ANY(SELECT DISTINCT(`salary`)FROM employeesWHERE `job_id` = 'IT_PROG')
AND `job_id` <> 'IT_PROG';
# 返回其它工种中比`job_id`为‘IT_PROG’部门所有工资低的员工的员工工号、姓名、`job_id`和salary
SELECT `employee_id`,`last_name`,`job_id`,`salary`
FROM employees
WHERE salary < ALL(SELECT DISTINCT(`salary`)FROM employeesWHERE `job_id` = 'IT_PROG')
AND `job_id` <> 'IT_PROG';# 3、行子查询(一行多列)
# 查询员工编号最小并且工资最高的员工信息
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);# 二、放select后面 (仅支持标量子查询)
# 案例:查询每个部门的员工个数
SELECT d.*,(SELECT COUNT(*) FROM employees e WHERE e.`department_id`=d.`department_id`) AS 个数
FROM departments d;
# 查询员工号=102的部门名
SELECT `department_name`
FROM departments d,employees e
WHERE d.`department_id`=e.`department_id` AND e.`employee_id`=102;
# 或
SELECT (SELECT `department_name` FROM departments dINNER JOIN employees eON d.`department_id`=e.`department_id`WHERE `employee_id`=102) 部门名;# 三、放from后面
# 查询每个部门的平均工资的工资等级
# ① 每个部门的平均工资
SELECT AVG(`salary`)
FROM employees
GROUP BY `department_id`;
# ② 连接①的结果集和`job_grades`表,筛选平均工资在`lowest_sal`和`highest_sal`之间
SELECT g.`grade_level`
FROM job_grades g
INNER JOIN (SELECT AVG(`salary`) ag # 查询的结果集当成一张表用FROM employees          # (必须起别名)GROUP BY `department_id`) ag_dep
ON ag_dep.ag BETWEEN g.`lowest_sal` AND g.`highest_sal`;# 四、放exists后面(相关子查询)
/* exists判断是还是否,有还是无,布尔类型(1代表True,0代表False)语法:exists(完整的查询语句) 结果:1或0  */
SELECT EXISTS(SELECT `employee_id` FROM employees);#括号中不管几行,只要能返回就为True
SELECT EXISTS(SELECT `employee_id` FROM employees WHERE salary=0);#无返回为False
# 查询有员工名的部门名
SELECT `department_name`
FROM departments d
WHERE EXISTS( SELECT *FROM employees eWHERE d.`department_id`=e.`department_id`);
# 或用in
SELECT `department_name`
FROM departments d
WHERE d.`department_id` IN( SELECT `department_id` FROM employees eWHERE e.`department_id`=d.`department_id`);
# 查询没有女朋友的男神信息
# 用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 bWHERE b.`boyfriend_id`=bo.`id`);
#----------------------------------------练习练习练习----------------------------------
# 查询和Zlotkey相同的部门的员工姓名和工资
SELECT `last_name`,`salary`
FROM employees
WHERE `department_id`=( SELECT `department_id`FROM employeesWHERE `last_name`='Zlotkey');
# 查询工资比公司平均工资高的员工的员工号、姓名和工资
SELECT `employee_id`,`last_name`,`salary`
FROM  employees
WHERE `salary` > (SELECT AVG(`salary`)FROM employees);
# 查询各部门中工资比本部门平均工资高的员工工号、姓名和工资☆
# ①查询各部门的平均工资
SELECT AVG(salary)
FROM employees
GROUP BY `department_id`;
# ②连接①和`employees`表,进行筛选
SELECT `employee_id`,`last_name`,`salary`
FROM employees e
INNER JOIN (             SELECT AVG(salary) ag,`department_id`FROM employeesGROUP BY `department_id`) ag_dep
ON e.`department_id`=ag_dep.`department_id`
WHERE `salary`>ag_dep.ag;
# 查询和姓名中包含字母U的员工在相同部门员工的员工号和姓名
SELECT `employee_id`,`last_name`
FROM employees
WHERE `department_id` IN(SELECT `department_id`FROM employees WHERE `last_name` LIKE '%u%');
# 查询在部门的`location_id`为1700的部门工作的员工的员工号
SELECT `employee_id`
FROM employees e
WHERE `department_id` IN(SELECT `department_id` FROM departments dWHERE `location_id`=1700);
# 查询管理者是K_ing的员工姓名和工资
SELECT `last_name`,`salary`
FROM employees
WHERE `manager_id` IN( SELECT `employee_id`FROM employeesWHERE last_name = 'K_ing');
# 查询工资最高的员工的姓名,要求`first_name`和`last_name`显示为一列
SELECT MAX(salary)
FROM employees;
#
SELECT CONCAT(`first_name`,`last_name`) '姓.名'
FROM employees
WHERE salary IN(SELECT MAX(salary)FROM employees);
#---------------------------------------------------------------------------------------

六、分页和联合查询

/* 分页查询(limit)应用:当要显示的数据一页显示不全,需要分页提交sql请求语法:select 查询列表from 表【join 表2on 连接条件where...group by order by】limit offset,size;  【】内为选择性添加offset要显示条目的起始索引(起始索引从0开始)size 要显示的条目个数 特点:limit语句放在最后 */
# 查询前五条员工信息
SELECT *
FROM employees
LIMIT 0,5;
# 或 (若从第一条开始可以省略起始索引)
SELECT *
FROM employees
LIMIT 5;
# 查询第11条到第25条员工信息
SELECT *
FROM employees
LIMIT 10,15;
# 有奖金的员工信息,且工资较高的前10名显示出来
SELECT *
FROM employees
WHERE `commission_pct` IS NOT NULL
ORDER BY `salary` DESC
LIMIT 10;
# 查询工资最低的员工的`last_name`和`salary`
SELECT `last_name`,`salary`
FROM employees
WHERE salary=(SELECT MIN(`salary`) FROM employees);
# 查询平均工资最低的部门 ☆
# ①求各部门的平均工资
SELECT AVG(`salary`)
FROM employees
GROUP BY `department_id`;
# ②查询①结果上的最低平均工资
SELECT MIN(ag)
FROM (SELECT AVG(`salary`) ag,`department_id`FROM employeesGROUP BY `department_id`) ag_dep;
# ③查询哪个部门平均工资=②
SELECT AVG(`salary`),`department_id`
FROM employees
GROUP BY `department_id`
HAVING AVG(`salary`) =(SELECT MIN(ag)FROM (SELECT AVG(`salary`) ag,`department_id`FROM employeesGROUP BY `department_id`) ag_dep);
# 或
SELECT AVG(`salary`),`department_id`
FROM employees
GROUP BY `department_id`
ORDER BY AVG(salary)
LIMIT 0,1;
# 查询平均工资最低的部门信息和该部门的平均工资
# ①求平均工资最低的部门编号
SELECT AVG(`salary`),`department_id`
FROM employees
GROUP BY `department_id`
ORDER BY AVG(salary)
LIMIT 0,1;
# ②查询部门信息
SELECT d.*,ag
FROM departments d
JOIN (SELECT AVG(`salary`) ag,`department_id`FROM employeesGROUP BY `department_id`ORDER BY AVG(salary)LIMIT 0,1) ag_dep
ON d.`department_id`=ag_dep.`department_id`;
# 查询平均工资最高的jobs表信息
# ①查询每个job的平均工资
SELECT AVG(salary)
FROM employees
GROUP BY `job_id`;
# ②找①中平均工资最高的
SELECT AVG(salary),`job_id`
FROM employees
GROUP BY `job_id`
ORDER BY AVG(salary) DESC
LIMIT 1;
# ③查询jobs表信息
SELECT *
FROM jobs
WHERE job_id=(SELECT `job_id`FROM employeesGROUP BY `job_id`ORDER BY AVG(salary) DESCLIMIT 1);
# 查询平均工资高于公司平均工资的部门有哪些
# ①查公司平均工资
SELECT AVG(salary)
FROM employees;
# ②查各部门的平均工资
SELECT AVG(salary)
FROM employees
GROUP BY `department_id`;
# ③筛选②结果集,满足平均工资>①
SELECT AVG(salary),`department_id`
FROM employees
GROUP BY `department_id`
HAVING AVG(salary)>(SELECT AVG(salary)FROM employees);
# 查询出公司所有manager的详细信息
# ①查询所有manager的员工编号
SELECT DISTINCT(`manager_id`)
FROM employees;
# ②查询员工编号=①的信息
SELECT *
FROM employees
WHERE `employee_id` IN(SELECT DISTINCT(`manager_id`)FROM employees);
# 各个部门中最高工资中最低的那个部门的最低工资是多少
# ①各个部门的最高工资中最低的那个部门
SELECT `department_id`
FROM employees
GROUP BY `department_id`
ORDER BY MAX(salary) ASC
LIMIT 1;
# ②查询对应①部门的最低工资
SELECT MIN(`salary`)
FROM employees
WHERE `department_id` =(SELECT `department_id`FROM employeesGROUP BY `department_id`ORDER BY MAX(salary) ASCLIMIT 1);
# 查询平均工资最高的部门的manager的`last_name`,`department_id`,`email`,`salary`
# ①平均工资最高的部门
SELECT `department_id`
FROM employees
GROUP BY `department_id`
ORDER BY AVG(salary) DESC
LIMIT 1;
# ②查询部门id等于①的manager_id
SELECT `manager_id`
FROM employees
WHERE `department_id` = (SELECT `department_id`FROM employeesGROUP BY `department_id`ORDER BY AVG(salary) DESCLIMIT 1);
# ③查询manager_id=②的`last_name`,`department_id`,`email`,`salary`
SELECT `last_name`,`department_id`,`email`,`salary`
FROM employees
WHERE `manager_id` IN(SELECT `manager_id`FROM employeesWHERE `department_id` = (SELECT `department_id`FROM employeesGROUP BY `department_id`ORDER BY AVG(salary) DESCLIMIT 1));
#---------------------------------------------------------------------------------------
/* 联合查询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%';
#---------------------------------------------------------------------------------------

七、数据的增、改、删

# DML语言(数据操作语言)
/* 插入:insert into ...修改:update ... set ...删除:delete from... truncate table ... */# 一、插入语句
/* 语法:insert into 表名(列名,...)values(值1,...);
*/
# 1、插入的值类型要与列的类型一致或兼容
INSERT INTO beauty(`id`,`name`,`sex`,`borndate`,`phone`,`photo`,`boyfriend_id`)
VALUES(13,'唐艺昕','女','1990-4-23','18988888888',NULL,2);
# 2、不可以为null的列必须插入值,可以为null的列如何插入值?
# 方式一:同上
INSERT INTO beauty(`id`,`name`,`sex`,`borndate`,`phone`,`photo`,`boyfriend_id`)
VALUES(13,'唐艺昕','女','1990-4-23','18988888888',NULL,2);
# 方式二:
INSERT INTO beauty(`id`,`name`,`sex`,`phone`)
VALUES(15,'娜扎','女','18988888888');
# 3、列的顺序可以调换
INSERT INTO beauty(`name`,`sex`,`id`,`phone`)
VALUES('蒋欣','女',16,'110');
# 4、列数和值的个数要一致
INSERT INTO beauty(`name`,`sex`,`id`,`phone`,`boyfriend_id`)
VALUES('关晓彤','女',17,'110'); # 不一致,报错
# 5、可以省略列名,默认所有列,而且列的顺序和表中一致
INSERT INTO beauty
VALUES(18,'张飞','男',NULL,'119',NULL,NULL); /* 插入语句另一种方式语法:insert into 表名set 列名=值,列名=值,...; */
INSERT INTO beauty
SET `id`=19,`sex`='女',`name`='刘涛',`phone`=999;# 两种方式大pk
# 1、第一种方法支持插入多行,第二种方法不支持
INSERT INTO beauty
VALUES(13,'唐艺昕','女','1990-4-23','18988888888',NULL,2),(14,'杨幂','女','1990-5-26','18988888882',NULL,2),(15,'赵丽颖','女','1990-6-4','18988888884',NULL,2);
# 2、第一种方法支持子查询,第二种方法不支持
INSERT INTO beauty(`id`,`name`,`phone`)
SELECT 26,'宋茜','11809866';    # 可以用select 子查询(不用values)# 二、修改语句
/* 1、修改单表记录语法: update 表名set 列=新值,列=新值,...(要修改内容)where 筛选条件;2、修改多表记录 sql92语法:语法: update 表1 别名,表2 别名set 列=新值,...(要修改内容)where 连接条件and 筛选条件;sql99语法:
语法:  update 表1 别名inner|left|right join 表2 别名on 连接条件set 列=新值,...(要修改内容)where 筛选条件*/# 1、修改单表
# 修改beauty表中姓唐的女神电话为13899888899
UPDATE beauty
SET `phone`=13899888899
WHERE NAME LIKE '唐%';
# 将boys表中id=2的男神名改成张飞,魅力值为10
UPDATE boys
SET `boyName` = '张飞',`userCP` = 10
WHERE id = 2;# 2、修改多表
# 修改张无忌的女朋友的手机号为114
UPDATE `beauty` b
LEFT JOIN boys bo   #注意之前的是select...from(表1)join(表2)on(连接条件)
ON bo.`id`=b.`boyfriend_id`
SET b.`phone` = 114
WHERE bo.`boyName` = '张无忌';
# 修改没有男朋友的女神的男朋友编号都为2号(有误)
UPDATE boys bo
RIGHT JOIN beauty b
ON bo.`id`=b.`boyfriend_id`
SET b.`boyfriend_id`=2
WHERE b.`boyfriend_id` IS NULL;# 三、删除语句
/* 方式一:delete  (删整行)1、单表的删除语法:delete from 表名 where 筛选条件2、多表的删除语法:delete 表1的别名,表2的别名from 表1 别名inner|left|right join 表2 别名on 连接条件where 筛选条件;方式二:truncate(删全表)语法:truncate table 表名; */# 方式一:delete
# 1、单表删除
# 删除手机号以9结尾的女神信息
DELETE FROM `beauty` WHERE `phone` LIKE '%9';# 2、多表删除
# 删除张无忌的女朋友信息
DELETE b
FROM beauty b
INNER JOIN boys bo
ON b.`boyfriend_id`=bo.`id`
WHERE bo.`boyName`='张无忌';
# 删除黄晓明和他女朋友的信息
DELETE b,bo
FROM beauty b
INNER JOIN boys bo
ON b.`boyfriend_id`=bo.`id`
WHERE bo.`boyName`='黄晓明';# 方式二:truncate (不能加where)
TRUNCATE TABLE `boys`
# 将魅力值>100的男神信息删除
TRUNCATE TABLE `boys` WHERE `userCP`>100; #错误,不能加where#   delete和truncate区别:
/*  假如要删除的表中有自增长列,如果用delete删除后,再插入数据,自增长列的值从断点开始,而truncate删除后,再插入数据,自增长列的值从1开始。(自增长:增加数据行,它的id自动紧随之前的id加1)*/
#   delete删除有返回值,truncate删除没有返回值
#   truncate删除不能回滚,delete删除可以回滚
#   delete可加where,truncate不能加where/*
增:insert into 表 values();
改:单表:update 表 set 条件;多表:update 表1,表2 from 表1 join 表2 on 连接条件 set 条件 where ...;
删:行删:delete from 表 where ...;全删:truncate table 表;
*/
#---------------------------------------------------------------------------------------

八、库和表的管理

# DDL
/*
数据定义语言,库和表的管理一、库的管理
创建、修改、删除二、表的管理
创建、修改、删除对库和表的操作:        对表中数据的操作:
创建:create            增:insert
修改:alter     改:update
删除:drop      删:delete
*/# 一、库的管理
/* 1、库的创建    语法:create database [if not exists]库名;
*/# 创建库book
CREATE DATABASE books;
CREATE DATABASE IF NOT EXISTS books; # 如果不存在则创建# 2、库的修改
# 改库名到文件夹中改
# 改库的编码字符集 (alter database 库名 character set 编码)
ALTER DATABASE books CHARACTER SET utf8;# 3、库的删除
DROP DATABASE books;
DROP DATABASE IF EXISTS books; #如果存在则删除# 二、表的管理
# 1、表的创建
/*语法:create table [if not exists]表名(列名,列类型【(长度) 约束】,列名,列类型【(长度) 约束】,列名,列类型【(长度) 约束】,...)
*/
# 创建表book
CREATE TABLE book(id INT,#整数bname VARCHAR(20),#字符型,最大长度为20place DOUBLE,authorID INT,publishDate DATETIME); #日期
CREATE TABLE author(id INT,au_name VARCHAR(20),nation VARCHAR(20));# 2、表的修改(改列名、改列类型或约束、添加列、删除列、改表名)
/* alter table 表名 change column|modify column|add column|drop column|rename to 列名 【列类型 约束】; */
# 改列名
ALTER TABLE book CHANGE COLUMN publishDate pubDate DATETIME;
# 改列类型
ALTER TABLE book MODIFY COLUMN pubDate TIMESTAMP;
# 添加列
ALTER TABLE author ADD COLUMN annual DOUBLE;
# 删除列
ALTER TABLE author DROP COLUMN annual;
# 改表名
ALTER TABLE author RENAME TO book_author;# 3、表的删除
DROP TABLE book_author;
DROP TABLE IF EXISTS book_author;# 4、表的复制
INSERT INTO book_author
VALUES  (1,'村上春树','日本'),(2,'莫言','中国'),(3,'冯唐','中国'),(4,'金庸','中国'); # 给表添加数据
# 仅仅复制表的结构
CREATE TABLE copy LIKE book_author;
# 复制表的结构+全部内容
CREATE TABLE copy2 SELECT * FROM book_author;
# 复制表的结构+部分内容
CREATE TABLE copy3 SELECT `id`,`au_name` FROM `book_author` WHERE nation='中国';
# 仅仅复制某些字段(索引)
CREATE TABLE copy4 SELECT `id`,`au_name` FROM `book_author` WHERE 1=2;# 不成立就没有数据
#--------------------------------------练习练习练习------------------------------------------
# 创建库test
CREATE DATABASE IF NOT EXISTS test;
# 创建表dept1
CREATE TABLE dept1(id INT(7),NAME VARCHAR(25));
# 将表departments中的数据插入新表dept2中(可以跨库)
CREATE TABLE dept2
SELECT `department_id`,`department_name`
FROM `myemployees`.departments;
# 创建表emp5
CREATE TABLE emp5(id INT(7),First_name VARCHAR(25),Last_name VARCHAR(25),Dept_id INT(7));
# 将列Last_name的长度增加到50
ALTER TABLE emp5 MODIFY COLUMN last_name VARCHAR(50);
# 根据表`employees`创建employees2(复制)
CREATE TABLE employees2 SELECT * FROM `myemployees`.`employees`;
# 删除表emp5
DELETE TABLE IF EXISTS emp5;
# 将表employees2重命名为emp5
ALTER TABLE `myemployees`.employees2 RENAME TO emp5;
# 在表dept和emp5中添加新列test_column,并检查所作的操作
ALTER TABLE dept ADD COLUMN IF NOT EXISTS test_column INT;
ALTER TABLE emp5 ADD COLUMN IF NOT EXISTS test_column INT;
# 直接删除表emp5中的列dept_id
ALTER TABLE emp5 DROP COLUMN dept_id;
#---------------------------------------------------------------------------------------

九、数据类型

# 常见的数据类型(实际应用中所选类型越简单越好)
/*
数值型:整型小数定点数浮点数
字符型:较短的文本:char、varchar较长的文本:text、blob(图片)
日期型:
*/
# 一、整型
/* Tinyint 微整型 1个字节Smallint 小整型 2个字节Mediumint 中整型 3个字节Int  常用整型 4个字节Bigint 大整型 8个字节特点:①如果不设置有无符号,默认为有,否则追加unsigned②如果插入数值超过整型范围,只插入到临界值③如果不设置长度,会有默认长度
(长度就是int()括号内数值,它代表了显示的最大宽度,如果不够可使用zerofill用0左填充)
*/
# 1、如何设置无符号和有符号(无符号不能插入负数,有符号可以)
CREATE TABLE tab_int(t1 INT,t2 INT UNSIGNED); # unsigned无符号
INSERT INTO tab_int VALUES(-5,5); #由于无符号,t2不可插入负数
DESC tab_int; #查询表信息# 2、长度设置
CREATE TABLE tab_int2(t1 INT,t2 INT(7) ZEROFILL); # zerofill,用0填充长度,无符号
INSERT INTO tab_int2 VALUES(-5,5); #由于无符号,t2不可插入负数
SELECT * FROM tab_int2; # int有7个长度,用0填充# 二、小数
/*
浮点型:float(M,D) 4个字节double(M,D) 8个字节
定点型:Dec(M,D) 与double类似,但是精度更高特点:①M表示整数和小数位数一共的长度(小数点算一位)②D表示四舍五入保留几位小数③M和D可以不设置,会有默认设置(10,0)*/
# 测试M和D
CREATE TABLE tab_float(f1 FLOAT(5,2),f2 DOUBLE(5,2),f3 DEC(5,2));
INSERT INTO tab_float VALUES(1523.45,123.45,123.45); # 都插入123.45
INSERT INTO tab_float VALUES(1523.456,123.456,123.456); # 插入123.456
INSERT INTO tab_float VALUES(1523.45,1523.45,1523.45); # 都插入1523.45 错误             # 三、字符型
/*
较短的文本:char(M)    固定字符  耗空间       效率高varchar(M) 可变字符   较节省空间   效率低enum(列表) 用于保存枚举set(列表)  用于保存集合binary和varbinary 用于保存较短的二进制
较长的文本:textblob(保存图片)特点:char的M可以省略,默认为1varchar的M不可以省略
*/
# enum类型
CREATE TABLE tab_char(cl 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('A'); # 不区分大小写
INSERT INTO tab_char VALUES('m'); # 插入enum中不存在的m  错误
# set类型
CREATE TABLE tab_set(sl SET('a','b','c'));
INSERT INTO tab_set VALUES('a');
INSERT INTO tab_set VALUES('A,b,c'); # 可多个一起插入,不区分大小写
INSERT INTO tab_set VALUES('A,a,c'); # 有重复只保留一个,这里a重复,插入为(a,c)# 四、日期型
/*date 4个字节 只有日期datetime 8个字节 日期+时间timestamp 4个字节 日期+有时间time 3个字节 只有时间year 1个字节 只有年datetime和timestamp的区别:①datetime的范围大1000-9999,timestamp的范围小1970-2038②datetime只能反映插入时当地时区timestamp和实际时区有关,更能反映实际的日期③timestamp的属性受Mysql版本和SQLMode的影响很大
*/
CREATE TABLE tab_date(t1 DATETIME,t2 TIMESTAMP);
INSERT INTO tab_date VALUES(NOW(),NOW());# 北京时间,东八区
SHOW VARIABLES LIKE 'time_zone'; #其中value值为系统时区
SET time_zone = '+9:00'; # 更改时区为东9区
#---------------------------------------------------------------------------------------

十、常见约束

# 常见约束
/* 含义:一种限制,用于限制表中的数据,为了保证表中数据的准确和可靠性。分类:六大约束NOT NULL:非空约束,保证该字段的值不能为空(如姓名、学号)default:默认,用于保证该字段有默认值(如性别,没设置时可默认为男)primary key:主键(一般只有一个主键,比如id是表的主键),用于保证该字段的值具有唯一性,且非空(如学号都不同,有唯一性)unique:唯一,用于保证该字段的值具有唯一性,可以为空check:检查约束【mysql不支持】(比如年龄,定义在18-60岁)foreign key:外键,用于限制两个表的关系,用于保证该字段的值必须来自于主表的关联列的值在从表添加外键约束,用于引用主表中某列的值(如学生表的专业编号,员工表的工种编号)添加约束的时机:1、创建表时2、修改表时(都在数据被插入之前)约束的添加分类:列级约束:create table 表名(字段名 字段类型 约束);(六大约束语法上都支持,但外键约束没有效果)表级约束:create table 表名(字段名 字段类型 约束,字段名 字段类型 约束,【constraint 约束名】 约束类型(字段名)【constraint 约束名】 约束类型(字段名) references 外表(字段名)); #将本表某列和外表某列连接(除了非空、默认,其它约束都支持)约束可以同时添加多个:如 create table if not exists syuinfo(id int primary key,stuname varchar(20) not null unique);(加not null约束后再加unique约束)*/# 一、创建表时添加约束
CREATE DATABASE students; # 创建新库
USE students;
# 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,/* 默认约束为18岁*/majorID INT REFERENCES major(id));#外键,majorID与major表id列连接CREATE TABLE major(id INT PRIMARY KEY,majorName VARCHAR(20));SHOW INDEX FROM stuinfo;# 查看索引,显示包括主键、外键、唯一# 2、添加表级约束
/* 语法:在各个字段的最下面【constraint 约束名】 约束类型(字段名)
*/
CREATE TABLE stuinfo2(id INT, stuName VARCHAR(20),gender CHAR(1), seat INT,age INT,majorID INT,CONSTRAINT pk PRIMARY KEY(id),#主键CONSTRAINT ug UNIQUE(seat),# 唯一键,可多个,如unique(seat,seat2)CONSTRAINT ck CHECK(gender='男' OR gender='女'),# 检查CONSTRAINT fk_stuinfo2_major FOREIGN KEY(majorid) REFERENCES major(id));#外键,将fk_stuinfo2_major列与major的id列相连接
SHOW INDEX FROM stuinfo2;# 查看索引,显示包括主键、外键、唯一
/* 通用写法:create table if not exists syuinfo(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、要求在从表设置外键关系2、从表的外键列类型和主表的关联列的类型要求一致或兼容,名称无要求(如上面的syuinfo表的majorid列是int类型,major表的id列也是int类型)3、主表的关联列必须是一个key(一般是主键或唯一键)4、插入数据时,先插入主表,再插入从表5、删表先删从表,建表先建主表 */# 二、修改表时添加约束
/*
1、添加列级约束alter table 表名 modify column 列名 列类型 新约束;
2、添加表级约束alter table 表名 add 【constraint 约束名】 新约束(列名);
*/
CREATE TABLE stuinfo3(id INT, stuName VARCHAR(20),gender CHAR(1), seat INT,age INT,majorID INT);
# 1、添加非空约束(NOT NULL)
ALTER TABLE stuinfo MODIFY COLUMN stuName VARCHAR(20) NOT NULL;
# 2、添加默认约束(default)
ALTER TABLE stuinfo MODIFY COLUMN age INT DEFAULT 18;
# 3、添加主键约束(primary key)
# ①列级约束
ALTER TABLE stuinfo MODIFY COLUMN id INT PRIMARY KEY;
# ②表级约束
ALTER TABLE stuinfo ADD PRIMARY KEY(id);
# 4、添加唯一约束(unique)
# ①列级约束
ALTER TABLE stuinfo MODIFY COLUMN seat INT UNIQUE;
# ②表级约束
ALTER TABLE stuinfo ADD UNIQUE(seat);
# 5、添加外键约束(foreign key)
ALTER TABLE stuinfo ADD FOREIGN KEY(majorId) REFERENCES major(id);# 三、修改表时删除约束
# 1、删除非空约束(not null)
ALTER TABLE stuinfo MODIFY COLUMN stuName VARCHAR(20) NULL;
# 2、删除默认约束(default)
ALTER TABLE stuinfo MODIFY COLUMN age INT NULL;
# 3、删除主键约束(primary key)
ALTER TABLE stuinfo  MODIFY COLUMN id INT NULL;
ALTER TABLE stuinfo DROP PRIMARY KEY;#两种方法
# 4、删除唯一约束(unique)
ALTER TABLE stuinfo MODIFY COLUMN seat INT NULL;
ALTER TABLE stuinfo DROP INDEX seat;#两种方法
# 5、删除外键约束(foreign key)
ALTER TABLE stuinfo MODIFY COLUMN majorId INT NULL;
ALTER TABLE stuinfo DROP FOREIGN KEY majorId;
#-------------------------------------练习练习练习---------------------------------------
CREATE TABLE IF NOT EXISTS emp2(id INT);
# 1、向表emp2的id列中添加primary key约束(称为my_emp_id_pk)
ALTER TABLE emp2 ADD CONSTRAINT my_emp_id_pk PRIMARY KEY(id);
# 2、向表dept2的department_id列中添加primary key约束(称为my_dept_id_pk)
ALTER TABLE dept2 ADD CONSISTENT my_dept_id_pk PRIMARY KEY(department_id);
# 3、向表emp2中添加列dept_id,并在其中定义foreign key约束,与之相关联的列是dept2表中的department_id列
ALTER TABLE emp2 ADD COLUMN dept_id INT;
ALTER TABLE emp2 ADD FOREIGN KEY(dept_id) REFERENCES dept2(department_id);
/*位置        支持的约束类型               是否可以起约束名
列级约束:   列的后面       语法都支持,外键没有效果     不可以
表级约束:   所有列的下面   默认和非空不支持,其他支持   可以(主键没有效果)
*/
#---------------------------------------------------------------------------------------

十一、标识列

# 标识列
/* 又称为自增长列含义:可以不用手动插入值,系统提供默认的序列值(步长为1)特点:1、标识列只能和主键、外键带Key的搭配2、一张表最多只能有一个标识列3、只能对数值型设置标识列4、标识列可以通过SET auto_increment_increment=3设置步长(可手动设置起始值)*/
# 一、创建表时设置标识列
CREATE TABLE tab_identify(id INT PRIMARY KEY AUTO_INCREMENT,#AUTO_INCREMENT设置标识列NAME VARCHAR(20),seat INT);
# 本来重复插入id=1的值会报错,现在插入会自动将id排序(auto_increment增量)
INSERT INTO tab_identify VALUES(NULL,'john');
INSERT INTO tab_identify(NAME) VALUES('lucy');# 或SHOW VARIABLES LIKE '%auto_increment%';#显示值的详细信息,increment为步长,offset为起始值
# increment步长改为3,上面的id以步长为3自动排序。要改起始值则改最初的values值即可
SET auto_increment_increment=3;# 二、修改表时设置标识列
CREATE TABLE tab_identify2(id INT,#创建表NAME VARCHAR(20),seat INT);ALTER TABLE tab_identify2 MODIFY COLUMN id INT PRIMARY KEY AUTO_INCREMENT;#修改标识列# 三、修改表时删除标识列
ALTER TABLE tab_identify2 MODIFY COLUMN id INT;#删除标识列
#---------------------------------------------------------------------------------------

十二、事务

# TCL 事务控制语言
/*
事务的含义:一个或一组sql语句组成一个执行单元,这个执行单元要么全部执行,要么全部不执行案例:转账(张三丰给郭襄转账500元)
张三丰:1000元
郭襄:1000元update 表 set 张三丰的余额=500 where name=‘张三丰’; ①
update 表 set 郭襄的余额=1500 where name=‘郭襄’;    ②
事务就是让上面的①和②代码同时执行或同时不执行。
(不能第①条执行后产生意外使第②条不执行,前者扣款后者却没收到款)事务的属性:1、原子性:要么都发生,要么都不发生2、一致性:必须使数据库从一个一致性状态变换到另外一个一致性状态3、隔离性:事务的执行不能被其他事务干扰,各个事务之间也互不干扰4、持久性:一个事务被提交,它对数据库中数据的改变是永久性的事务的创建
隐式事务:事务没有明显的开启和结束的标记(如select、update、delete语句等)
显示事务:事务具有明显的开启和结束的标记前提:必须先设置自动提交功能为禁用 set autocommit=0;开启:步骤1set autocommit=0;start transaction;步骤2编写事务中的sql语句(select、insert、delete、update)语句1;语句2;...步骤3结束事务commit;提交事务rollback;回滚事务savepoint 节点名; 设置节点/保存点事务的隔离级别:
read uncommitted; 出现脏读、幻读、不可重复读都可隔离
read committed; 不隔离脏读,隔离幻读和不可重复读(Oracle默认)
repeatable read;  隔离幻读(mysql默认)
serializable 无法隔离
*/
# 查看Mysql的存储引擎,主流的有InnoDB、MEMORY、MyISAM(其中只有InnoDB支持事务)
SHOW ENGINES;
# 查询autocommit信息,其中为on说明原事务已开启
SHOW VARIABLES LIKE 'autocommit';
# set命令设置原事务禁止,其中off说明原事务已禁止
SET autocommit=0;
SHOW VARIABLES LIKE 'autocommit';# 1、演示事务使用步骤
CREATE TABLE account(id INT PRIMARY KEY AUTO_INCREMENT,username VARCHAR(25),balance DOUBLE);
ALTER TABLE account CONVERT TO CHARACTER SET gbk COLLATE gbk_chinese_ci;# 改username列的编码
SHOW FULL COLUMNS FROM account;# 查看编码convert to character set collate
INSERT INTO account(username,balance) VALUES ('张无忌',1000),('赵敏',1000);
# 步骤1 开启事务
SET autocommit=0;
START TRANSACTION;
# 步骤2 编写事务
UPDATE account SET balance = 500 WHERE username = '张无忌';
UPDATE account SET balance = 1500 WHERE username = '赵敏';
# 步骤3 结束事务
COMMIT; #或用回滚rollback# 2、事务的隔离级别设置
SELECT @@tx_isolation; # 查看隔离级别
SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;# 设置级别为READ UNCOMMITTED(读未提交)
SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;# 设置级别为READ COMMITTED(读已提交)
SET GLOBAL TRANSACTION ISOLATION LEVEL READ COMMITTED; # 设置数据库系统的全局的隔离级别# 3、演示savepoint的使用
SET autocommit=0;
START TRANSACTION;
DELETE FROM account WHERE id=25;
SAVEPOINT a; # savepoint设置保存点
DELETE FROM account WHERE id=29;
ROLLBACK TO a; #回滚到保存点处# 4、delete和truncate在事务使用时的区别
# 演示delete(执行回滚,可撤销)
SET autocommit=0
START TRANSACTION;
DELETE FROM account;
ROLLBACK;
# 演示truancate(不执行回滚,全删,不可撤销)
SET autocommit=0
START TRANSACTION;
TRUNCATE TABLE account;
ROLLBACK;
#---------------------------------------------------------------------------------------

十三、视图


# 视图
/*
含义:虚拟的表,和普通表一样使用(临时的)应用场景:1、多个地方用到同样的查询结果2、该查询结果使用的sql语句较复杂时创建视图:create view 视图名 as 查询语句视图和表的区别:创建语法的关键字    是否实际占用空间         使用
视图    create view         只保存了sql逻辑   一般不能增删改表  create table        保存了数据              可以增删改
*/# 一、创建和使用视图
# 查询姓张的学生名和专业名
SELECT `stuName`,`majorName`
FROM stuinfo s
INNER JOIN major m
ON m.`id`=s.`majorID`
WHERE s.`stuName` LIKE '张%';
# 封装为视图
CREATE VIEW v1
AS
(SELECT `stuName`,`majorName`
FROM stuinfo s
INNER JOIN major m
ON m.`id`=s.`majorID`); # 括号内为视图,起名为v1
# 使用视图
SELECT * FROM v1 WHERE s.`stuName` LIKE '张%';# 查询姓名中包含a字符的员工名、部门名和工种信息
# 创建视图
CREATE VIEW myv1
AS
(SELECT e.`last_name`,d.`department_name`,j.`job_title`
FROM employees e JOIN `departments` d
ON e.`department_id`=d.`department_id`
JOIN jobs j
ON j.`job_id`=e.`job_id`);
# 使用视图
SELECT * FROM myv1 WHERE `last_name` LIKE '%a%';# 查询各部门的平均工资级别
# ①创建视图查看每个部门的平均工资
CREATE VIEW myv2
AS
SELECT AVG(`salary`) ag FROM employees GROUP BY `department_id`;
# ②使用视图
SELECT myv2.`ag`,g.`grade_level`
FROM `job_grades` g JOIN myv2
ON myv2.`ag` BETWEEN g.`lowest_sal` AND g.`highest_sal`;# 查询平均工资最低的部门信息
# 创建视图
CREATE VIEW myv3
AS
SELECT AVG(`salary`),`department_id`
FROM employees GROUP BY `department_id`
ORDER BY AVG(`salary`)
LIMIT 1;
# 使用视图
SELECT d.* FROM departments d JOIN myv3
ON d.`department_id`=myv3.`department_id`;# 二、修改视图
/* 方式一: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`;# myv3存在,故修改
/*方式二:alter view 视图名 as 查询语句;
*/
ALTER VIEW myv3
AS
SELECT * FROM employees;# 三、删除视图
/*
语法:drop view 视图名,视图名...;
*/
DROP VIEW myv1,myv2,myv3;# 四、查看视图
DESC myv3;# 或
SHOW CREATE VIEW myv3;# 五、视图的更新(很少用)
CREATE OR REPLACE VIEW myv4
AS
SELECT `last_name`,`email`
FROM employees;
# 1、插入数据
INSERT INTO myv4 VALUES('张飞','zf@qq.com');#同时会对原始表更改
# 2、修改数据
UPDATE myv4 SET `last_name`='张无忌' WHERE `last_name`='张飞';#同时会对原始表更改
# 3、删除数据
DELETE FROM myv4 WHERE `last_name`='张无忌';#同时会对原始表更改
/* 具备以下特点的视图不能更新:包含以下关键字的sql语句:分组函数、distinct、group by、having、union或union all常量视图select中包含子查询joinfrom一个不能更新的视图where子句的子查询引用了from子句中的表
*/
#-------------------------------练习练习练习---------------------------------------------
# 创建视图emp_v1,要求出现电话号码以011开头的员工姓名、工资和邮箱
CREATE OR REPLACE VIEW emp_v1
AS
SELECT `last_name`,`salary`,`email`
FROM employees
WHERE `phone_number` LIKE '011%';
# 创建视图emp_v2,要求出现部门的最高工资高于12000的部门信息
CREATE OR REPLACE VIEW emp_v2
AS
SELECT d.*
FROM departments d
JOIN (SELECT MAX(`salary`) g,`department_id`FROM employeesGROUP BY `department_id`) ag
ON d.`department_id`=ag.`department_id`
WHERE ag.g>12000;
# 创建book表
CREATE TABLE book (bid INT PRIMARY KEY,bname VARCHAR(20) NOT NULL UNIQUE,price FLOAT DEFAULT 10,btypeID INT,FOREIGN KEY(btypeID) REFERENCES bookType(id));
# 开启事务,向表中插入一行数据并结束
SET autocommitted=0;
START TRANSACTION;
INSERT INTO book VALUES(1,'小李飞刀',100,1);
COMMENT;# 或rollback;
# 创建视图,出现价格大于100的书名和类型名
CREATE VIEW myv1
AS
SELECT `bname`,`name`
FROM books b
JOIN bookType t
ON b.id=t.id
WHERE price>100;
# 修改视图
ALTER VIEW myv1
AS
SELECT bname,price
FROM books
WHERE price BETWEEN 90 AND 120;
# 删除视图
DROP VIEW myv1;
#---------------------------------------------------------------------------------------

十四、变量

#变量
/*
系统变量:由系统提供,不是自己定义的变量全局变量 global作用域:服务器每次启动将为所有的全局变量赋初始值,针对所有连接有效,但重启会恢复会话变量 session作用域:仅仅针对当前连接有效自定义变量:自己定义的变量用户变量作用域:仅仅针对当前连接有效局部变量  作用域:仅仅在定义它的begin end中有效
*/# 一、系统变量
#1、查看所有系统变量
SHOW GLOBAL VARIABLES; #查询全局变量
SHOW SESSION VARIABLES;#查询会话变量#2、查看满足条件的系统变量
SHOW GLOBAL VARIABLES LIKE '%char%'; #注意是like不是where#3、查看指定的某个系统变量的值
#select @@global|session.系统变量名;
SELECT @@global.autocommit;
SELECT @@tx_isolation;#4、为某个系统变量赋值(跨连接有效)
#(如果是全局级别,则需要加global,如果是会话级别,可不写session,默认为session)
#方式一:set global|session 系统变量名=值;
SET autocommit=0;
#方式二:set @@global|session.系统变量名=值;
SET @@global.autocommit=0;#二、自定义变量
/*  用户变量
使用步骤:①声明:  set @用户变量名=值;set @用户变量名:=值;select @用户变量名:=值;(以上三种任意一种都可以)②赋值:  set @用户变量名=值;set @用户变量名:=值;select @用户变量名:=值;(与上同)select 字段 into @变量名 from 表名;③使用(查看、比较、运算等):select @用户变量名;应用在任何地方,也就是begin end里面或begin end外面
*/
#1、用户变量
#①声明并初始化
SET @name='john';
SET @name=100;SET @count=1;
#②赋值
SELECT COUNT(*) INTO @count FROM employees;
#③使用
SELECT @count;/* 局部变量
使用步骤:①声明:  declare 局部变量名 类型;declare 局部变量名 类型 default 值;(值类型与类型相同)②赋值:  set 局部变量名=值;set 局部变量名:=值;select @局部变量名:=值;(与上同)select 字段 into @变量名 from 表名;③使用(查看、比较、运算等):select 局部变量名;应用在begin end中的第一句话!!!
*/# 声明两个变量并赋初始值,求和并打印
# 1、用户变量方式
SET @m=1;
SET @n=2;
SET @sum=@m+@n;
SELECT @sum;
# 2、用局部变量方式(declare 宣布)
DECLARE m INT DEFAULT 1;
DECLARE n INT DEFAULT 2;
DECLARE SUM INT;
SET SUM = m+n;
SELECT SUM;# 代码报错,原因是没有放在begin end中# 声明两个变量,并拼接打印出来
SET @m='w';
SET @n='d';
SET @sum=CONCAT(@n,@m);
SELECT @sum;
#--------------------------------------------------------------------------------

十五、存储过程

# 存储过程(相当于自己创建的方法)
/*好处:1、提高代码的重用性2、简化操作3、减少了编译次数并且减少了和数据库服务器的连接次数,提高效率存储过程:一组预先编译好的SQL语句的集合、理解成批处理语句
*//*一、创建语法
create procedure 存储过程名(参数列表)
begin 存储过程体,一组合法的SQL语句
end;
注意:
1、参数列表包括三部分:参数模式   参数名     参数类型比如:   in      stuname   varchar(20)
参数模式:
in:该参数可以作为输入,也就是说该参数需要调用方法传入值
out:该参数可以作为输出,也就是可以作为返回值
inout:该参数即可以作为输入也可以作为输出2、如果存储过程体仅仅只有一句话,begin end可以省略
存储过程体中每条SQL语句的结尾要求必须加分号;
存储过程的结尾可以使用delimiter重新设置
语法:delimiter 结束标记如:delimiter $
*/#二、调用语法
#CALL 存储过程名(实参列表)# 1、参数列表为空
# 插入到admin表中五条记录(在cmd运行)
DELIMITER $ #设置结束标记(不再用分号结束)
CREATE PROCEDURE myp1()
BEGININSERT INTO admin(username,PASSWORD) VALUES('john',0000),('lily',0000),('rose',0000),('jack',0000),('tom',0000);
END $
# 调用
CALL myp1()$;
# 查看
SELECT * FROM admin $# 2、创建带in模式参数的存储过程
# 创建存储过程,实现:根据女神名,查询对应的男神信息
DELIMITER $
CREATE PROCEDURE myp2(IN beautyName VARCHAR(20))
BEGINSELECT bo.* FROM boys bo JOIN beauty b ON bo.`id`=b.`boyfriend_id`WHERE b.name=beautyName;
END $
# 调用
SET NAMES gbk $ #更改编码为gbk
CALL myp2('柳岩') $# 创建存储过程实现:用户是否登录成功(多参数,两个in)
DELIMITER $
CREATE PROCEDURE myp3(IN username VARCHAR(20),IN PASSWORD VARCHAR(20))
BEGINDECLARE result INT DEFAULT 0;#声明变量result(详细见上一章节)SELECT COUNT(*) INTO result#赋值FROM admin aWHERE a.username=usernameAND a.password=PASSWORD;SELECT IF(result>0,'成功','失败');#使用
END $
# 调用
CALL myp3('john','0000')$# 3、创建带out模式参数的存储过程
# 根据(in)女神名,返回(out)对应的男神名
CREATE PROCEDURE myp5(IN beautyName VARCHAR(20), OUT boyname VARCHAR(20))
BEGIN   SELECT bo.`boyName` INTO boynameFROM boys bo JOIN beauty bON bo.`id`=b.`boyfriend_id`WHERE b.`name`=beautyName;
END $
# 调用
SET @bName$#变量声明
CALL myp5('小昭',@bName)$
SELECT @bName$#查看# 根据(in)女神名,返回对应的男神名和魅力值(多参数,两个out)
CREATE PROCEDURE myp6(IN beautyname VARCHAR(20),OUT boyname VARCHAR(20),OUT userCP INT)
BEGINSELECT bo.`boyName`,bo.`userCP` INTO boyname,userCPFROM boys bo JOIN beauty bON bo.`id`=b.`boyfriend_id`WHERE b.`name`=beautyname;#in在where后连接参数,out在select后连接参数
END $
# 调用
SET @bName$
SET @userCP$
CALL myp6('小昭',@bName,@userCP)$
SELECT @bName,@userCP$ #查看结果# 4、创建带inout模式参数的存储过程
# 传入a和b两个值,最终a和b都翻倍并返回
CREATE PROCEDURE myp8(INOUT a INT,INOUT b INT)
BEGINSET a=a*2;SET b=b*2;
END $
# 调用
SET @m=10$
SET @n=20$
CALL myp8(@m,@n)$
SELECT @m,@n$ #查看结果# 三、删除语法(一次只能删一个)
/* 语法:drop procedure 存储过程名; */
DROP PROCEDURE myp1;
DROP PROCEDURE myp1,myp2; # 错误,不能多个同时删除# 四、查看存储过程的信息
/* 语法:show create procedure 存储过程名; */
SHOW CREATE PROCEDURE myp3;
#-----------------------------------------练习练习练习-----------------------------------
# 1、创建存储过程实现传入用户名和密码,插入到admin表中
CREATE PROCEDURE test_pro1(IN username VARCHAR(20),IN loginPwd VARCHAR(20))
BEGININSERT INTO admin(admin.`username`,`password`) VALUES(username,loginPwd);
END $
# 调用
CALL test_pro1('john','0000')$
# 查看结果
SELECT * FROM admin$# 2、创建存储过程实现传入女神编号,返回女神名和女神电话
CREATE PROCEDURE test_pro2(IN beautyID INT,OUT beautyName VARCHAR(50),OUT bphone VARCHAR(20))
BEGINSELECT b.`name`,b.`phone` INTO beautyName,bphoneFROM beauty bWHERE b.id=beautyID;
END $
# 调用
CALL test_pro2(1,@m,@n)$
# 查看结果
SELECT @m,@n$# 3、创建存储过程实现传入两个女神生日,返回大小
CREATE PROCEDURE test_pro3(IN beauty_date1 DATETIME,IN beauty_date2 DATETIME,OUT result INT)
BEGINSELECT DATEDIFF(beauty_date2,beauty_date1) INTO result;
END $
# 调用
CALL test_pro3('1998-1-1',NOW(),@m)$
# 查看结果
SELECT @m $# 4、创建存储过程实现传入一个日期,格式化成xx年xx月xx日并返回
CREATE PROCEDURE test_pro4(IN mydate DATETIME,OUT strDate VARCHAR(50))
BEGINSELECT DATE_FORMAT(mydate,'%y年%m月%d日') INTO strDate;
END $
# 调用
CALL test_pro4(NOW(),@m)$
# 查看结果
SELECT @m $               # 5、创建存储过程实现传入女神名,返回:女神 AND 男神 格式的字符串
CREATE PROCEDURE test_pro5(IN beautyName VARCHAR(20),OUT str VARCHAR(50))
BEGINSELECT CONCAT(beautyName,' AND ',IFNULL(boyName,'null')) INTO strFROM boys bo RIGHT JOIN beauty bON bo.`id`=b.`boyfriend_id`WHERE b.`name`=beautyName;
END $
# 调用
CALL test_pro5('小昭',@m)$
# 查看结果
SELECT @m$# 6、创建存储过程,根据传入的起始索引和条目数,查询beauty表的记录
CREATE PROCEDURE test_pro6(IN startIndex INT,IN size INT)
BEGINSELECT * FROM beauty LIMIT startIndex,size;
END $
# 调用
CALL test_pro6(3,5)$ #第3行之后的5条记录
#---------------------------------------------------------------------------------------

十六、函数

# 函数(相当于自定义函数)
/*好处:1、提高代码的重用性2、简化操作3、减少了编译次数并且减少了和数据库服务器的连接次数,提高效率含义:一组预先编译好的SQL语句的集合、理解成批处理语句与存储过程的区别:存储过程:可以有0个返回,也可以有多个返回,适合批量的插入或更新(进行增删改)函数:有且仅有1个返回,适合处理数据后返回一个具体结果(进行具体计算返回值)(函数是可以嵌入在sql中使用的,可以在select中调用,而存储过程不行)
*//*一、创建语法
create function 函数名(参数列表) returns 返回类型
begin函数体
end注意:
1、参数列表包含两部分:参数名  参数类型2、函数体:肯定会有return语句  return 值;
(如果return语句没有放在函数体的最后也不报错,但不建议这么做)3、函数体中仅有一句话,则可以省略begin end
4、使用delimiter语句设置结束标记
*/# 二、调用语法
# select 函数名(参数列表)# 1、无参有返回
# 返回公司的员工个数
DELIMITER $
CREATE FUNCTION myf1() RETURNS INT
BEGIN DECLARE c INT DEFAULT 0; #局部变量声明SELECT COUNT(*) INTO c#变量赋值FROM employees; RETURN c;#返回结果
END $
# 调用
SELECT myf1()$# 2、有参有返回
# 根据员工名,返回他的工资
CREATE FUNCTION myf2(empName VARCHAR(25)) RETURNS DOUBLE
BEGINSET @sal=0; #用户变量声明SELECT salary INTO @sal #赋值FROM employeesWHERE `last_name`=empName;RETURN @sal;#返回结果
END $
# 调用
SELECT myf2('K_ing')$ #由于叫K_ing的有两人,故无法返回(函数只能返回一个结果)
SELECT myf2('Kochhar')$ # 可执行# 根据部门名,返回该部门的平均工资
CREATE FUNCTION myf3(deptName VARCHAR(20)) RETURNS DOUBLE
BEGINDECLARE sal DOUBLE; #用 set @c;也行SELECT AVG(salary) INTO salFROM departments d JOIN employees eON d.`department_id`=e.`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
BEGINDECLARE SUM FLOAT DEFAULT 0;#局部变量声明SELECT SUM=num1+num2; #赋值RETURN SUM;#返回
END $
#调用
SELECT test_fun1(1,2)$
#---------------------------------------------------------------------------------------

十七、流程控制

# 流程控制结构
/*
顺序结构:程序从上往下依次执行分支结构:程序从多条路径中选择一条去执行循环结构:程序在满足一定条件的基础上,重复执行一段代码
*/#一、分支结构
/*1、if函数功能:实现简单是双分支语法:select if(表达式1,表达式2,表达式3)执行顺序:若表达式1成立,则返回表达式2的值,否则返回表达式3的值应用:任何地方  */
/*2、case结构  功能:实现多个等值判断或区间判断语法:方式一:case 要判断的变量、字段或表达式when 要判断的值 then 要返回的值1或语句1;when 要判断的值 then 要返回的值2或语句2;...else 要返回的值n或语句n;end  方式二:case when 条件1 then 要返回的值1或语句1when 条件2 then 要返回的值2或语句2...else 要返回的值n或语句n end  特点:①可以作为表达式嵌套在其他语句中使用,可以放在任何地方(begin end中或begin end外)可以作为独立的语句使用,只能放在begin end中,要显示结果需加select②如果when中的值或条件成立,则执行对应的then后面的语句,并且结束case如果都不满足,则执行else中的语句或值③else可以省略,如果else省略了,且所有when条件都不满足,则返回null
*//* 创建存储过程,根据传入的成绩,来显示等级
比如传入的成绩:90-100显示A80-90显示B60-80显示C否则显示D  */
DELIMITER $
CREATE PROCEDURE test_case(IN score INT)
BEGINCASE # case前无selectWHEN score>=90 AND score<=100 THEN SELECT 'A';#注意这里要加selectWHEN score>=80 THEN SELECT 'B'; WHEN score>=60 THEN SELECT 'C';ELSE SELECT 'D'END CASE;
END $
# 调用
CALL test_case(95)$/*3、if结构功能:实现多重分支语法:if 条件1 then 语句1;elseif 条件2 then 语句2;...else 语句n;end if;应用:只能用在begin end中   *//*根据传入的成绩,来返回等级
比如传入的成绩:90-100返回A80-90返回B60-80返回C否则返回D  */
CREATE FUNCTION test_if(score INT) RETURNS CHAR #char类型
BEGINIF score>=90 AND score<=100 THEN RETURN 'A';#注意这里加returnELSEIF score>=80 THEN RETURN 'B';ELSEIF score>=60 THEN RETURN 'C';ELSE RETURN 'D';END IF;
END $
# 调用
SELECT test_if(86)$#二、循环结构
/*分类:while、loop、repeat循环控制:iterate:类型与continue,结束本次循环,继续下一次leave:类似于break,跳出,结束当前所在的循环
*/ #1、while(先判断后执行)
/*
语法:(如果要加循环控制,就要起标签)
【标签:】while 循环条件 do 循环体;end while 【标签】;   */#2、loop
/*
语法:
【标签:】loop   循环体;end loop 【标签】;(可以用来模拟简单的死循环)    */#3、repeat(先执行后判断)
/*
语法:
【标签:】repeat循环体;until 结束循环的条件end repeat 【标签】;   */# 批量插入,根据次数插入到admin表中多条记录(没有添加循环控制)
CREATE PROCEDURE pro_while1(IN insertCount INT)
BEGINDECLARE i INT DEFAULT 1;#局部变量声明WHILE i<=insertCount DOINSERT INTO admin(`username`,`password`) VALUES(CONCAT('Rose',i),'666');SET i=i+1;END WHILE;
END $
# 调用
CALL pro_while1(100)$# 批量插入,根据次数插入到admin表中多条记录,如果次数>20则停止(添加leave循环控制)
CREATE PROCEDURE pro_while2(IN insertCount INT)
BEGINDECLARE i INT DEFAULT 1;a:WHILE i<=insertCount DOINSERT INTO admin(`username`,`password`) VALUES(CONCAT('xiaohua',i),'0000');IF i>=20 THEN LEAVE a; # leave相当于break结束循环,注意加标签END IF;SET i=i+1;END WHILE a;
END $
# 调用
CALL pro_whlie2(100)$# 批量插入,根据次数插入到admin表中多条记录,只插入偶数次(添加iterate循环控制)
CREATE PROCEDURE pro_while3(IN insertCount INT)
BEGINDECLARE i INT DEFAULT 0;a:WHILE i<=insertCount DOSET i=i+1;IF MOD(i,2)<>0 THEN ITERATE a;# iterate跳过这次循环继续下次循环END IF;INSERT INTO admin(`username`,`password`) VALUES(CONCAT('xiaohua',i),'0000');       END WHILE a;
END $
# 调用
CALL pro_while3(100)$
#---------------------------------------练习练习练习-------------------------------------
/*一、已知表stringcontent其中字段:id 自增长content varchar(20)向该表插入指定个数的随机的字符串 */
CREATE TABLE IF NOT EXISTS stringcontent (id INT PRIMARY KEY AUTO_INCREMENT,content VARCHAR(20));
DELIMITER $
CREATE PROCEDURE test_randstr_insert(IN insertCount INT)
BEGINDECLARE i INT DEFAULT 1;#定义一个循环变量1,表示插入次数DECLARE str VARCHAR(26) DEFAULT 'abcdefghijklmnopqrstuvwxyz';DECLARE startIndex INT DEFAULT 1;#代表起始索引DECLARE len INT DEFAULT 1;#代表截取的字符长度WHILE i<=insertCount DOSET len=FLOOR(RAND()*(20-startIndex+1)+1);#产生一个随机整数,代表截取长度,1-(26-startIndex+1)SET startIndex=FLOOR(RAND()*26+1);#产生一个随机整数,代表起始索引1-26(rand()随机函数包含0不包含1)INSERT INTO stringcontent(content) VALUES (SUBSTR(str,startIndex,len));SET i=i+1;#循环变量更新END WHILE;
END $
# 调用
CALL test_randstr_insert(10)$
# 查看结果
SELECT * FROM `stringcontent`$
#---------------------------------------------------------------------------------------

MySQL入门代码(附案例)相关推荐

  1. python爬虫入门 - 代码、案例集合

    python爬虫入门 - 代码.案例集合 资源案例 · 统计 · 如下: 10个Python爬虫入门实例 以上就是关于"python爬虫入门 - 代码.案例集合"的全部内容.

  2. 阿里云学生服务器购买以及使用入门教程(附案例学习)

    最新版本的阿里云学生服务器该名称为:轻量应用服务器 虽然改名字了,但是还是以前的阿里云学生服务器.这次不仅改名称了,价格降低了(以前是1年114元,现在是1年96元),配置也更好了(以前配置是1核2G ...

  3. jQuery入门基础-附案例

    文章目录 预备知识与后续知识及项目案例 为什么要学jquery jQuery介绍 JavaScript 库 jQuery的概念 jQuery的优点 体验jquery的使用 jquery到底是什么 jq ...

  4. unity3d排行榜mysql_Unity3D 连接MySql数据库(附案例)

    Unity3D 连接MySql数据库 一.在Mac OS X中架设MySql数据库 下载mysql for Mac http://dev.mysql.com/downloads/mysql/5.0.h ...

  5. dpf linux安装db2_值得一看!数据库及Mysql入门,附详细安装教程

    #什么是数据 用来描述事物的符号记录.可以是数字.文字.图形等,有多种形式,经过数字化之后存入计算机 #什么是数据库 数据库(Database)就是一个用来存放数据库的仓库,是按照一定的数据结构来组织 ...

  6. mysql序列号生成_值得一看!数据库及Mysql入门,附详细安装教程

    #什么是数据 用来描述事物的符号记录.可以是数字.文字.图形等,有多种形式,经过数字化之后存入计算机 #什么是数据库 数据库(Database)就是一个用来存放数据库的仓库,是按照一定的数据结构来组织 ...

  7. PHP导入excel到mysql数据库完整代码附效果图

    微信小程序开发交流qq群   173683895    承接微信小程序开发.扫码加微信. 1.新建一个数据库  ImportXlsx 并在里面添加表名  IsXlsx. 2.下载 phpExcel 插 ...

  8. JQuery 入门 - 附案例代码

    文章目录 预备知识与后续知识及项目案例 为什么要学jquery 体验jquery的使用 jquery到底是什么 jquery的版本问题 jquery的入口函数 jq对象和dom对象(重要) jquer ...

  9. python爬虫简单实例-最简单的Python爬虫案例,看得懂说明你已入门,附赠教程

    原标题:最简单的Python爬虫案例,看得懂说明你已入门,附赠教程 这是最简单的Python爬虫案例,如果你能看懂,那么请你保持信心,因为你已经入门Python爬虫,只要带着信心和努力,你的技术能力在 ...

最新文章

  1. [物理学与PDEs]第2章第5节 一维流体力学方程组的 Lagrange 形式 5.1 引言
  2. mysql对数据库进行备份吗_怎么对MySQL数据库进行备份与恢复
  3. 京东产品负责人:数据如何高效驱动供应链?
  4. linux 访客日志ip,shell统计ip访问情况,要求分析访问日志分析。
  5. pythondjango搭建数据管理平台,使用Django快速搭建简单的数据管理后台
  6. ArcGIS导入Sketchup模型
  7. [渝粤教育] 西南科技大学 西方经济学 在线考试复习资料
  8. [react] react怎么拿到组件对应的DOM元素?
  9. 六、PyQt5 QTreeWidget操作,获取树控件所有2级目录内容
  10. 程序设计基础(C语言)
  11. asp.net关于上传文件修改文件名的方法
  12. jquery 把元素移动到另外一个元素里面
  13. springboot 多线程_从零开始到架构,800页Java+并发+容器+多线程+高并发+Spring+SpringBoot源码...
  14. MySQL春节收支表怎么建立_怎样才能建一个收支表格?
  15. 【论文解读--Xdog】(宇树科技鼻祖)新型电驱式四足机器人研制与测试
  16. Word去除多余的页眉
  17. Looking for the Devil in the Details
  18. 用python做一个飞机大战(一)
  19. antd4使用form表单
  20. Opencv3基础操作3——图像形态学处理

热门文章

  1. Linkedin领英怎么导出非好友电话、邮箱等资料
  2. vue+axios+echarts实现一个折线图
  3. 热点项目|近期Github热门项目Top5
  4. CISP-PTE2021最新考试经验
  5. 怎样强制修改笔记本密码
  6. 早起的故事-为什么早起?怎么早起?早起做什么?
  7. 基于prometheus的网络指标监控
  8. 西门子人机界面产品的常见问题
  9. Asio Reactor-Style Operations
  10. Qt 使用QAxWidget操作 ppt