MYSQL学习笔记

前言

这是我自学mysql入门_尚硅谷过程中做的笔记,里面包括mysql基础的知识点和代码演示案例,老师用的数据库表等材料材料b站视频的评论区可以找到,第一次发笔记,就直接一次性发出来了,以后会更新一些学习笔记的,希望能和大家一起交流学习。

数据库好处

  • 实现数据持久化
  • 使用完整的管理系统统一管理,易于查询

数据库的相关概念

  • DB:数据库(database):储存数据的"仓库"。它保存了一系列有组织的数据

  • DBMS:数据库管理系统(Database Management System),又称数据库软件,用于管理DB中的数据

    • 常见的数据库管理系统有:MySQL、Oracle、DB2、SqlServer等
    • 程序员通过数据库管理系统对数据库进行增删改查等操作
  • SQL:结构化查询语言(Structure Query Language),专门用来和数据库通信的语言

    • SQL的优点:

      1. 不是某个特定数据库供应商专有的语言,几乎所有DBMS都支持SQL
      2. 简单易学
      3. 一种强有力的语言,灵活使用其语言元素,可以进行非常复杂和高级的数据库操作

数据库的特点

  1. 将数据放到表中,表再放到库中
  2. 一个数据库中有多个表,每个表有一个名字,用来表示自己。表名具有唯一性。
  3. 表具有一些特性,这些特性定义了数据在表中如何存储,类似java中"类"的设计
  4. 表由列组成,我们也称为字段。所有表都是由一个或多个列组成的,每一列类似java中的”属性“
  5. 表中的数据是按照行存储的,每一行类似于java中的“对象”

MySQL软件介绍

  • 优点:

    1. 成本低:开源,一般开源免费试用
    2. 性能高:执行很快
    3. 简单:很容易安装和使用
  • DBMS分为两类:

    • 基于共享文件系统DBMS(Access)
    • 基于客户机——服务器的DBMS(MySQL,Oracle,SqlServer)
      • 安装数据库,一般指安装在服务端

MySQL软件的安装

  • 安装完成后,可以在my.ini里更改配置
    • 端口
    • 安装目录
    • 数据库目录
    • 字符集
    • 存储引擎
    • 语法模式
    • 最大连接数
  • 改完之后记得重新启动数据库

MySQL服务的启动和停止

  • 方式1:(适用于windows系统)计算机右键-管理-服务和应用程序-服务-mysql的服务名(根据安装时的设定而异)右键可以启动,关闭,还可以在属性选项修改启动方式。
  • 方式2:(命令行)
    • 以管理员权限启动cmd
      • 输入命令net stop (mysql的服务名)停止
      • 输入命令net start (mysql的服务名)启动

MySQL客户端的登录和退出

  • 方式1(只适用于root用户):
    • 进入:通过mysql自带的客户端(command line client),输入密码
    • 退出:输入exit或 ctrl+c
  • 方式2(通过命令行)
    • 进入:输入命令mysql -h localhost -P 3306 -u root -p
      • 其中-h后接连接的主机名(host),-P后面接端口号(Port) ,-u后面接用户名(user),-p 代表使用密码进入(可以接密码,但和p之间不能有空格,其他几个对空格不做要求)
      • 命令可以简写为mysql -u root -p
    • 退出:输入exit或Ctrl+c

MySQL的常见命令

  • 每条命令的结尾加;或/g
  1. show databases;显示数据库

  2. mysql自带的4个数据库、

    information_schema:保存源数据信息
    mysql:保存用户信息的
    performance_schema:收集性能信息,参数
    test:测试数据库(空的),可以修改,其他三个不可以修改
    
    
  3. use 数据库名;:打开数据库

  4. show tables;:显示目前打开的数据库的表

  5. show tables from 数据库名;:显示指定数据库的表(不出打开的数据库)

  6. select database();:显示目前打开的数据库

  7. desc 表名;:显示表的结构(查看属性,类型等)

  8. create table 表名(列名 列类型,列名 列类型,。。。);

p12节

查询数据库服务器版本号:

  • 方式1:mysql命令里输入 select version();
  • 方式2:在命令行内输入mysql --versionmysql --V

MYSQL语法规范

  1. 不区分大小写,但建议关键字大写,表名列名小写
  2. 每条命令最好用分号结尾
  3. 每条命令根据需要,可以进行缩进换行(建议关键字后面换行)
  4. 注释
    • 单行注释:#注释文字
    • 单行注释-- 注释文字 (注意空格)
    • 多行注释:/*注释文字 */

DQL语言学习

进阶1:基础查询

#进阶1:基础查询
/*
语法:
select 查询列表
from 表名;

类似于System.out.println(打印内容)

特点:
1、查询列表可以是:表中的字段、常量值、表达式、函数
2、查询的结果是一个虚拟的表格
*/

USE myemployees;

#1.查询表中的单个字段

SELECT last_name FROM employees;

#2.查询表中的多个字段
SELECT last_name,salary,email FROM employees;

#3.查询表中的所有字段
SELECT 
  `employee_id`,
  `first_name`,
  `last_name`,
  `email`,
  `phone_number`,
  `job_id`,
  `salary`,
  `commission_pct`,
  `manager_id`,
  `department_id`,
  `hiredate` 
FROM
  employees ;
#着重号表示是字段,不是关键字

SELECT * FROM employees;#显示不能调整字段顺序

#4.查询常量值
SELECT 100;
SELECT 'john';

#5.查询表达式
SELECT  100*98;
SELECT  100%98;

#6.查询函数
# SELECT 函数名(实参列表);
SELECT VERSION();

#7.起别名
/*
(1)便于理解
(2)如果要查询的字段有重名的情况,使用别名区别

*/
 #方式一:使用AS
SELECT 100%98 AS 结果;
SELECT last_name AS,first_name ASFROM employees;
 #方式二:使用空格
SELECT last_name 姓,first_name 名 FROM employees;

#案例: 查询salary,显示结果为output
SELECT salary AS "out put" FROM employees;

#8.去重

#案例:查询员工表中设计的所有部门编号
SELECT DISTINCT department_id FROM employees;

#9.+的作用

/*
mysql中+号
仅仅只有一个功能:运算符

select 100+90; 两个操作数都为数值型,则做加法运算
select '123'+90;其中一方为字符型,试图将字符串数组转换为数值型
		如果转换成功,继续做加法,(这里'123'转换为123)
		如果转换失败,则将字符型数组转换成0.
select 'john'+90;

select null+100; 只要其中一方为null,则结果为null

*/

#案例:查询员工名和姓连接成一个字段,并显示为 姓名
SELECT CONCAT('a','b','c') AS 结果;

SELECT 
  CONCAT(last_name, first_name) AS 姓名 
FROM
  employees ;


  • 课程补充:
    1. 着重符号可以区分字段名和关键字,加着重号的表示字段名
    2. select后面加的字符型和日期型的常量值必须用单引号引起来,数值型不需要
    3. 想要执行命令,要先选中相应命令,再点击执行(或F9)。格式化命令也同理,快捷键是F12.
    4. 查询函数就是调用方法,得到返回值(比如 select version())
    5. 起别名时,别名中有空格等特殊字符时,加双引号括起来
    6. 执行函数必须用select,不能直接函数名(参数);
    7. 几个函数补充
      1. concat函数:拼接字符
      2. ifnull函数:判断某字符或表达式是否为null,如果为null返回制定的值,否则返回原本的值
      3. isnull函数:判断某字段或表达式是否为null,是返回1,否则返回0

进阶2:条件查询

#进阶2:条件查询
/*
语法:
	select 
		查询列表    (步骤3)
	from
		表名        (步骤1)
	where 
		筛选条件;   (步骤2)
		
分类:
	一、按条件表达式筛选
	条件运算符:> < = != <>(推荐) >= <=
	二、按逻辑表达式筛选
	逻辑运算符:
		&& || !
		and or not (推荐)
	三、模糊查询
		like
		between and (not between and)
		in
		iS null (is not null)
*/
#一、按条件表达式筛选

#案例1:查询工资>12000的员工信息

SELECT
	*
FROM
	employees
WHERE
	salary>12000;

#案例2:查询部门编号不等于90号的员工名和部门编号
SELECT
	last_name,
	department_id
FROM
	employees
WHERE
	department_id <> 90;
	
#二、按逻辑表达式筛选

#案例1:查询工资在100000到20000之间的员工名,工资以及奖金
SELECT
	last_name,
	salary,
	commission_pct
FROM
	employees
WHERE
	salary>=10000 AND salary<=20000;
	
#案例2:查询部门编号不是在90到110之间,或工资高于15000的员工信息
SELECT
	*
FROM
	employees
WHERE
	NOT (department_id>=90 AND department_id<=110) OR salary >=15000;
	
#三、模糊查询
/*
like
特点:
(1)一般和通配符搭配使用
	通配符:
	% 任意多个字符(也可能是0字符)
	_任意单个字符

bewteen and
in
is null|is not null
*/

#1.like
#like也可以查询数值型,比如like '1__'

#案例1:查询员工名中包含a的员工信息

SELECT
	*
FROM
	employees
WHERE
	last_name LIKE '%a%';

#案例2:查询员工名中第三个字符为n,第五个字符为l的员工名和工资
SELECT
	last_name,salary
FROM
	employees
WHERE
	last_name LIKE '__n_l%'
	
#案例3:查询员工名中第二个字符为_的员工名

SELECT
	last_name
FROM
	employees
WHERE
	last_name LIKE '_\_%';
	#last_name LIKE '_$_%' ESCAPE '$';

#2.between and
/*
(1)提高了语言的整洁度
(2)包含临界值
(3)两个临界值不要调换位置
*/
#案例1:员工编号在100到120之间的员工信息

SELECT
	*
FROM
	employees
WHERE
	employee_id >= 100 AND employee_id <=120;
#+---------------------------------------------
SELECT
	*
FROM
	employees
WHERE
	employee_id BETWEEN 100 AND 120;
	
#3.in
/*
含义:判断某字段是否属于in列表中的某一项
特点:
	(1)使用in提高语言简洁度
	(2)in列表的值类型必须一致或兼容

*/
#案例:查询员工的工种编号是 IT_PROG,ADVP,AD_PRES 的一个员工名和工种编号

SELECT
	last_name,
	job_id
FROM
	employees
WHERE
	job_id = 'IT_PROG' OR job_id = 'AD_VP' OR job_id = 'AD_PRES';
	
#------------------------------------
SELECT
	last_name,
	job_id
FROM
	employees
WHERE
	job_id IN ('IT_PROG' , 'AD_VP' , 'AD_PRES');
	
#4.is null
/*
=或<>不能用于判断null值
is null或is not null可以判断null
*/
#案例1:没有奖金的员工名和奖金率
SELECT 
	last_name,
	commission_pct
FROM
	employees
WHERE
	commission_pct IS NULL;
	
#案例2:有奖金的员工名和奖金率
SELECT 
	last_name,
	commission_pct
FROM
	employees
WHERE
	commission_pct IS NOT NULL;	

#---------------------------以下为错误
SELECT 
	last_name,
	commission_pct
FROM
	employees
WHERE
	salary IS 12000;	
	
#安全等于  <=>

#案例1:没有奖金的员工名和奖金率
SELECT 
	last_name,
	commission_pct
FROM
	employees
WHERE
	commission_pct <=> NULL;
	
#案例2:查询工资为12000的员工信息
SELECT 
	last_name,
	salary
FROM
	employees
WHERE
	salary <=> 12000;
	
#is null pk <=>
/*
is null:仅仅可以判断null值,可读性较高(建议)
<=>    :既可以判断null值,又可以判断普通的数值,可读性较低
*/

  • 课程补充:
    1. 等于号运算符(=)不能判断null值,要判断是否是null要用is null
    2. is null的否定为is not nullbetween and 的否定为 not between and
    3. like 进行判断时 如果字段包含null,则进行比对时’%%’和null时不匹配的

进阶3:排序查询

  1. 引入,对输出的表格要求对某个字段进行排序显示
#进阶3:排序查询

/*
引入:
	select * from employees;

语法:
	select 查询列表               (3)
	from 表                       (1)
	【where 筛选条件】            (2)
	order by 排序列表 【asc|desc】(4)
	
特点:
	1、asc代表升序,desc降序
	如果不写,默认是升序
	2、order by子句中可以支持单个字段,多个字段,表达式,函数,别名
	3、order by子句一般是放在查询语句的最后面,limit子句除外
	
*/

#案例1:查询员工信息,要求工资从高到低

SELECT * FROM employees ORDER BY salary DESC;
#升序
SELECT * FROM employees ORDER BY salary ASC;
SELECT * FROM employees ORDER BY salary;

#案例2:查询部门编号>=90的员工的信息,按入职时间先后进行查询

SELECT *
FROM employees
WHERE department_id>=90
ORDER BY hiredate;

#案例3:按年薪的高低显示员工的信息和年薪【按表达式排序】

SELECT *,salary*12*(1+IFNULL(commission_pct,0)) AS 年薪
FROM employees
ORDER BY salary*12*(1+IFNULL(commission_pct,0)) DESC;

#案例4:按年薪的高低显示员工的信息和年薪【按别名排序】

SELECT *,salary*12*(1+IFNULL(commission_pct,0)) AS 年薪
FROM employees
ORDER BY 年薪 DESC;

#案例5:按姓名的长度显示员工的姓名和工资【按函数排序】

SELECT LENGTH(last_name) 字节长度,last_name,salary
FROM employees
ORDER BY LENGTH(last_name) DESC;

#案例6:查询员工信息,先按工资升序,再按员工编号降序【按多个字段排序】

SELECT *
FROM employees
ORDER BY salary ASC,employee_id DESC;

进阶4:常见函数

笔记
#进阶4:常见函数1

/*

概念:类似于java的方法,将一组逻辑语句封装在方法体重,对外暴露方法名
好处:1、隐藏了实现细节 2、提高了代码的重用性
调用:select 函数名(实参列表) 【from 表】;
特点:
	(1)函数名
	(2)函数功能
分类:
	1、单行函数
	如:concat、length、ifnull等
	2、分行函数
	
	功能:做统计使用,又称为统计函数,聚合函数,组函数
	
常见函数:
	字符函数
	length
	concat
	substr
	instr
	trim
	upper
	lower
	lpad
	rpad
	replace
	
	数学函数:
	round
	ceil
	floor
	truncate
	mod
	
	日期函数:
	now
	curdate
	curtime
	year
	month
	monthname 以英文形式返回月
	day
	hour
	minute
	second
	str_to_date
	dateformat
	其他函数
	version
	database
	user
	password('字符')返回该字符的密码加密形式
	md5('字符')返回该字符的md5加密形式
	控制函数
	if
	case
	
*/
#一、字符函数

#1.length 获取参数值的[字节]个数
SELECT LENGTH('join');
SELECT LENGTH('张三丰hahaha');

SHOW VARIABLES LIKE '%char%';

#2.concat 拼接字符串

SELECT CONCAT(last_name,'_',first_name)
FROM employees;

#3.upper、lower
SELECT UPPER('john');
SELECT LOWER('joHN');
#示例:将姓变大写,名变小写,然后拼接
SELECT CONCAT(UPPER(last_name),LOWER(first_name)) 姓名 FROM employees;

#4.substr/substring
#注意索引从1开始
#截取从指定索引处后面所有字符
SELECT SUBSTR('李莫愁爱上了陆展元',7) out_put;
#截取从指定索引处指定字符长度的字符
SELECT SUBSTR('李莫愁爱上了陆展元',1,3) out_put;

#案例:姓名中首字符大写,其他字符小写,然后用_Z拼接

SELECT CONCAT(UPPER(SUBSTR(last_name,1,1)),'_',LOWER(SUBSTR(last_name,2)))
FROM employees;

#5.instr 返回子串出现的第一次索引,如果找不到返回0

SELECT INSTR('杨不悔爱上了殷六侠  殷六侠','殷六侠') AS out_put;

SELECT INSTR('杨不悔爱上了殷六侠  殷六侠','殷八侠') AS out_put;

#6.trim 去掉开头结尾重复的空格或字符(需指定)

SELECT LENGTH(TRIM('    张翠山    ')) AS out_put;

SELECT TRIM('a' FROM 'aaaaaa张aaaa翠山aaaaaa');

#7.lpad 用指定的字符实现左填充指定长度
SELECT LPAD('殷素素',10,'*') AS out_put;
#长度不足显示两个
SELECT LPAD('殷素素',2,'*') AS out_put;

#8.rpad 用指定的字符实现右填充指定长度

SELECT RPAD('殷素素',10,'ab') AS out_put;

#9.replace 替换

SELECT REPLACE('张无忌爱上了周芷若周芷若周芷若','周芷若','赵敏') AS out_put;

#二、数学函数

#round 四舍五入
SELECT ROUND(1.65);
SELECT ROUND(1.45);
SELECT ROUND(-1.45);
SELECT ROUND(-1.5);
#保留几位小数
SELECT ROUND(1.567,2);

#ceil向上取整,返回>=该参数的最小整数

SELECT CEIL(1.02);
SELECT CEIL(-1.02);

#floor 向下取整,返回<=该参数的最大整数
SELECT FLOOR(-9.99);

#truncate 截断

SELECT TRUNCATE(1.69,1);

#mod 取余
/*
注:(被除数为正,结果为正,被除数为负,结果为负)
mod(a,b): a-a/b*b
*/
SELECT MOD(10,3);
SELECT 10%3;

#三、日期函数

#now 返回当前系统日期+时间
SELECT NOW();

#curdate 返回当前系统日期,不包含时间
SELECT CURDATE();

#curtime 返回当前的时间,不包含日期
SELECT CURTIME();

#可以获取指定的部分,年、月、日、小时、分钟、秒
SELECT YEAR(NOW());
SELECT YEAR('1998-1-1');

SELECT YEAR(hiredate)FROM employees;

SELECT MONTH(NOW());
SELECT MONTHNAME(NOW());

#str_to_date将字符通过指定的格式转换为日期

SELECT STR_TO_DATE('1998-3-2','%Y-%c%d') AS out_put;

#查询入职日期为1992-4-3的员工信息
SELECT * FROM employees WHERE hiredate = '1992-4-3';
SELECT * FROM employees WHERE hiredate = STR_TO_DATE('4-3 1992','%c-%d %Y');

#date_format 将日期转换为字符

SELECT DATE_FORMAT(NOW(),'%y年%m月%d日') AS out_put;

#查询有奖金的员工名和入职日期(xx月/xx日 xx年)

SELECT 
	last_name 员工名,
	DATE_FORMAT(hiredate,'%m月/%d日 %y年') 入职日期
FROM
	employees
WHERE commission_pct IS NOT NULL;

#其他函数

SELECT VERSION();
SELECT DATABASE();

#五、流程控制函数
#1.if函数(成立返回第一个,不成立返回第二个)

SELECT IF(10>5,'大','小');

SELECT last_name,IF(commission_pct IS NULL,'没有奖金','有奖金') 奖金
FROM employees;

#2.case函数的使用一:switch case的效果
/*
java中
switch(变量或表达式){
	case 常量1:语句1;break;
	。。。
	default:语句n;break;
}
mysql中

case 要判断的字段或表达式
when 常量1 then 要显示的值1或语句1;
when 常量2 then 要显示的值2或语句2;
...
else 要显示的值n或语句n;
end
*/

/*案例:查询员工的工资,要求

部门号=30,显示的工资为1.1倍
部门号=40,显示的工资为1.2倍
部门号=50,显示的工资为1.3倍
其他部门,显示的工资为原工资
*/

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 工资
FROM employees;

#3.case函数的使用二:类似于多重if
/*
java中
if(条件1){
	语句1
}else if(条件2){
	语句2;
}
else{
	语句n;
}

mysql中:
case
when 条件1 then 要显示的值1或语句1;
when 条件2 then 要显示的值2或语句2;
...
else 要显示的值n或语句n
end
*/

/*案例:查询员工的工资情况

如果工资>20000,显示A级别
如果工资>15000,显示B级别
如果工资>10000,显示c级别
否则,显示D级别
*/

SELECT salary,
CASE
WHEN salary>20000 THEN 'A'
WHEN salary>15000 THEN 'B'
WHEN salary>10000 THEN 'C'
ELSE 'D' 
END 工资级别
FROM employees;

#二、分组函数
/*
功能:用作统计使用,又称为聚合函数或统计函数或组函数

分类:
sum 求和、avg 平均值、max 最大值 、min 最小值、count 计算个数

特点:
1、sum、avg一般用于处理数值型
   max、min、count可以处理任何类型
2、以上分组函数都忽略null值

3、可以和distinct搭配实现去重的运算

4、count函数的单独介绍
一般使用count(*)用作统计行数

5、和分组函数一同查询的字段要求是group by后的字段



*/

#1、简单的使用
SELECT SUM(salary) FROM employees;
SELECT AVG(salary) FROM employees;
SELECT MIN(salary) FROM employees;
SELECT MAX(salary) FROM employees;
SELECT COUNT(salary) FROM employees;


SELECT SUM(salary),ROUND(AVG(salary),2) 平均,MAX(salary) 最高,MIN(salary) 最低,COUNT(salary) 个数
FROM employees;

#2、参数类型支持那些类型
#sum 和 avg 用字符型参数没有意义

#max可以用于日期,字母排序
SELECT MAX(last_name),MIN(last_name) FROM employees;
SELECT MAX(hiredate),MIN(hiredate) FROM employees;

#count数不为null的个数
SELECT COUNT(commission_pct) FROM employees;
SELECT COUNT(last_name) FROM employees;

#3、是否忽略null

SELECT SUM(commission_pct),AVG(commission_pct),SUM(commission_pct)/35,SUM(commission_pct)/107 FROM employees;
#说明sum和avg都忽略null值
SELECT MAX(commission_pct),MIN(commission_pct) FROM employees;
#max和min也忽略

#4、和distinct搭配

SELECT SUM(DISTINCT salary),SUM(salary) FROM employees;

SELECT COUNT(DISTINCT salary),COUNT(salary) FROM employees;

#5、count函数的详细介绍

SELECT COUNT(salary) FROM employees;
#一般用来统计行数
SELECT COUNT(*) FROM employees;

SELECT COUNT(1) FROM employees;

/*
效率:
MYISAM(5.5版本之前)存储引擎下,count(*)的效率高
INNODB存储引擎下,count(*)和count(1)的效率差不多,比count(字段)快,
因为字段需要筛选出非null的
*/

#6、和分组函数一同查询的字段有限制(表格不规则)

SELECT AVG(salary),employee_id FROM employees;
补充
  1. str_to_date:将日期格式的字符转换为指定格式的日期

  2. date_format:将日期格式转换为字符

  3. 序号	格式符	功能
    1	%Y	四位的年份
    2	%y	2位的年份
    3	%m	月份(01,02,03,..11,12)
    4	%c	月份(1,2,3,,11,12)
    5	%d	日(01,02)
    6	%H	小时(24小时制)
    7	%h	小时(12小时制)
    8	%i	分钟(00,01..59)
    9	%s	秒(00,01...59)
    
  4. datediff:计算前面的时间减去后面的时间,例如下

  5. select datediff('2017-10-1','2017-9-29'); #计算天数之差
    select datediff(now(),你的生日); #计算你活了多少天
    

进阶5:分组查询

笔记
#进阶5:分组查询
/*
语法:
	select 分组函数,列(要求出现在group by的后面)
	from 表
	【where 筛选条件】
	group by 分组的列表
	【order by 子句】
注意:
	查询列表必须特殊,要求是分组函数和group by后出现的字段
	
特点:
	1、分组查询中的筛选条件分为两类
			数据源不一样		位置			关键字
	分组前筛选	原始表			group by子句的前面	where
	分组后筛选	分组后的结果集		group by子句的后面	having
	
	(1)分组函数做条件肯定是放在having子句中
	(2)能用分组前筛选的优先考虑使用分组前筛选
	2、group by子句支持单个字符分组,多个字段分组(多个字段之间用逗号隔开没有顺序要求),表达式或函数(用的较少)
	3、也可以添加排序(排序房子啊整个分组查询的最后)
*/

#引入:查询每个部门的平均工资

#简单的分组查询
#案例1:查询每个工种的最高工资
SELECT MAX(salary),job_id
FROM employees
GROUP BY job_id;

#案例2:查询每位置上的部门个数
SELECT COUNT(*), location_id
FROM departments
GROUP BY location_id;

#添加分组前的筛选条件
#案例1:查询邮箱中包含a字符的,每个部门的平均工资
SELECT AVG(salary) ,department_id
FROM employees
WHERE email LIKE '%a%'
GROUP BY department_id;

#案例2:查询有奖金的每个领导手下员工的最高工资
SELECT MAX(salary),manager_id
FROM employees
WHERE commission_pct IS NOT NULL
GROUP BY manager_id;

#添加分组后的筛选条件

#案例1:查询那个部门的员工个数>2

#(1)查询每个部门的员工个数
SELECT COUNT(*),department_id
FROM employees
GROUP BY department_id;
#(2)根据(1)的结果进行筛选,查询哪个部门的员工个数>2
SELECT COUNT(*),department_id
FROM employees
GROUP BY department_id
HAVING COUNT(*)>2;

#案例2:查询每个工种有奖金的员工的最高工资>12000的工种编号和最高工资
SELECT MAX(salary) 最高工资,job_id 工种编号
FROM employees
WHERE commission_pct IS NOT NULL
GROUP BY job_id
HAVING 最高工资>12000;


#案例3:查询领导编号>102的每个领导手下的最低工资>5000的领导编号是哪个,以及最低工资
SELECT MIN(salary) 最低工资,manager_id 领导编号
FROM employees
WHERE manager_id > 102
GROUP BY manager_id
HAVING 最低工资>5000;

#按表达式或函数分组

#案例:按员工姓名的长度分组,查询每一组员工的个数,筛选员工个数>5的有哪些
SELECT LENGTH(last_name) 姓名长度,COUNT(*) 员工个数
FROM employees
GROUP BY LENGTH(last_name)
HAVING COUNT(*)>5;


SELECT LENGTH(last_name) 姓名长度,COUNT(*) 员工个数

#按多个字段分组

#案例:查询每个部门每个工种的员工的平均工资

SELECT AVG(salary),department_id,job_id
FROM employees
#group by department_id,job_id;
GROUP BY job_id,department_id;
#上面两条的结果一样,排序不一样,第一个按department_id顺序,第二个按job_id顺序

FROM employees
GROUP BY 姓名长度
HAVING 员工个数>5;
#上面group by和having后面可以用别名代替(oracle等数据库不支持用别名代替,mysql可以),where不可用代替
#order by必然可以加别名

#添加排序

#案例:查询每个部门每个工种的员工的平均工资,并按平均工资的高低显示,再外加一些条件

SELECT AVG(salary),department_id,job_id
FROM employees
WHERE department_id IS NOT NULL
GROUP BY department_id,job_id
HAVING AVG(salary)>10000
ORDER BY AVG(salary) DESC;

进阶6:连接查询

笔记
#进阶6:连接查询
/*
含义:又称为多表查询,当查询的字段涉及多个表时,就会用到连接查询

笛卡尔乘积现象:表1 有m行,表2有n行,结果=m*n行

发生原因:没有添加有效的连接条件
如何避免:添加有效的连接条件

分类:
	按年代分类:
	sql92标准:仅仅支持内连接
	sql99标准【推荐】:内连接+外连接(左外和右外)+交叉连接
	
	按功能分类:
		内连接:
			等值连接
			非等值连接
			自连接
		外连接
			左外连接
			右外连接
			全外连接
		
		交叉连接

*/

SELECT * FROM beauty;
DESC beauty;

SELECT * FROM boys;
 
 
SELECT `name`,`boyName` FROM boys,beauty
WHERE beauty.boyfriend_id=boys.id;

#一、sql92标准
#1、等值连接
/*
(1)多表等值连接的结果为多表的交集部分
(2)n表连接,至少需要n-1个连接条件
(3)多表的顺序没有要求
(4)一般需要为表起别名
(5)可以搭配前面介绍的所有子句使用,比如排序、分组、筛选
*/

#案例1:查询女神名和对应的男神名
SELECT `name`,`boyName`
FROM boys, beauty
WHERE beauty.`boyfriend_id`=boys.`id`;

#案例2:查询员工名和对应的部门名

SELECT last_name,department_name
FROM employees,departments
WHERE employees.`department_id`=departments.`department_id`;

#2、为表起别名
/*
(1)提高语句的简洁度
(2)区分多个重名的字段

注意:如果为表起了别名,则查询的字段就不能使用原来的表名去限定
*/
#查询员工名、工种号、工种名
SELECT e.last_name,e.job_id,j.job_title
FROM employees e,jobs j
WHERE e.`job_id`=j.`job_id`;

#3、两个表的顺序是否可以调换
#查询员工名、工种号、工种名
SELECT e.last_name,e.job_id,j.job_title
FROM jobs j,employees e
WHERE e.`job_id`=j.`job_id`;


#4、可以加筛选吗(可以)

#案例查询有奖金的员工名、部门名
SELECT last_name,department_name,commission_pct
FROM employees e,departments d
WHERE e.`department_id`=d.`department_id`
AND e.`commission_pct` IS NOT  NULL;

#案例2:查询城市名中第二个字符为o的部门名和城市名
SELECT department_name,city
FROM departments d,locations l
WHERE d.`location_id`=l.`location_id` 
AND city LIKE '_o%';

#5、可以加分组?

#案例1:查询每个城市的部门个数

SELECT COUNT(*),city
FROM departments d,locations l
WHERE d.`location_id`=l.`location_id`
GROUP BY city;

#案例2:查询有奖金的每个部门的部门名和该部门的领导编号和该部的最低工资
SELECT department_name,d.manager_id,MIN(salary)
FROM departments d,employees e
WHERE e.`department_id`=d.`department_id` AND e.`commission_pct` IS NOT NULL
GROUP BY department_name;

SELECT * FROM employees;
SELECT * FROM departments;

#6、可以加排序

#案例:查询每个工种名和员工的个数,并且按照员工的个数降序

SELECT job_title,COUNT(*)
FROM jobs j,employees e
WHERE e.`job_id`=j.`job_id`
GROUP BY job_title 
ORDER BY COUNT(*) DESC;

#7、可以实现三表连接
#查询员工名,部门名和所在的城市

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`
AND city LIKE 's%'
ORDER BY department_name DESC;

#2、非等值连接

#案例1:查询员工的工资和工资级别

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';


CREATE TABLE job_grades
(grade_level VARCHAR(3),
 lowest_sal  INT,
 highest_sal INT);

INSERT INTO job_grades
VALUES ('A', 1000, 2999);

INSERT INTO job_grades
VALUES ('B', 3000, 5999);

INSERT INTO job_grades
VALUES('C', 6000, 9999);

INSERT INTO job_grades
VALUES('D', 10000, 14999);

INSERT INTO job_grades
VALUES('E', 15000, 24999);

INSERT INTO job_grades
VALUES('F', 25000, 40000);

SELECT  * FROM job_grades;

#3、自连接

#案例:查询员工名和上级的名称

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`;



#进阶6:连接查询2
#二、sql99语法
/*
语法:
	select 查询列表
	from 表1 别名 【连接类型】
	join 表2 别名
	on 连接条件
	【where 筛选条件】
	【group by 分组】
	【having 筛选条件】
	【order by 排序列表】
	
分类:
内连接(重点):inner
外连接
	左外(重点):left【outer】
	右外(重点):right【outer】
	全外:full 【outer】
交叉连接:cross

*/

#一)内连接
/*
语法

select 查询列表
from 表1 别名
inner join 表2 别名
on 连接条件;

分类:
等值
非等值
自连接

特点:
(1)添加排序、分组、筛选
(2)inner可以省略
(3)筛选条件放在where后面,连接条件放在on后面,提高分离性,便于阅读
(4)inner join连接和sql92语法中的连接效果是一样的,都是查询多表的交集



*/

#1、等值连接

#案例1:查询员工名、部门名

SELECT last_name,department_name
FROM employees e
INNER JOIN departments d
ON e.`department_id`=d.`department_id`;

#案例2:查询名字中包含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、查询部门个数>3的城市名和部门个数(添加分组+筛选)

SELECT city,COUNT(*) 部门个数
FROM departments d
INNER JOIN locations l
ON d.`location_id`=l.`location_id`
GROUP BY city
HAVING COUNT(*)>3;

#案例4:查询那个部门的员工个数>3的部门名和员工个数,并按个数排序(添加排序)
SELECT department_name,COUNT(*) 员工个数
FROM departments d
INNER JOIN employees e
ON e.`department_id`=d.`department_id`
GROUP BY department_name
HAVING COUNT(*)>3
ORDER BY COUNT(*)

#案例5:查询员工名、部门名、工种名,并按部门名排序(添加三表连接)

SELECT last_name,department_name,job_title
FROM employees e
INNER JOIN departments d ON e.`department_id`=d.`department_id`
INNER JOIN jobs j ON e.`job_id`=j.`job_id`
ORDER BY department_name DESC;

#二)非等值连接

#查询员工的工资级别

SELECT last_name,salary,grade_level
FROM employees e
INNER JOIN job_grades g ON e.salary BETWEEN g.lowest_sal AND g.highest_sal;

#查询每个工资级别的个数>2的个数,并且按工资级别降序

SELECT COUNT(*) 个数, grade_level
FROM employees e
INNER 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
INNER JOIN employees m
ON e.`manager_id`=m.`employee_id`
WHERE e.`last_name` LIKE '%k%';

#二、外连接
/*
应用场景:用于查询一个表中有,另一个表中更没有的记录

特点:
1、外连接的查询结果为主表中的所有记录
	如果从表中有和它匹配的,则显示null
	如果从表中没有和它匹配的,则显示null
	外连接查询结果=内连接结果+主表中有而从表没有的记录
2、左外连接,left左边的是主表
   右外连接,right join右边的是主表
3、左外和右外交换两个表的顺序可以实现同样的效果
4、全外连接=内连接结果+表1中有但表2没有+表2中有但表1中没有的
*/

#引入:查询没有男朋友的女神名
SELECT * FROM beauty;
SELECT * FROM boys;

#左外连接
SELECT b.name
FROM beauty b
LEFT OUTER JOIN boys bo
ON b.`boyfriend_id`=bo.`id`
WHERE bo.id IS NULL;

#案例1:查询那个部门没有员工
#左外
SELECT department_name
FROM departments d
LEFT OUTER JOIN employees e
ON d.department_id=e.department_id
WHERE e.employee_id IS NULL;

#右外
SELECT department_name
FROM employees e
RIGHT OUTER JOIN departments d
ON d.department_id=e.department_id
WHERE e.employee_id IS NULL;

#全外连接(mysql不支持)

USE grils;
SELECT b.*,bo.*
FROM beauty b
FULL OUTER JOIN boys bo
ON b.`boyfriend_id`=bo.id;

#交叉连接(笛卡尔乘积)

SELECT b.*,bo.*
FROM beauty b
CROSS JOIN boys bo;

#sql92和sql99 pk
/*
功能
sql99支持的较多
可读性:sql99实现的连接条件和筛选条件的分离,可读性较高


*/

进阶7:子查询

笔记
#进阶7:子查询
/*
含义:
出现在其他语句中的select语句,称为子查询或内查询
外部的查询语句,称为主查询或外查询

分类:
案子查询出现的位置分类
	select后面:
		仅仅支持标量子查询
	from后面:
		支持表子查询
	where或having后面:√
		标量子查询(单行)√
		列子查询  (多行)√
		
		行子查询
	exists后面(相关子查询):
		表子查询
按结果集的行列数不同:
	标量子查询(结果集只有一行一列)
	列子查询(结果集只有一列多行)
	行子查询(结果集有一行多列)
	表子查询(结果集,一般为多行多列)
	




*/

#一、where或having后面
/*1、标量子查询(单子查询)
2、列子查询(多行子查询)

3、行子查询(多列多行)

特点:
①子查询放在小括号内
②子查询一般放在条件的右侧
③标量子查询,一般搭配单行操作符
> < >+ <+ = <>
列子查询,一般搭配多行操作符使用
in、any/some、all
④子查询的执行优先于主查询执行,主查询条件用到了子查询的结果

*/

#1、标量子查询

#案例1:谁的工资比阿贝尔高
#①查询Abel工资
SELECT salary
FROM employees
WHERE last_name='Abel';
#②查询员工的信息,满足salary>①结果
SELECT *
FROM employees
WHERE salary>(
	SELECT salary
	FROM employees
	WHERE last_name='Abel'
)

#案例2:返回job_id与141号员工相同,salary比143号员工多的员工 姓名,job_id和工资

#①查询141号员工的job_id
SELECT job_id
FROM employees
WHERE employee_id=141;
#②查询143号员工的salary
SELECT salary
FROM employees
WHERE employee_id=143;
#③查询员工的姓名,job_id和工资,要求job_id=①并且salary>②

SELECT last_name,job_id,salary
FROM employees
WHERE job_id=(
	SELECT job_id
	FROM employees
	WHERE employee_id=141
) AND salary>(
	SELECT salary
	FROM employees
	WHERE employee_id=143
);


#案例3:返回工资最少的员工的last_name,job_id和salary
#①查询公司的最低公司
SELECT MIN(salary)
FROM employees;

#②查询last_name,job_id和salary,要求salary=①
SELECT last_name,job_id,salary
FROM employees
WHERE salary=(
	SELECT MIN(salary)
	FROM employees
);

#案例4:查询最低工资大于50号部门最低工资的部门id和其最低工资
#①查询50号部门的最低工资
SELECT MIN(salary)
FROM employees
WHERE department_id=50;

#②查询每个部门的最低工资,并筛选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
);

#非法使用标量子查询

SELECT MIN(salary),department_id
FROM employees
GROUP BY department_id
HAVING MIN(salary)>(  #只能搭配标量子查询
SELECT salary #这里不是标量
	FROM employees
	WHERE department_id=50
);

SELECT MIN(salary),department_id
FROM employees
GROUP BY department_id
HAVING MIN(salary)>(
SELECT MIN(salary)
	FROM employees
	WHERE department_id=250 #不是一行一列
);

#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)

)

#同理not in可以换成 <>all

#案例2:返回其他工种中比job_id为`IT_PROG`工种任一工资低的员工的员工号,姓名和job_id以及salary

#①查询job_id为`IT_PROG`部门任一工资
SELECT 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 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';

##案例2:返回其他工种中比job_id为`IT_PROG`工种所有工资低的员工的员工号,姓名和job_id以及salary

SELECT last_name,employee_id,job_id,salary
FROM employees
WHERE salary<ALL(
	SELECT 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 *
FROM employees
WHERE (employee_id,salary)=(
	SELECT MIN(employee_id),MAX(salary)
	FROM employees
);

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后面
/*
仅仅支持标量子查询
*/

#案例:查询每个部门的员工个数

SELECT d.*,(
	SELECT COUNT(*)
	FROM employees e
	WHERE e.department_id=d.department_id
) 个数
FROM departments d;


SELECT d.*,COUNT(*)
FROM departments d
LEFT JOIN employees e
ON d.department_id=e.department_id
GROUP BY d.department_id;

#案例2:查询员工号=102的部门名
#别扭,一般可用其他的代替

SELECT(
	SELECT d.department_name
	FROM employees e
	LEFT JOIN departments d
	ON e.`department_id`=d.department_id
	WHERE e.`employee_id`=102
) 部门名;

#三、from后面
/*
将子查询结果充当一张表要求必须起别名
*/
#案例:查询每个部门的平均工资的工资等级

SELECT department_id,AVG(salary)
FROM employees
GROUP BY department_id;

SELECT ag_dep.*,grade_level
FROM (
	SELECT department_id,AVG(salary) ag
	FROM employees
	GROUP BY department_id
) ag_dep
INNER JOIN job_grades g
ON ag_dep.ag BETWEEN lowest_sal AND highest_sal;

/*
自己写的
select department_id,
case
when ag_dep.ag>20000 then 'A'
when ag_dep.ag>15000 then 'B'
when ag_dep.ag>10000 then 'C'
else 'D'
end 工资级别
from (
	SELECT department_id,AVG(salary) ag
	FROM employees
	GROUP BY department_id
) ag_dep;
*/

#四、exists(not exists)后面(相关子查询)(用得少)
/*
语法:
exists(完整的查询语句)
结果:1或0


*/

SELECT EXISTS(SELECT employee_id FROM employees WHERE salary=30000);

#案例1:查询员工的部门名

#in
SELECT department_name
FROM departments d
WHERE d.`department_id` IN(
	SELECT department_id
	FROM employees
)



SELECT department_name
FROM departments d
WHERE EXISTS(
	SELECT *
	FROM employees e
	WHERE d.`department_id`=e.department_id
)

#案例2:查询没有女朋友的男神信息

#in
SELECT bo.boyName
FROM boys bo
WHERE bo.id NOT IN(
	SELECT boyfriend_id
	FROM beauty
);

#exists
SELECT bo.boyName
FROM boys bo
WHERE NOT EXISTS(
	SELECT boyfriend_id
	FROM beauty b
	WHERE b.`boyfriend_id`=bo.`id`
)
感悟
  1. 子查询里的语句千万不要加分号结束(呜呜呜)
  2. 当不确定用in还是=的时候,就用in,因为单行和多行列表都可以

进阶8:分页查询(重点)

笔记
#进阶8:分页查询(重点)
/*
应用场景:当要显示的数据一页显示不全,需要分页提交sql请求
语法:
	select 查询列表
	from 表
	【join type join 表2
	on 连接条件
	where 筛选条件
	group by分组字段
	having 分组的筛选
	order by 排序后的字段】
	limit 【offset,】size;
	
	offset要显示条目的起始索引(起始索引从0开始)
	size 要显示的条目个数
特点:
	①limit语句放在查询语句的最后
	②公式
	要显示的页数 page,每页的条目数size
	
	select 查询列表
	from 表
	limit (page-1)*size,size;
	
	size=10
	page 
	1	0
	2	10
	3	20


*/

#案例1:查询前五条员工信息

SELECT * FROM employees LIMIT 0,5;
#offset=0时可以省略
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 ;

进阶9:联合查询

笔记
#进阶9:联合查询
/*
union 联合 合并:将多条查询语句的结果合并成一个结果

语法:
查询语句1
union
查询语句2
union
。。。。

应用场景:
要查询的结果来自于多个表,且多个表没有直接的连接关系,但查询的信息一致时

特点: √
1、要求多条查询语句的查询列数一致
2、要求多条查询语句查询的每一列的类型和顺序是一致的
3、union关键字默认去重,如果使用union all,可以包换重复项

*/

#引入的案例:查询部门编号大于90或邮箱中包含a的员工信息

SELECT * FROM employees WHERE department_id>90 OR email LIKE '%a%';

SELECT * FROM employees WHERE email LIKE '%a%'
UNION
SELECT * FROM employees WHERE department_id>90

#案例:查询中国用户中男性的信息以及外国用户中年龄>12岁的用户信息
SELECT id,cname,csex FROM t_ca WHERE csex='男'
UNION
SELECT t_id,tName,tGender FROM t_ua WHERE tGender='male'


SELECT id,cname,csex FROM t_ca WHERE csex='男'
UNION ALL
SELECT t_id,tName,tGender FROM t_ua WHERE tGender='male'



DML语言

数据的增删改

笔记
#DML语言
/*
数据操作语言
插入:insert
修改:update
删除:delete

*/

#一、插入语句
#方式一:经典的插入
/*
语法:
insert into 表名(列名,...) values(值1,...);


*/
SELECT * FROM beauty;
#1.插入的值的类型要与列的类型一致或兼容
INSERT INTO beauty(id,NAME,sex,borndate,phone,photo,boyfriend_id)
VALUES(13,'唐艺昕','女','1990-4-23','1898888888',NULL,2)

#2.不可以为null的列必须插入值,可以为null的列如何插入值

#方式一:
INSERT INTO beauty(id,NAME,sex,borndate,phone,photo,boyfriend_id)
VALUES(13,'唐艺昕','女','1990-4-23','1898888888',NULL,2)
#方式二:
INSERT INTO beauty(id,NAME,sex,borndate,phone,boyfriend_id)
VALUES(14,'金星','女','1990-4-23','1398888888',9);

INSERT INTO beauty(id,NAME,sex,phone)
VALUES(15,'娜扎','女','1398888888');

#3.列的顺序可以调换
INSERT INTO beauty(NAME,sex,id,phone)
VALUES('蒋欣','女',16,'110');

#4.列数和值个数必须一致

INSERT INTO beauty(NAME,sex,id,phone)
VALUES('关晓彤','女',17,'110');

#5.可以省略列名,默认所有列,而且列的顺序和表中列的顺序一致

INSERT INTO beauty
VALUES(18,'张飞','男',NULL,'119',NULL,NULL);

#方式二:
/*
语法:
insert into 表名
set 列名=值,列名=值。。

*/

INSERT INTO beauty
SET id=19,NAME='刘涛',phone='999';

#两种方式比较

#1、方式一支持插入多行,方式2不支持

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';

#二、修改语句

/*

1.修改单表的记录 √

语法:
update 表名
set 列=新值,列=新值
where 筛选条件;

2.修改多表的记录【补充】

语法:
sql92语法:
update 表1 别名,表2 别名
set 列=值,...
where 连接条件
and 筛选条件;

sql99语法:
update 表1 别名
inner|left|right join 表2 别名
on 连接条件
set 列=值
where 筛选条件;

*/

#案例1:修改姓唐的女神的电话为13899888899

UPDATE beauty
SET phone='13899888899'
WHERE NAME LIKE '唐%';

#案例2:修改boys表中的id号为2的名称为张飞,魅力值为10
UPDATE boys SET boyname='张飞',usercp=10
WHERE id=2;

#2.修改多表的记录

#案例1:修改张无忌的女朋友手机号为114

UPDATE boys b
INNER JOIN beauty be
ON be.`boyfriend_id`=b.`id`
SET be.phone='114'
WHERE b.boyName='张无忌';

#案例2:修改没有男朋友的女神的女朋友标号都为2

UPDATE  boys bo
RIGHT JOIN beauty b
ON b.`boyfriend_id`=bo.`id`
SET b.`boyfriend_id`=2
WHERE bo.id IS NULL;

#三、删除语句
/*
方式一:delete
语法:
1.单表的删除【√   】
delete from 表名 where 筛选条件

2、多表的删除【补充】
sql92语法
delete 表1的别名,表2的别名
from 表1 别名,表2 别名
where 连接条件
and 筛选条件

sql99语法
delet 表1的别名,表2的别名
from 表1 别名
inner|left|right join 表2 别名 on 连接条件
where 筛选条件
方式二:truncate
语法:truncate table 表名;

*/

#方式一:delete
#1.单表的删除
#案例1:删除手机号以9结尾的女神信息

DELETE FROM beauty
WHERE phone LIKE '%9';

SELECT * FROM beauty;

#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语句
#案例:将魅力值>100的男神删除
TRUNCATE TABLE boys;

#delete 和truncate 比较
/*
1.delete可以加where条件,truncate 不能加

2.truncate删除,效率高一点点
3。假如要删除的表中有自增长列,
如果用delete删除后在插入数据,
自增长列的值从断点开始
4.truncate 删除没有返回值
delete 有返回值(返回受影响的行数)
5.truncate删除不能回滚,delete删除可以回滚
*/

SELECT * FROM boys;

DELETE FROM boys;
TRUNCATE TABLE boys;
INSERT INTO boys (boyname,usercp)
VALUES('张飞',100),('刘备',100),('关云长',100);
补充
  1. 一个库使用另一个库中的表时,可以用库名.表名来访问
  2. delete可以搭配limit使用,语法delete from 表名 【where 筛选条件】【limit 条目数】

DDL语言

库和表的管理

笔记
#DDL


/*

数据定义语言

库和表的管理

一、库的管理
创建、修改、删除
二、表的管理
创建、修改、删除

创建:create
修改:alter
删除:drop


*/

#一、库的管理
#1、库的创建
/*
语法:
create datebase 库名

*/

#案例:创建库Books
CREATE DATABASE Books;

CREATE DATABASE IF NOT EXISTS Books;

#2、库的修改

RENAME DATABASE books TO 新库名;#已废弃

#更改库的字符集

ALTER DATABASE Books CHARACTER SET gbk;

#3、库的删除

DROP DATABASE IF EXISTS Books;

#二、表的管理
#1.表的创建 √
CREATE DATABASE books;
/*
create table 表名(
	列名 列的类型【(长度)约束】,
	列名 列的类型【(长度)约束】,
	列名 列的类型【(长度)约束】,
	......
	列名 列的类型【(长度)约束】
)

*/

#案例:创建表book

CREATE TABLE book(
	id INT,#编号
	bName VARCHAR(20),#图书名
	price DOUBLE,#价格
	authorId VARCHAR(20),#作者编号
	publishDate DATETIME#出版日期

);
DESC book;

#案例:创建表author

CREATE TABLE IF NOT EXISTS author(
	id INT,
	au_name VARCHAR(20),
	nation VARCHAR(10)
);
DESC author;

#2.表的修改
/*
alter table 表名 add|drop|modify|change column 列名 【列类型 约束】
*/

DESC book;
#①修改列名
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 IF EXISTS book_author;

SHOW TABLES;

#通用的写法:
DROP DATABASE IF EXISTS 久库名;
CREATE DATABASE 新库名;

DROP TABLE IF EXISTS 旧表名;
CREATE TABLE 表名();

#4.表的复制
INSERT INTO author VALUES
(1,'村上春树','日本'),
(2,'莫言','中国'),
(3,'冯唐','中国'),
(3,'金庸','中国');

#1.仅仅复制表的结构

CREATE TABLE copy LIKE author;

#2.复制表的结构+数据
CREATE TABLE copy2
SELECT * FROM author;

#只复制部分数据
CREATE TABLE copy3
SELECT id,au_name
FROM author
WHERE nation='中国';

#仅仅复制某些字段

CREATE TABLE copy4
SELECT id,au_name
FROM author
WHERE 0;

补充
  1. 修改表时添加列也可以设置添加顺序,如
alter table 表名 add column 列名 类型 【first|after 字段名】

常见的数据类型

笔记
#常见的数据类型
/*
数值型:
	整型
	小数:
		定点数
		浮点数
字符型:
	较短的文本:char、varchar
	较长的文本:text、blob(较长的二进制数据)
日期型
	
	
*/

#一、整型
/*
分类:
tinyint、smallint、mediumint、int/integer、bigint
1	2		3	4		8

特点:
①如果不设置无符号还是有符号,默认是有符号,如果想设置无符号,需要添加unsigned关键字
②如果插入的数值超出了整型的范围,会报out of range 异常,并插入临界值
③如果不设置长度,会有默认的长度
长度代表了显示的最大宽度,如果不够会用0在左边填充,但必须搭配zerofill使用(zerofill默认无符号)
*/

#1.如何设置无符号和有符号
DROP TABLE tab_int;
CREATE TABLE tab_int(
	t1 INT(7) ZEROFILL,
	t2 INT(7) UNSIGNED
);

DESC tab_int;

INSERT INTO tab_int VALUES(-1);

INSERT INTO tab_int VALUES(-1,-1);
SELECT * FROM tab_int;


INSERT INTO tab_int VALUES(21478634000,41000101000);

INSERT INTO tab_int VALUES(123,123);

#二、小数
/*
1.浮点型
float(M,D)

double(M,D)
2.定点型
dec(M,D)
decimal(M,D)

特点:
①
M:整数部位外加小数部位
D:小数部位
如果超过范围,则插入临界值
②
M和D都可以省略
如果是decimal,则M默认为10,D默认为0
如果是float和double,则会根据插入数值的精度来决定精度
③定点型的精确度较高,如果要求插入数值的精度较高如货币运算则使用
*/

CREATE TABLE tab_float(

	f1 FLOAT(5,2),
	f2 DOUBLE(5,2),
	f3 DECIMAL(5,2)
);


INSERT INTO tab_float VALUES(123.45,123.45,123.45);
INSERT INTO tab_float VALUES(123.456,123.456,123.456);
INSERT INTO tab_float VALUES(1523.45,1523.45,1523.45);
SELECT * FROM tab_float;

DROP TABLE tab_float;
CREATE TABLE tab_float(

	f1 FLOAT,
	f2 DOUBLE,
	f3 DECIMAL
);

INSERT INTO tab_float VALUES(123.456,123.456,123.456);

#原则:
/*
所选的类型越简单越好,能保存数值的类型越小越好

*/

#三、字符型
/*
较短的文本
char
varchar

其他:
binary和varbinary用于保存较短的而二进制
enum用于保存枚举
set用于保存集合

较长的文本:
text
blob(较大的二进制)

特点:
	写法		M的意思				特点			空间的耗费	效率
char	char(M)		最大的字符数可以省略,默认为1	固定长度的字符		比较耗费	高
varchar	varchar(M)	最大的字符数,不可以省略	可变长度的字符		比较节省	低
*/

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');

SELECT * FROM tab_char;

CREATE TABLE tab_set(
	s1 SET('a','b','c','d')

);

INSERT INTO tab_set VALUES('a');
INSERT INTO tab_set VALUES('a,b');
INSERT INTO tab_set VALUES('A,c,d');
SELECT * FROM tab_set;

#日期型
/*

分类:
date只保存日期
time 只保存时间
year 只保存年

datetime 保存日期+时间
timestamp 保存日期+时间


特点:
		字节		范围		时区等的影响
datetime	8		1000-9999	不受
timestamp	4		1970-2038	受



*/

CREATE TABLE tab_date(
	t1 DATETIME,
	t2 TIMESTAMP

);

INSERT INTO tab_date VALUES(NOW(),NOW());

SELECT * FROM tab_date;

SHOW VARIABLES LIKE 'time_zone';

SET time_zone='+9:00';
SET time_zone='system';

常见约束

笔记
#常见约束

/*



含义:一种限制,用于限制表中的数据,为了保证数据的准确和可靠性

分类:六大约束
	NOT NULL:非空,用于保证该字段的值不能为空
	比如姓名、学号等
	DEFAULT:默认,用于保证该字段有默认值
	比如性别
	PRIMARY KEY:主键,用于保证该字段的值具有唯一性,并且非空
	比如学号、员工编号等
	UNIQUE:唯一,用于保证该字段的值具有唯一性,可以为空
	比如座位号
	CHECK:检查约束【mysql中不支持】
	比如年龄、性别
	FOREIGN KEY:外键约束,用于限制两个表的关系,用于保证该字段的值必须来自与主表关联列的值
		在从表添加外键约束,用于引用主表中某列的值
	比如学生表的专业编号,与员工表的部门编号工种编号
	
添加约束的实际:
	1、创建表时
	2、修改表时

约束的添加分类:
	列级约束:
		六大约束语法上都支持,但外键约束没有效果
	表级约束:
		除了非空,默认,其他的都支持


主键和唯一对比:
		保证唯一性	是否允许为空		一个表中可以有多少个	是否允许组合
主键		√		×			至多有一个主键		√,但不推荐
唯一		√		√(只允许一个为空)	可以有多个唯一		√,但不推荐
	
这里是否能够组合的意思是组合的两个键不能同时相同,定义方法如下
	CONSTRAINT pk PRIMARY KEY(id,stuname),#主键
	
外键:
	1、要求在从表设置外键关系
	2、从表的外键类型和主表的关联列的类型一致或兼容,名称无要求
	3、主表的关联列必须是一个key(一般是主键或唯一键)
	4、插入数据时,先插入主表,再插入从表
	删除数据时,先删除从表,再删除主表
*/

CREATE TABLE 表名(
	字段名 字段类型 列级约束,
	字段名 类型,
	表级约束
)

CREATE DATABASE students;
#一、创建表时添加约束

#1.添加列级约束
/*
语法:

直接在字段名和类型后面追加 约束类型即可

只支持:默认、非空、主键、唯一

一个列可添加多个约束,用空格隔开即可


*/

USE students;

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)

);

DESC stuinfo;
#查看stuinfo表中所有的索引,包括主键、外键、唯一
SHOW INDEX FROM stuinfo;

#2.添加表级约束

/*

语法:在各个字段的最下面
【constraint 约束名】 约束类型(字段名)

*/

DROP TABLE IF EXISTS stuinfo;
CREATE TABLE stuinfo(
	id INT,
	stuname VARCHAR(20),
	gender CHAR(1),
	seat INT,
	age INT,
	majorid INT,
	
	CONSTRAINT pk PRIMARY KEY(id),#主键
	CONSTRAINT uq UNIQUE(seat),#唯一键
	CONSTRAINT ck CHECK(gender IN ('男','女')),#检查
	CONSTRAINT fk_stuinfo_major FOREIGN KEY(majorid) REFERENCES major(id)#外键
);

SHOW INDEX FROM stuinfo;

#通用的写法

CREATE TABLE IF NOT EXISTS stuinfo(
	id INT PRIMARY KEY,
	stuname VARCHAR(20) NOT NULL,
	sex CHAR(1),
	age INT DEFAULT 18,
	seat INT UNIQUE,
	majorid INT,
	CONSTRAINT fk_stuinfo_major FOREIGN KEY(majorid) REFERENCES major(id)
);

#二、修改表时添加约束
/*
1.添加列级约束
alter table 表名 modify column 字段名 字段类型 新约束;

2.添加表级约束
alter table 表名 add 【constraint 约束名】 约束类型(字段名) 【外键的引用】

*/
DROP TABLE IF EXISTS stuinfo;
CREATE TABLE stuinfo(
	id INT,
	stuname VARCHAR(20),
	gender CHAR(1),
	seat INT,
	age INT,
	majorid INT
);
DESC stuinfo;
#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 MODIFY COLUMN id INT;#这句话没用

ALTER TABLE stuinfo DROP PRIMARY KEY;
#4.删除唯一
ALTER TABLE stuinfo DROP INDEX seat;
#5.删除外键
ALTER TABLE stuinfo DROP FOREIGN KEY fk_stuinfo_major;
SHOW INDEX FROM stuinfo;



/*
		位置		支持的约束类型			是否可以起约束名
列级约束:	列的后面	语法都支持,但外键没有效果	不可以
表级约束	所有列的下面	默认和非空不支持,其他支持	可以(主键没有效果)

*/

补充
  1. 在外键的主表中,若想删除一行,可以通过以下两种方式
    • 级联删除(删除主表行的同时删除从表相应的行)
      • ALTER TABLE stuinfo ADD CONSTRAINT fk_stu_major FOREIGN KEY(majorid) REFERENCES major(id) ON DELETE CASCADE;
    • 级联置空(删除主表的同时,把从表的外键值改为null)
      • ALTER TABLE stuinfo ADD CONSTRAINT fk_stu_major FOREIGN KEY(majorid) REFERENCES major(id) ON DELETE SET NULL;

标识列

笔记
#标识列
/*
又称为自增长列
含义:可以不用手动的插入值,系统提供默认的序列值

特点:
1、标识列必须和主键搭配吗?不一定,但要求是一个key(主键,唯一)
2、一个表可以有多少标识列?至多一个!
3、标识列的类型只能是数值型
4、标识列可以通过 SET auto_increment_increment=3;设置步长
也可通过手动插入值设置起始值

*/
#一、创建表时设置标识列
DROP TABLE IF EXISTS tab_identity;
CREATE TABLE tab_identity(
	id INT PRIMARY KEY AUTO_INCREMENT,
	NAME VARCHAR(20)
);
TRUNCATE TABLE tab_identity;
INSERT INTO tab_identity VALUES(NULL,'john');
INSERT INTO tab_identity(NAME) VALUES('lucy');

SELECT * FROM tab_identity;

#步长,偏移量
SHOW VARIABLES LIKE 'auto_increment%';
#步长这样设置
SET auto_increment_increment=3;
SET auto_increment_increment=1;
#不支持修改偏移量,但可以这么改(例子中可以从100开始)
INSERT INTO tab_identity VALUES(100,'john');

#二、修改表时设置标识列

DROP TABLE IF EXISTS tab_identity;
CREATE TABLE tab_identity(
	id INT,
	NAME VARCHAR(20)
);

ALTER TABLE tab_identity MODIFY COLUMN id INT PRIMARY KEY AUTO_INCREMENT;

#修改表时删除标识列
ALTER TABLE tab_identity MODIFY COLUMN id INT;

TCL语言

  • 事务
    • 定义:事务由单独单元的一个或多个SQL语句组成,在这个单元中,每个MySQL语句是相互依赖的。
    • ACID属性(面试题):
      • 原子性(Atomicity):原子性是指事务是个不可分割的工作单位,事务中的操作要么都发生,要么都不发生。
      • 一致性(Consistency):事务必须使数据库从一个一致性状态变换到另外一个一致性状态
      • 隔离性(Isolation):事务的隔离性是指一个事务的执行不能被其他事务干扰,即一个事务内部的操作及使用的数据对并发的其他事务是隔离的,并发执行的各个事务之间不能互相干扰。
      • 持久性(Durability):持久性是指一个事务一旦被提交,它对数据库中数据的改变就是永久性的,接下来的其他操作和数据库故障不应该对其有任何影响
    • 事务的隔离级别
      • read uncommitted
      • read commited
      • repeatable read
      • serializable
    • 隔离级别的切换:set session|global transaction isolaction level 隔离级别
笔记
#TCL
/*
Transaction Control Language 事务控制语言

事务:
一个或一组sql语句组成一个执行单元,这个执行单元要么全部执行,要么全部不执行。

案例:转账

张三丰 1000
郭襄   1000

update 表 set 张三丰余额=500 where name='张三丰'
意外
update 表 set 郭襄的余额=1500 where name='郭襄'

事务的创建
隐式事务:事务没有明显的开启和结束的标记
比如insert、update、delete语句

delete from 表 where id=1;

显式事务:事务必须具有明显的开启和结束的标记
前提:必须先设置自动提交功能为禁用

set autocommit=0;

步骤1:开启事务
set autocommit=0;
start transaction;#可选的
步骤2:编写事务中的sql语句(select insert update delete)
语句1;
语句2;
...

步骤3: 结束事务
commit;提交事务
rollback;回滚事务

savepoint 节点名;设置节点,设置保存点


事务的隔离级别:
			脏读	不可重复读	幻读	
read uncommitted:	√	√		√
read committed: 	×	√		√
repeatable read:	×	×		√
serializable:		×	×		×
mysql中默认第三个隔离级别 repeatable read
oracle中默认第二个隔离级别read committed
查看隔离级别
select @@tx_isolation;
设置隔离级别
set session|global transaction isolation level 隔离级别;




开启事务的语句;
update 表 set 张三丰余额=500 where name='张三丰'
意外
update 表 set 郭襄的余额=1500 where name='郭襄'
结束事务的语句;

*/

SHOW ENGINES;

SHOW VARIABLES LIKE 'autocommit';
SET autocommit=1;

CREATE TABLE account(
	id INT PRIMARY KEY AUTO_INCREMENT,
	username VARCHAR(20),
	balance DOUBLE
);

INSERT INTO account(username,balance)
VALUES('张无忌',1000),('赵敏',1000);


#1.演示事务的使用步骤

#开启事务
SET autocommit=0;
START TRANSACTION;
#编写一组事务的语句
UPDATE account SET balance=1000 WHERE username='张无忌';
UPDATE account SET balance=1000 WHERE username='赵敏';

#结束事务
ROLLBACK;
#commit;

SELECT * FROM account;

#2.演示事务对于delete和truncate的处理的区别

SET autocommit=0;
START TRANSACTION;
DELETE FROM account;
ROLLBACK;

#实际的删除,无法回滚
SET autocommit=0;
START TRANSACTION;
TRUNCATE TABLE account;
ROLLBACK;


#3.演示savepoint 的使用
SET autocommit=0;
START TRANSACTION;
DELETE FROM account WHERE id=5;
SAVEPOINT a;#设置保存点
DELETE FROM account WHERE id=6;
ROLLBACK TO a;#回滚到保存点


SELECT * FROM account;

视图的讲解

笔记

#视图
/*
含义:虚拟表,和普通表一样使用
mysql5.1出现的新特性,是通过表动态生成的数据

	创建语法的关键字	是否实际占用物理空间	使用
视图	create view		只是保存了sql逻辑	增删改查,一般不能增删改

表	create table		保存了数据		增删改查

*/



#案例:查询姓张的学生名和专业名
SELECT stuname,majorname
FROM stuinfo s
INNER JOIN major m ON s.`majorid`= m.`id`
WHERE s.`stuname` LIKE '张%';

CREATE VIEW v1
AS
SELECT stuname,majorname
FROM stuinfo s
INNER JOIN major m ON s.`majorid`= m.`id`;

SELECT * FROM v1 WHERE stuname LIKE '张%';

#一、创建视图
/*
语法:
create view 视图名
as
查询语句;

*/

#1.查询姓名中包含a字符的员工名、部门名和工种信息
#①创建
CREATE VIEW myv1
AS

SELECT last_name,department_name,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%';

#2.查询各部门的平均工资级别

#①创建视图查看每个部门的平均工资
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`;



#3.查询平均工资最低的部门信息

SELECT * FROM myv2 ORDER BY ag LIMIT 1;

#4.查询平均工资最低的部门名和工资
CREATE VIEW myv3
AS
SELECT * FROM myv2 ORDER BY ag LIMIT 1;


SELECT d.*,m.ag
FROM departments d
INNER JOIN myv3 m
ON m.`department_id`=d.`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;

#方式二:
/*
语法:
alter view 视图名
as
查询语句;
*/
ALTER VIEW myv3
AS
SELECT * FROM employees;

#三、删除视图
/*
drop view 视图名,视图名,....;

*/

DROP VIEW myv1,myv2,myv3;

#四、查看视图
#在命令行里查看可以格式化:SHOW CREATE VIEW myv3/G;
DESC myv3;
SHOW CREATE VIEW myv3;

#五、视图的更新

CREATE OR REPLACE VIEW myv1
AS
SELECT last_name,email
FROM employees;

SELECT * FROM myv1;
SELECT * FROM employees;
#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 myv1
AS 
SELECT MAX(salary) m,department_id
FROM employees
GROUP BY department_id;

SELECT * FROM myv1;

#更新(不可更新)
UPDATE myv1 SET m=9000 WHERE department_id=10;

#②常量视图
CREATE OR REPLACE VIEW myv2
AS
SELECT 'john' NAME;
#更新
UPDATE myv2 SET NAME='lucy';

#③Select中包含子查询

CREATE OR REPLACE VIEW myv3
AS

SELECT(SELECT MAX(salary) FROM employees) 最高工资;

#更新
SELECT * FROM myv3;
UPDATE myv3 SET 最高工资=1000000

#④join
CREATE OR REPLACE VIEW myv4
AS

SELECT last_name,department_name
FROM employees e
JOIN departments d
ON e.department_id =d.department_id;

#更新

SELECT * FROM myv4;
UPDATE myv4 SET last_name ='张飞' WHERE last_name='Whalen';
INSERT INTO myv4 VALUES('陈真','xxxx');

#⑤from一个不能更新的视图
CREATE OR REPLACE VIEW myv5
AS
SELECT * FROM myv3;

SELECT * FROM myv5;

UPDATE myv5 SET 最高工资=100000 WHERE department_id=60;

#⑥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
);

#更新
SELECT * FROM myv6;
UPDATE myv6 SET salary=10000 WHERE last_name = 'k_ing';

变量

笔记

#变量
/*
系统变量:
	全局变量
	会话变量

自定义变量:
	用户变量
	局部变量

*/

#一、系统变量
/*
说明:变量又系统提供,不是用户定义,属于服务器层面
使用语法:
1、查看所有的系统变量
show global|【session】 variables;

2、查看满足条件的部分系统变量
show global|【session】 variables like '%char%';

3、查看指定的某个系统变量的值
select @@【session】|global.系统变量名;

4、为某个具体的系统变量赋值
方式一:(不加@@不加·)
set global|【session】 系统变量名=值;

方式二:(加@@加·)
set @@ global|【session】.系统变量名=值
注意:
如果是全局级别,则需要加global,如果是会话级别,则需要加session,如果不写,则默认session

*/

#1》全局变量
/*
作用域:服务器每次启动将为所有的全局变量赋初始值,针对于所有的会话连接有效,但不能跨重启

*/
#①查看所有的全局变量
SHOW GLOBAL VARIABLES;
#②查看部分的全局变量
SHOW GLOBAL VARIABLES LIKE '%char%';
#③查看指定的全局变量的值
SELECT @@global.autocommit;
SELECT @@tx_isolation;

#④为某个指定的全局变量赋值
SET @@global.autocommit=0;

#2》会话变量
/*
作用域:仅仅针对于当前的会话(连接)有效


*/

#①查看所有的会话变量
SHOW SESSION VARIABLES;
SHOW VARIABLES;

#②查看部分的会话变量
SHOW VARIABLES LIKE '%char%';
SHOW SESSION VARIABLES LIKE '%char%';
#③查看指定的某个会话变量
SELECT @@tx_isolation;
SELECT @@session.tx_isolation;

#④为某个会话变量赋值
方式一:
SET @@session.tx_isolation='read-uncommitted'

方式二:
SET SESSION tx_isolation='read-committed';


二、自定义变量
/*
说明:变量是用户自定义的,不是由系统的
使用步骤:
声明
赋值
使用(查看、比较、运算)
*/
#1、用户变量
/*
作用域:针对于当前会话连接有效,同于会话变量的作用域
应用在任何地方,也就是begin end里面或外面
*/

赋值操作符:=或:=
#①声明并初始化
SET @用户变量名=;
SET @用户变量名:=;
SELECT @用户变量名:=;

#②赋值(更新用户变量的值)
方式一:通过SETSELECT
	SET @用户变量名=;
	SET @用户变量名:=;
	SELECT @用户变量名:=;
方式二:通过SELECT INTO
	SELECT 字段 INTO 变量名
	FROM;

#③使用(查看用户变量的值)
SELECT @用户变量名;

#案例:
#声明并初始化
SET @name='john';
SET @name=100;
#赋值
SELECT COUNT(*) INTO @count
FROM employees;
#查看
SELECT @count;

#2.局部变量
/*
作用域:仅仅在定义它的begin end中有效
应用在begin end中的 *第一句话*

*/
#①声明
DECLARE 变量名 类型;
DECLARE 变量名 类型 DEFAULT;

#②赋值
方式一:通过SETSELECT
	SET 局部变量名=;
	SET 局部变量名:=;
	SELECT @局部变量名:=;
方式二:通过SELECT INTO
	SELECT 字段 INTO 局部变量名
	FROM;
	
#③使用
SELECT 局部变量名;

对比用户变量和局部变量
		作用域		定义和使用的位置		语法
用户变量	当前会话	会话中的任何地方		必须加@,不用限定类型

局部变量	BEGIN END中	只能在BEGIN END中,且为第一句话	一般不用加@

#案例:声明两个变量并赋初值,求和并打印
#1.用户变量
SET @m:=1;
SET @n:=2;
SET @sum = @m+@n;
SELECT @sum;

#2.局部变量
#不能执行,因为不在begin end中
DECLARE m INT DEFAULT 1;
DECLARE n INT DEFAULT 2;
DECLARE s INT;
SET s:=m+n;
SELECT s;

存储过程和函数

笔记

存储过程
#存储过程和函数
/*
存储过程和函数:类似于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表中五条记录
SELECT * FROM admin;

DELIMITER $
CREATE PROCEDURE myp1()
BEGIN
	INSERT INTO admin(username,`password`) VALUES('john1','0000'),('liy','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('柳岩')$

#注:字符集问题,set names gbk;
#案例2:创建存储过程实现,用户是否登录成功
#一般判断有没有就用count关键字
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 myp4('','')$

#3.创建带out模式的存储过程

#案例1:根据女神名,返回对应的男神名
CREATE PROCEDURE myp5(IN beautyName VARCHAR(20),OUT boyName VARCHAR(20))
BEGIN
	SELECT bo.boyname INTO boyName
	FROM beauty b
	INNER JOIN boys bo 
	ON bo.id=b.boyfriend_id
	WHERE b.name=beautyName;
END$

#调用
SET @bName$

CALL myp5('小昭',@bName)$

#案例2:根据女神名,返回对应的男神名和男神魅力值

CREATE PROCEDURE myp6(IN beautyName VARCHAR(20),OUT boyName VARCHAR(20),OUT userCP INT)
BEGIN
	SELECT bo.boyname,bo.userCP INTO boyName,userCP #多个变量赋值方法***
	FROM beauty b
	INNER JOIN boys bo 
	ON bo.id=b.boyfriend_id
	WHERE b.name=beautyName;

END$

CALL myp6('柳岩',@bName,@usercp)$

#4.创建带inout模式参数的存储过程
#案例1:传入a和b两个值,最终a和b都翻倍并返回

CREATE PROCEDURE myp8(INOUT a INT, INOUT b INT)
BEGIN
	SET a=2*a;
	SET b=2*b;
END$
#调用
SET @a=1$
SET @b=2$
CALL myp8(@a,@b)$
SELECT @a,@b$

#二、删除存储过程
#语法:drop procedure 存储过程名称

DROP PROCEDURE myp1;
DROP PROCEDURE myp2;

#三、查看存储过程的信息
DESC myp3;   ×
SHOW CREATE PROCEDURE myp3;

函数
#函数
/*
1、提高代码的重用性
2、简化操作
3、减少了编译次数并且减少了数据库服务器的连接次数,提高了效率

区别:

存储过程:可以有0个返回,也可以有多个返回,适合做批量插入,批量更新
函数:有且仅有一个返回,适合做处理数据后返回一个结果
*/

#一、创建语法
CREATE FUNCTION 函数名(参数列表) RETURNS 返回类型
BEGIN
	函数体
 
END
/*
注意:
1.参数列表 包含两部分
参数名 参数类型

2.函数体:肯定有return语句,如果没有会报错
如果return语句没有放在函数值的最后也不报错,但不建议

return 值;
3.函数体中只有一句话,则也可省略begin end
4.使用 delimiter 语句设置结束标记


*/

#调用语法
SELECT 函数名(参数列表);

#-------------------------案例演示----------------------
#1.无参有返回
#案例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 INT
BEGIN
	SET @sal=0;#定义用户变量
	SELECT salary INTO @sal
	FROM employees
	WHERE last_name=empName;
	RETURN @sal;
END$

SELECT myf2('Kochhar')$

#案例2:根据部门名,返回该部门的平均工资

CREATE FUNCTION myf3(deptName VARCHAR(20)) RETURNS DOUBLE
BEGIN
	DECLARE sal DOUBLE DEFAULT 0;
	SELECT AVG(salary) INTO sal
	FROM employees e
	JOIN departments d ON d.department_id=e.department_id
	WHERE deptName=d.department_name;
	RETURN sal;
	
END$

SELECT myf3('Adm');

#三、查看函数
DELIMITER ;
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函数
/*
功能:实现简单的双分支
语法:
select if(表达式1,表达式2,表达式3)
执行顺序:
如果表达式1成立,则if函数返回表达式2的值,否则返回表达式3的值

应用:任何地方
*/
#2.case结构

情况1:类似于java中的switch语句,一般用于实现等值判断

语法:
	CASE 变量|表达式|字段
	WHEN 要判断的值 THEN 返回的值1或语句1;
	WHEN 要判断的值 THEN 返回的值2或语句2;
	...
	ELSE 要返回的值n或语句n;
	END CASE;

情况2:类似于java中的多重IF语句,一般用于实现区间判断

语法:
	CASE
	WHEN 要判断的条件1 THEN 返回的值1或语句1;
	WHEN 要判断的条件2 THEN 返回的值2或语句2;
	...
	ELSE 要返回的值n或语句n;
	END

特点:
①
可以作为表达式,嵌套在其他语句中使用,可以放在任何地方,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 THEN SELECT 'A';
	WHEN score>=80 THEN SELECT 'B';
	WHEN score>=60 THEN SELECT 'C';
	ELSE SELECT 'D';
	END CASE;
END$

CALL test_case(95)$

#3.if结构
/*
功能:是吸纳多重分支

语法:
if 条件1 then 语句1;
elseif 条件2 then 语句2;
...
【else 语句n】;
end if;

应用在begin end中
*/

#根据传入的成绩,来显示等级,比如传入的成绩:90-100,返回A,80-90,返回B,60-80返回C,否则显示D

CREATE FUNCTION test_if(score INT) RETURNS CHAR
BEGIN
	IF score>=90 AND score<=100 THEN RETURN 'A';
	ELSEIF score >=80 THEN RETURN 'B';
	ELSEIF score >=60 THEN RETURN 'C';
	ELSE RETURN 'D';
	END IF;
END$

#二、循环结构
/*
分类:
while、loop、repeat

循环控制:

iterate类似于continue,继续,结束本次循环,继续下一次
leave 类似于braak,跳出,结束当前所在循环

*/

#1.while
/*

【标签:】while 循环条件 do
	循环体;
end while 【标签】;

联想:
while(循环条件){

	循环体
}

*/

#2.loop
/*
语法:
【标签:】loop
	循环体;
end loop 【标签】;

可以用来模拟简单的死循环

*/

#3.repeat
/*
语法
【标签:】repeat
	循环体;
until 结束循环的条件;
end repeat【标签】;

对比:

①这三种循环都可以省略名称,但如果循环中添加了循环控制语句(leave或iterate)则必须添加名称
②
loop 一般用于实现简单的死循环
while 先判断后执行
repeat 先执行后判断,无条件至少执行一次

*/

#没有添加循环控制语句
#案例:批量插入,根据次数插入到admin表中多条记录

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)$

#2.添加leave语句
#案例:批量插入,根据次数插入到admin表中多条记录,如果次数>20,则停止
TRUNCATE TABLE admin$
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),'666');
		SET i=i+1;
		IF i>20 THEN LEAVE a;
		END IF;
	END WHILE a;
  
END$

CALL test_while1(100)$

#3.添加interate语句

#案例:批量插入,根据次数插入到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),'666');
		
	END WHILE a;
  
END$

CALL test_while1(100)$
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值