MySQL学习笔记(基础部分)
B站学习视频:https://www.bilibili.com/video/BV12b411K7Zu
这篇笔记由我在看这个视频的时候顺便做的笔记(仅供参考)
如果本篇文章内容有什么错误也欢迎各位大佬指正!
MySQL基础
MySQL安装与使用
下载链接:https://dev.mysql.com/downloads/mysql/
一般都是使用5.5版本。
安装与卸载:https://blog.csdn.net/qq_45740349/article/details/113833200
配置文件:my.ini(在安装目录下),在里面可以修改一些服务端配置(端口号等)
启动与停止MySQL服务
方法一:打开计算机管理,在服务和应用程序中,找到MySQL服务,右键可以停止和启动
方法二:通过命令行的方式(注意需要以管理员的身份打开cmd窗口)
net stop mysql # 关闭mysql服务,其中stop后面跟的是mysql服务的名称
net start myaql # 开启mysql服务
登录和退出
方法一:通过mysql自带的客户端 MySQL 5.5 Command Line Client,缺点是仅限于root用户
方法二:通过cmd输入命令来登录:
mysql -h主机名 -P端口号 -u用户名 -p密码
注意:端口号是-P(大写P),如果是本机,可以直接省略掉-h和-P
mysql -uroot -proot # 登录root 用户
mysql -uroot -p # 登录root用户,这样子回车之后会在下一行以密文的方式输入密码
退出:exit 或 Ctrl + C
常见命令
# 查看当前的所有的数据库
show databases;
# 打开指定的库
use 库名;
# 查看当前打开的库
select database();
# 查看当前库的所有表
show tables;
# 查看其他库的所有表
show tables from 库名;
# 创建表
create table 表名(列名 列类型,列名 列类型,...
);
# 查看表结构
desc 表名;
查看当前mysql的版本:
登录到mysql服务端
select version();
没有登录到mysql服务端,直接在命令行输入
mysql --version mysql -V
编码问题
#设置客户端的编码
set character_set_client=gbk#设置连接器编码
set character_set_connection=gbk#设置返回值编码
set character_set_results=gbk#如果client(客户端)、connection(连接器)、results(返回值)都设置成gbk的话,可以简写成
set names gbk
当用cmd连接mysql时,报下面错误,可以尝试执行set names gbk
ERROR 1366 (HY000): Incorrect string value: '\xD6\xDC\xB6\xAC\xD3\xEA' for column 'beautyName' at row 1
语法规范
不区分大小写,但建议关键字大写,表名、列名小写。
每一条命令用;或者\g结尾。
每条命令可以根据需要进行缩进或换行。
注释
#单行注释 -- 单行注释(注意--后面要有一个空格!) /*多行注释 */
SQL的语言分类
- DQL(Data Query Language):数据查询语言
select - DML(Data Manipulate Language):数据操作语言
insert 、update、delete - DDL(Data Define Languge):数据定义语言
create、drop、alter - TCL(Transaction Control Language):事务控制语言
commit、rollback
DQL数据查询语言
基础查询
基础查询SELECT,语法:SELECT 查询列表 from 表名;
特点:
- 查询的列表可以是:表中的字段、常量值、表达式、函数
- 查询的结果是一个虚拟的表格
查询表中的某个字段:
SELECT last_name FROM employees;
查询表中的多个字段:
SELECT last_name,salary,email FROM employees;
查询表中的所有字段:
SELECT * FROM employees;
查询常量值:
SELECT 100;
SELECT 'ghdfijsvh';
查询表达式:
SELECT 100+200;
查询函数:
SELECT VERSION();
起别名:
SELECT 100+200 AS 结果;
SELECT last_name AS 姓,first_name AS 名 FROM employees;
起的别名会直接显示在查询结果的表的列上:
注意:
AS关键字可以省略
如果别名有关键字、空格、#号,应该加上引号。
SELECT 100+200 AS 'out put';
去重:
案例:查询员工表中涉及到的所有的部门编号:
SELECT department_id FROM employees;
查询结果:(数据重复)
解决方案:加上DISTINCT
关键字
SELECT DISTINCT department_id FROM employees;
mysql中+号的作用:数值相加,如果是非数值类型,则会试图将其转换成数值,如果转换失败则会当成0,如果其中一个为null,则结果必为null
SELECT '120' + 20; -- 140
SELECT 'abc' + 20; -- 20
SELECT NULL + 20; -- null
如果需要实现字符串拼接,需要用到concat函数:
SELECT CONCAT('a','b','c') AS 结果; -- abc
SELECT CONCAT(last_name,' ',first_name) AS 姓名 FROM employees; -- 查询两个字段拼接起来的结果
条件查询
语法:SELECT 要查询的字段|表达式|常量值|函数 FROM 表名 WHERE 条件;
分类:
- 条件表达式: > < >= <= = != <>
- 逻辑表达式:and(&&) or(||) not(!)
- 模糊查询:like between and in is null
查询工资大于12000的所有员工信息:
SELECT * FROM employees WHERE salary >= 12000;
查询所有部门编号不等于90的员工信息:
SELECT * FROM employees WHERE department_id != 90;
SELECT * FROM employees WHERE department_id <> 90;
LIKE模糊查询(一般和通配符一起使用,%表示匹配任意多个字符,_表示匹配任意单个字符。)
# 查询员工名中包含字符a的员工信息:
SELECT * FROM employees WHERE first_name LIKE '%a%';
# 查询员工姓名中第三个字符为e,第五个字符为a的员工姓名和工资:
SELECT first_name,salary FROM employees WHERE first_name LIKE '__e_a%';
# 查询员工姓名中第二个字符为_的员工名(不希望把这个_当成通配符)
SELECT last_name FROM employees WHERE last_name LIKE '_\_%'; -- 使用\来当作转义字符
SELECT last_name FROM employees WHERE last_name LIKE '_$_%' ESCAPE '$'; -- 自定义转义符
BETWEEN AND(注意两个数字不能颠倒)
# 查询员工编号在100到120之间的员工信息
SELECT * FROM employees WHERE employee_id BETWEEN 100 AND 120;# 查询员工编号不在100到120之间的员工信息
SELECT * FROM employees WHERE employee_id NOT BETWEEN 100 AND 120;
IN(注意括号里面的数据类型必须与对应字段的数据类型一致或兼容,而且括号里面的字符串不支持通配符)
# 查询员工的job_id为 IT_PROG / AD_VP / AD_PRES 的员工信息
SELECT * FROM employees WHERE job_id IN ('IT_PROG','AD_VP','AD_PRES');
IS NULL(注意不能使用=来判断数据是否为NULL)
SELECT * FROM employees WHERE commission_pct IS NULL;
SELECT * FROM employees WHERE commission_pct IS NOT NULL;
安全等于 <=>
# 可以判断是否为null
SELECT * FROM employees WHERE commission_pct <=> NULL;
# 也可以判断具体数值
SELECT * FROM employees WHERE salary <=> 12000;
经典面试题:试问select * from employees; 和 select * from employees where commission_id like ‘%%’ and last_name like ‘%%’;是否一样?
答:不一样。后者排除了为null的情况。
排序查询
语法:
select 查询列表
from 表
[where 筛选条件]
order by 排序列表 asc|desc -- asc升序 desc降序
示例:
# 查询所有员工信息,并按工资的排序
SELECT * FROM employees ORDER BY `salary` DESC; -- 降序
SELECT * FROM employees ORDER BY `salary` ASC; -- 升序
SELECT * FROM employees ORDER BY `salary`; -- 不写的时候默认是升序# 查询部门编号大于90的员工信息,按入职时间的先后排序
SELECT * FROM employees WHERE `department_id` >= 90 ORDER BY `hiredate` ASC;# 按姓名的长度显示员工的姓名和工资,并按姓名长度降序排序
SELECT LENGTH(last_name) 长度,last_name,salary
FROM employees
ORDER BY LENGTH(last_name) DESC;
-- 或
SELECT LENGTH(last_name) 长度,last_name,salary
FROM employees
ORDER BY 长度 DESC; -- 可以根据别名排序# 查询员工信息,要求按工资升序排列,当工资一样时再按员工编号降序
SELECT * FROM employees ORDER BY salary ASC,employee_id DESC;
注意:
- asc代表升序,desc代表降序。如果不写,默认是升序。
- order by 子句中可以支持单个字段、多个字段、表达式、函数、别名
- order by子句一般放在查询语句的最后面,只有limit子句放在order by后面外,其他的都在它前面。
常见函数
概念:类似于java的方法
好处:1. 隐藏了实现细节 2. 提高代码的重用性
调用: select 函数名(参数) [from 表] – 当参数使用到表中的字段时,才加上from 表
分类: 1. 单行函数(如concat length ifnull 等) 2. 分组函数(做统计使用,又称为统计函数)
单行函数
字符函数:
# 字符函数
# 1. length 求参数值的字节
SELECT LENGTH('abc'); -- 3
SELECT LENGTH('哈哈哈');-- 9(utf8编码的一个汉字占3个字节)# 2. concat 拼接字符串
SELECT CONCAT('abc','def');
SELECT CONCAT(last_name,' ',first_name) 姓名 FROM employees;# 3. upper将字符串中的所有字符转变成大写;lower将字符串中的所有字符转变成小写
SELECT UPPER('abcdef');
SELECT LOWER('ABCDEF');
# 案列:将姓变大写,名变小写,然后拼接。
SELECT CONCAT(UPPER(last_name),' ',LOWER(first_name)) FROM employees;# 4. substr/substring 截取子串(注意索引从1开始)
# SUBSTR("字符串",开始索引,截取长度);
SELECT SUBSTR("李莫愁爱上了莫展元",7); -- 莫展元
SELECT SUBSTR("李莫愁爱上了莫展元",1,3);-- 李莫愁# 5. instr(str,substr) 求出substr在str中的起始索引(找不到返回0)
SELECT INSTR("abcdefgh",'def'); -- 4# 6. trim 去左右空格
SELECT TRIM(" aaaa ");
SELECT TRIM('b' FROM 'bbbbaaaabbbbb'); -- 去除左右的b# 7. lpad(str,len,padstr) 用padstr在左边填充str,填充完之后str的长度为len
SELECT LPAD('aaaa',10,'*'); -- ******aaaa
# 如果str的长度一开始就大于len,则会从右边截断
SELECT LPAD('abcd',3,'*'); -- abc# 8. rpad 和lpad类似,右填充
SELECT RPAD('aaaa',10,'*'); -- aaaa******# 9. replace(str,from_str,to_str) 替换
SELECT REPLACE('张无忌爱上了周芷若','周芷若','赵敏'); -- 张无忌爱上了赵敏
数学函数:
# 数学函数# 1. round(X) 四舍五入
# 重载形式 round(X,D),在小数点后D位四舍五入
SELECT ROUND(1.45); -- 1
SELECT ROUND(1.4567,2); -- 1.46# 2. ceil(x) 向上取整
SELECT CEIL(1.233); -- 2# 3. floor(x) 向下取整
SELECT FLOOR(9.999); -- 9 # 4. truncate(X,D) 截断到小数点后D位
SELECT TRUNCATE(1.23456789,3); -- 1.234
SELECT TRUNCATE(1.234,10); -- 1.2340000000# 5. mod(n,m) 取余
SELECT MOD(10,3); -- 1
日期函数:
# 日期函数# 1. now() 返回当前系统日期+时间
SELECT NOW(); -- 2021-02-20 17:57:32# 2. curdate() 返回当前系统日期
SELECT CURDATE(); -- 2021-02-20# 3. curtime() 返回当前系统时间
SELECT CURTIME(); -- 17:57:32# 4. 可以获取指定的年、月、日、时、分、秒
SELECT YEAR(NOW()); -- 2021
SELECT YEAR('1998-1-1');-- 1998
SELECT MONTH(NOW()); -- 2
SELECT MONTHNAME(NOW());-- February# 5. str_to_date(str,format) 将字符串通过指定的格式转换成日期
SELECT STR_TO_DATE('2021-02-21','%Y-%m-%d');
# 查询入职日期为1992-4-3的员工信息
SELECT * FROM employees WHERE hiredate = '1992-4-3'; -- 可以直接这么查
-- mysql默认的日期格式是年-月-日,如果字符串不满足这个格式就要进行转换
SELECT * FROM employees WHERE hiredate = STR_TO_DATE('4-3 1992','%c-%d %Y');# 6. date_format(date,format): 将日期通过指定格式转化成字符串
SELECT DATE_FORMAT(NOW(),'%Y年%m月%d日');
日期格式符:
其他函数:
# 查看版本号
SELECT VERSION();# 查看当前数据库
SELECT DATABASE();# 查看当前用户
SELECT USER();
流程控制函数:
# 流程控制函数# 1. if(expr1,expr2,expr3) 判断expr1,如果成立则返回expr2,不成立返回expr3
SELECT IF(10 < 5,'小','大');
SELECT last_name,IF(commission_pct IS NULL,'没有奖金','有奖金') 备注 FROM employees;# 2. case# 2.1 使用方法一(类似switch)
/*
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 last_name,salary 原来的工资,
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;# 2.2 使用方法二(类似多重if)
/*
case
when 条件1 then 要显示的值1或语句1;
when 条件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 工资级别
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;
特点:
- SUM、AVG只用于处理数值型
- 以上函数都忽略了null值
- 和分组函数一起查询的字段要求是group by后的字段
count()函数,一般会采用count(*)来统计行数。也可以采用count(1)
来统计,count(1)相当于给每一行都加一列,值为1,然后统计1的个数
效率上:
- MyISAM存储引擎:count(*)的效率最高
- InnoDB存储引擎:count(*)和count(1)的效率差不多,都比count(字段)的效率高
分组查询
语法:
select 分组函数, 列 -- 这个列要求出现在group by后面
from 表
[where 筛选条件]
group by 分组列表
[order by 排序列表]
案例:
查询每个工种的最高工资
SELECT job_id,MAX(salary) FROM employees GROUP BY job_id;
查询每个部门的 邮箱中包含a字符 的人的平均工资(分组前筛选)
SELECT department_id,AVG(salary) FROM employees WHERE `email` LIKE '%a%' GROUP BY department_id;
查询出所有员工个数大于2的部门
# 1. 先查询出每个部门的员工个数 SELECT department_id,COUNT(*) FROM employees GROUP BY department_id;# 2. 再从1的结果中筛选出count(*)大于2的部门 # 使用having关键字 SELECT department_id,COUNT(*) FROM employees GROUP BY department_id HAVING COUNT(*) > 2;
特点:
- 分组查询中的筛选条件分为2类,一类是分组前筛选,一类是分组后筛选。
分组前筛选使用的是where子句,放在group by的前面,数据源是原始表
分组后筛选使用的是having子句,放在group by的后面,数据源是分组后的记过集。
(分组函数作为条件一定是放在having子句中) - group by支持单个字段,也支持多个字段(多个字段时,这些字段的值都一样的视为一组,多个字段之间用逗号隔开,没有顺序要求),还可以是表达式和函数。
- 也可以添加排序(放在group by的后面)
连接查询
又称多表查询,当查询的字段来自多个表时,就会用到连接查询
笛卡尔积现象:如果表1中包含m行,表2包含n行,那么执行select * from 表1,表2;
就出现m * n行结果。
如何避免? 加入连接条件。
分类:
- 按年代分类:sql92标准(仅仅支持内连接)、sql99标准(支持内连接、外连接和交叉连接,外连接只支持左外和右外)
- 按功能分类:
- 内连接:等值连接、非等值连接、自连接
- 外连接:左外连接、右外连接、全外连接
- 交叉连接
等值连接
# 1. 查询女神名和对应的男神名
USE girls;
SELECT `name`,`boyName`
FROM beauty,boys
WHERE beauty.`boyfriend_id`=boys.`id`;# 2. 查询员工名和对应的部门名
USE myemployees;
SELECT `last_name`,`department_name`
FROM employees,departments
WHERE employees.`department_id` = departments.`department_id`;# 3. 查询每个员工的名字、工种号和对应的工种名
SELECT `last_name`,employees.`job_id`,`job_title`
FROM employees,jobs
WHERE employees.`job_id` = jobs.`job_id`;# 4. 查询所有工种的工种名和员工个数,并按员工个数降序
SELECT `job_title` 工种名,COUNT(*) 员工个数
FROM employees e,jobs j
WHERE e.`job_id` = j.`job_id`
GROUP BY j.`job_title`
ORDER BY 员工个数 DESC
注意:如果查询的字段在多个表中同时出现,要用表名.
来加以区分。
表名也可以加上别名
SELECT `last_name`,e.`job_id`,`job_title`
FROM employees e,jobs j
WHERE e.`job_id` = j.`job_id`;
但是注意:一旦给表名加上了别名,就不能再使用原来的名字了!
注:
- 多表等值连接的结果为多表的交集部分
- n表连接,至少需要n-1个连接条件
- 多表的顺序没有要求
- 一般需要为表起别名
- 可以搭配排序、分组、筛选这些子句来使用
非等值连接
假如有一张表job_grades,里面包含了所有的工资等级:
案例:查询出所有员工的工资等级
SELECT `last_name`,`salary`,`grade_level`
FROM employees,job_grades
WHERE salary BETWEEN `lowest_sal` AND `highest_sal`;
自连接
其实就是等值连接,就是连接的是同一张表而已。
案例:查询所有的员工姓名和他的上级的名称
SELECT e1.`last_name` 员工名称,e2.`last_name` 上级名称
FROM employees e1, employees e2
WHERE e1.`manager_id` = e2.`employee_id`;
sql99语法
语法:
select 查询列表
from 表1 [连接类型]
join 表2
on 连接条件
[where 筛选条件]
[group by 分组]
[having 筛选条件]
[order by 排序]
连接类型可选:
- 内连接:inner
- 外连接:左外连接 left [outer] , 右外连接 right [outer] ,全外连接 full [outer]
- 交叉连接:cross
等值连接
# 1. 查询员工名和对应的部门名
SELECT `last_name`,`department_name`
FROM `employees`
INNER JOIN `departments`
ON `employees`.`department_id` = `departments`.`department_id`;# 2. 查询名字中包含e的员工名和工种名(添加筛选)
SELECT `last_name`,`job_title`
FROM `employees` e
INNER JOIN `jobs` j
ON e.`job_id` = j.`job_id`
WHERE e.`last_name` LIKE '%e%';# 3. 查询部门个数>3的城市名和部门个数(添加筛选和分组)
SELECT `city`,COUNT(*) 部门个数
FROM `departments` d
INNER JOIN `locations` l
ON d.`location_id`=l.`location_id`
GROUP BY `city`
HAVING COUNT(*) > 3;# 4. 查询哪个部门的员工个数大于3,查询出部门名和员工个数,并按个数降序(添加排序)
SELECT `department_name`,COUNT(*) 员工个数
FROM `employees` e
INNER JOIN `departments` d
ON e.`department_id` = d.`department_id`
GROUP BY `department_name`
HAVING 员工个数>3
ORDER BY 员工个数 DESC;# 5. 查询员工名、部门名、工种名,并按部门名降序(三表连接)
SELECT `last_name`,`department_name`,`job_title`
FROM `employees` e
INNER JOIN `jobs` j ON e.`job_id` = j.`job_id`
INNER JOIN `departments` d
ON e.`department_id` = d.`department_id`
ORDER BY `department_name`;
特点:
- 可以添加排序、分组、筛选
- inner可以省略
- 筛选条件放在where后面,连接条件放在on后面,提高分离性。
- inner join 连接和sql92语法中的等值连接效果是一样的,都是查询多表的交集部分。
非等值连接
# 查询员工的工资级别
SELECT `last_name`,`salary`,`grade_level`
FROM `employees` e
INNER JOIN `job_grades` j
ON e.`salary` BETWEEN j.`lowest_sal` AND j.`highest_sal`;
自连接
# 查询员工的名字、上级的名字
SELECT e1.`last_name`,e2.`last_name`
FROM `employees` e1
INNER JOIN `employees` e2
ON e1.`manager_id` = e2.`employee_id`;
外连接
外连接的应用场景:用于查询一个表中有,而另外一个表中没有的记录。
特点:
- 外连接查询的结果为主表中的所有记录
如果从表中有和他匹配的,就显示匹配的值(这个的效果是和内连接一样的)
如果从表中没有和他匹配的,就用null填充。
外连接的查询结果=内连接结果+主表中有而从表没有的结果 - 怎么区分主表和从表?
左外连接:left join 左边的是主表
右外连接:right join 右边的是主表 - 左外和右外的顺序交换,可以实现一样的效果。
- mysql不支持全外连接,但是全外连接的效果=内连接+表1有而表2没有+表2有而表1没有
案例:
# 查询男朋友不在boys表的女神名
SELECT `beauty`.`name`
FROM `beauty`
LEFT JOIN `boys`
ON `beauty`.`boyfriend_id` = `boys`.`id`
WHERE `boys`.id IS NULL;
-- 也可以是
SELECT `beauty`.`name`
FROM `boys`
RIGHT JOIN `beauty`
ON `beauty`.`boyfriend_id` = `boys`.`id`
WHERE `boys`.id IS NULL;
# 查询哪个部门没有员工
SELECT `department_name`
FROM `departments` d
LEFT JOIN `employees` e
ON d.`department_id` = e.`department_id`
WHERE e.`department_id` IS NULL;
交叉连接
# 交叉连接(没啥特别的,就是sql99版的笛卡尔乘积)
SELECT * FROM `beauty` CROSS JOIN `boys`;
子查询
含义:出现在其他语句中的SELECT语句,称为子查询或内查询。外部的查询语句称为主查询或内查询。
分类:
- 按子查询出现的位置
- select后面:仅支持标量子查询
- from 后面:支持表子查询
- where或having后面:支持标量子查询和列子查询,也支持行子查询(用得较少)
- exists后面:支持表子查询
- 按结果集的行列数不同
- 标量子查询(结果集为一行一列)
- 列子查询(结果集为一列多行)
- 行子查询(结果集一般为一行多列)
- 表子查询(结果集有多行多列)
where或having后面
特点:
子查询一般放在小括号内
子查询一般放在条件的右侧
标量子查询一般搭配着单行操作符使用(> < >= <= = <>)
列子查询一般搭配多行操作符使用(in any/some all)子查询里面的select语句最后不需要加分号
标量子查询(单行子查询)
# 案例1:查询谁的工资比Abel高? # 1. 先查询出Abel的工资(查询出的结果是一行一列的结果) SELECT salary FROM employees WHERE last_name = 'Abel';# 2. 查询员工信息,满足salary>1中的结果 SELECT * FROM employees WHERE salary > (SELECT salary FROM employees WHERE last_name = 'Abel');# 案例2:查询job_id与141号员工相同,salary比143号员工多的员工 SELECT * 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:返回工资最少的员工的信息 SELECT * FROM employees WHERE salary=(SELECT MIN(salary) FROM employees);
列子查询(多行子查询)
# 案例1:查询location_id是1400或1700的部门的所有员工 # 1. 先查询location_id是1400或1700的部门 SELECT `department_id` FROM `departments` WHERE `location_id` IN (1400,1700);# 2. 再查询department_id为1中的结果的所有员工 SELECT * FROM `employees` WHERE `department_id` IN(SELECT `department_id`FROM `departments`WHERE `location_id` IN (1400,1700) );
行子查询(一行多列或多列多行)
# 案例:查询员工编号最小并且工资最高的员工信息# 以前的做法: 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 后面的子查询
# 案例1:查询每个部门的员工个数
SELECT d.*,COUNT(e.`employee_id`) 员工个数
FROM `departments` d
LEFT JOIN `employees` e
ON d.`department_id`=e.`department_id`
GROUP BY d.`department_id`;
-- 使用子查询
SELECT d.*,(SELECT COUNT(*)FROM employees eWHERE e.`department_id`=d.`department_id`
) 员工个数
FROM departments d;# 案例2:查询员工号=102的部门名
SELECT(SELECT `department_name`FROM `departments` dINNER JOIN `employees` eON d.`department_id` = e.`department_id`WHERE e.`employee_id`=102
) 部门名;
注:仅仅支持一行一列
from后面的子查询
# 案例:查询每个部门的平均工资的工资等级
# 1. 先查询每个部门的平均工资
SELECT AVG(salary),`department_id`
FROM `employees`
GROUP BY `department_id`;# 2. 连接1中的结果集和job_grades表
SELECT av_dep.*,jd.`grade_level`
FROM (SELECT AVG(salary) av,`department_id`FROM `employees`GROUP BY `department_id`
) av_dep
INNER JOIN `job_grades` jd
ON av_dep.av BETWEEN jd.`lowest_sal` AND jd.`highest_sal`;
exists后面的子查询(相关子查询)
exists的语法为:exists(完整的查询语句),结果只有1和0两种,只要括号里面的查询语句有值,就是1,没值,就是0
# 案例:查询有员工的部门名字
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
);
分页查询limit
应用场景:当要显示的数据,一页显示不全,需要分页提交sql请求。
语法:
select 查询列表
from 表
join 表2 on 连接条件
where 筛选条件
group by 分组字段
having 分组后筛选
order by 排序
limit [开始索引,]显示数目; -- 分页查询,注意开始索引从0开始
案例:
# 查询前5条员工信息
SELECT * FROM employees LIMIT 0,5; -- 索引从0开始,显示5条
SELECT * FROM employees LIMIT 5; -- 索引从0开始,那么 0, 可以省略# 查询有奖金的员工中奖金最高的10位员工信息
SELECT * FROM employees WHERE commission_pct IS NOT NULL ORDER BY salary DESC LIMIT 10;
特点:
- limit语句放在查询语句的最后
- 公式(要查询的页数 page,每页的条目数 size),那么limit 子句可以写成
limit (page-1)*size,size
union联合查询
union联合:将多条查询语句的结果合并成一个结果。
语法:
查询语句1
union
查询语句2
union
...
案例:
# 查询部门编号>90或邮箱包含a的员工信息
SELECT * FROM employees WHERE email LIKE '%a%' OR department_id > 90;
-- 使用联合查询
SELECT * FROM employees WHERE email LIKE '%a%'
UNION
SELECT * FROM employees WHERE department_id > 90;
应用场景:要查询的结果来自多个表,且多个表没有直接的连接关系,但查询的信息一致时。
特点:
- 要求多条查询语句的列数是一致的
- 要求多条查询语句的每一列的类型是一致的(虽然不一致也不会报错,但是尽量这么干)
- 使用union关键字是默认去重的,如果不需要去重,可以使用union all
DML数据操作语言
数据操作语言:插入(insert),修改(update),删除(delete)
插入语句
语法:
insert into 表名(列1,列2,列3,...) values(值1,值2,值3,...);
insert into 表名
set 列1=值1,列2=值2,...
两种方式的区别:
第一种方式可以插入多行
insert into 表名(列1,列2,列3,...) values(值1,值2,值3,...),(值1,值2,值3,...),(值1,值2,值3,...);
第一种方式还支持子查询
insert into 表名(列1,列2,列3,...) select查询语句;
效果是:将select语句查询出来的结果集加入到表中。
修改语句
修改单表记录:
update 表名
set 列1=新值1,列2=新值2
where 筛选条件
修改多表记录:
# sql92语法:
update 表1 别名,表2 别名
set 列1=值1,...
where 连接条件 and 筛选条件;# sql99语法:
update 表1 别名
inner|left|right join 表2 别名
on 连接条件
set 列=值
where 筛选条件;
删除语句
语法:
# 方式一:
delete from 表名 where 筛选条件;# 方式二:
truncate table 表名; -- 删除表的所有内容,不能加where条件
多表的删除(补充):
# 方式一:
# SQL92语法:
delete 表1的别名,表2的别名 -- 要删除哪个表的记录就写哪个表
from 表1 别名,表2 别名
where 连接条件
and 筛选条件;# SQL99语法
delete 要删除哪张表的记录
from 表1 别名
inner|left|right join 表2 别名
where 筛选条件;
DELETE和TRUNCATE的区别:
- DELETE可以加where条件
- TRUNCATE的效率要更高
- 假如要删除的表中有自增长列:使用DELETE删除后,自增长列的值从断点开始;使用TRUNCATE删除后,自增长列的值从1开始。
- DELETE删除有返回值(执行之后可以看到有多少行受到影响),而TRUNCATE的删除无返回值。
- DELETE删除之后可以回滚,而TRUNCATE删除之后不能回滚。
DDL数据定义语言
库的管理、表的管理。
创建(create),修改(alter),删除(drop)
库的管理
1. 创建:
create database (if not exists) 库名;# 创建的时候指定字符集
create database (if not exists) 库名 character set utf8;
2. 修改
# 修改库名(已弃用)
rename database 旧数据库名 to 新数据库名;# 修改字符集
alter database 库名 character set utf8;
3. 删除
drop database if exists 库名;
表的管理
1. 创建
create table [if not exists] 表名(列名 列的类型(长度[可选]) 约束[可选],列名 列的类型(长度[可选]) 约束[可选],列名 列的类型(长度[可选]) 约束[可选],...列名 列的类型(长度[可选]) 约束[可选]
);
查看表结构
desc 表名;
2. 修改
# 修改列名
alter table 表名 change [column] 旧列名 新列名 类型;# 修改列的类型或约束
alter table 表名 modify column 列名 新类型;# 添加新列
alter table 表名 add column 列名 类型;# 删除列
alter table 表名 drop column 列名;# 修改表名
alter table 表名 rename to 新表名;
列的增加、删除、修改都是alter table 表名 change|modify|add|drop column XXXX
,其中change后面的column可以省略,其他的都不可以。写的时候最好都加上!!
3. 删除
drop table 表名;
4. 复制
# 仅仅复制表的结构
create table 表名 like 要复制的表;# 复制表的结构+数据(子查询)
create table 表名 select * from 要复制的表;
-- 如果要复制部分数据,可以在后面的子查询加条件.
数据类型
分为:
- 数值型:整形、小数(定点数、浮点数)
- 字符型:较短的文本(char / varchar)、较长的文本(text / blob(较长的二进制数据))
- 日期型
1. 整形
如何设置无符号和有符号?
create table tab_int(t1 int, -- 默认是有符号t2 int unsigned -- 如果要设置成无符号,就在int后面加上unsigned );
▲注意:如果对设置成无符号的列插入一个负数,会发出警告!并且最终得到的值是0
如果插入的数值超出了整形的范围,会报out of range异常,并且最终插入的是临界值。
定义类型时,如果不设置长度,会有默认的长度。
注意:长度只代表显示的最大宽度,并不能限制数据的范围!!
可以通过搭配zerofill
关键字,来实现用0在左边填充create table tab_int(t1 int(7) zerofill -- 注:一旦加上zerofill关键字,就会定义成无符号类型 ); -- 当插入数据123后,再查询表中的内容,得到的就是0000123
2. 小数
注:定义类型时,一般会指定长度,如:float(M,D)
/double(M,D)
/dec(M,D)
其中:D代表的是小数点后留多少位,M代表的是整数+小数部分的总位数! 比如dec(5,2),代表的是整数部分最多3位数,小数部分最多2位数,即最大值为999.99
M和D都可以省略:
- decimal类型:M默认为10,D默认为0
- float和double类型:则会根据插入的数值来确定精度
注:定点数的精确读较高,如果要求插入数据的精度较高(如货币运算),则优先考虑使用。
3. 字符型
char和varchar的比较:
写法 | M的意思 | 特点 | 空间的耗费 | 效率 | |
---|---|---|---|---|---|
char | char(M) | 最大的字符数,可以省略,默认为1 | 固定长度 | 比较耗费 | 高 |
varchar | varchar(M) | 最大的字符数,不可以省略 | 可变长度 | 比较节省 | 低 |
4. 日期型
常见约束
约束:一种限制,用于限制表中的数据,为了保证表中数据的准确性和可靠性
create table 表名(字段名 字段类型 约束,...
)
分类:
- NOT NULL:非空,用于保障该字段的值不能为空
- DEFAULT:默认,用于给该字段设置默认值
- PRIMARY KEY:主键,用于保证该字段的值具有唯一性,并且非空(主要用于有标识性的字段,如学号、员工编号)
- UNIQUE:唯一,用于保证该字段的值具有唯一性,可以为空
- CHECK:检查约束【mysql中不支持,如果使用,语法上不会报错,但是不会有效果】
- FOREIGN KEY:外键约束,用于限制两个表的关系,用于保证该字段的值必须来自于主表关联列的值
在从表添加外键约束,用于引用主表中某列的值。
添加约束的时机:
- 创建表时
- 修改表时
约束的添加分类:
- 列级约束:六大约束语法上都支持,但是外键约束没有效果
- 表级约束:除了非空,默认,其他的都可以
执行命令:可以查看所有约束
show index from xxx;
★主键和唯一的对比:
保证唯一性 | 是否允许为空 | 表中可以有多少个 | |
---|---|---|---|
主键 | √ | √ | 至多一个 |
唯一 | √ | √ | 可以有多个 |
★外键约束的特点:
- 要求在从表设置外键关系
- 从表的外键列的类型必须和主表的关联列的类型一致或者兼容,名称无要求
- 主表的关联列必须是一个key(一般是主键或者唯一,也可以是外键,但是无意义)建表的时候要注意,要不然会报1005错误!
- 插入数据时,先插入主表再插入从表;删除数据时,先删除从表再删除主表。
主表:被引用的那个表
从表:添加外键的那个表
列级和表级的区别:
位置 | 支持哪些类型 | 是否可以起约束名 | |
---|---|---|---|
列级约束 | 列的后面 | 语法都支持(mysql中检查和外键没有效果) | 不可以 |
表级约束 | 所有列的下面 | 默认和非空不支持外其他都支持(mysql中还不支持检查约束) | 可以 |
1. 创建表时添加约束
语法:
# 列级约束
create table 表名(字段名 字段类型 约束,...
);# 表级约束
create table 表名(字段名 字段类型,...,[constraint 约束名称] 约束类型(字段名); -- [constraint 约束名称]中的约束名称是随意起的,并且可以省略
);
添加列级约束
create table stuinfo(id int primary key, #主键stuName varchar(20) not null, #非空gender char(1) check(gender='男' or gender='女'), #检查seat int unique, #唯一(mysql不支持)age int default 18,#默认majorId int references major(id) #外键(mysql不支持) );
添加表级约束
语法:constraint 约束名 约束类型(字段名)
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='男' or gender='女'), # 检查(mysql不支持)constraint fk foreign key(id) references major(id), # 外键(mysql的外键只支持表级约束) -- major表的id字段必须是主键或唯一,要不然建表报1005错误! );
2. 修改表时添加约束
语法:
# 列级约束
alter table 表名 modify column 字段名 字段类型 新约束;# 表级约束
alter table 表名 add [constraint 约束名称] 约束类型(字段名);
添加非空约束:
alter table stuinfo modify column stuname varchar(20) not null;
添加默认约束
alter table stuinfo modify column age int default 18;
添加主键
alter table stuinfo modify column id int primary key; -- 列级 alter table stuinfo add primary key(id); -- 表级
添加唯一
alter table stuinfo modify column seat int unique; -- 列级 alter table stuinfo add unique(seat); -- 表级
添加外键
alter table stuinfo add foreign key(majorid) references major(id); -- mysql中的外键约束只支持表级,所以只有add没有modify
3. 删除约束
#1. 删除非空、默认
alter table stuinfo modify column stuname varchar(20); -- 后面不跟约束(modify就相当于修改表中的字段)#2. 删除唯一
alter table stuinfo drop index 约束名; -- 约束名可以执行show index from xxx 查看#3. 删除主键
alter table stuinfo drop primary key;#4. 删除外键
alter table stuinfo drop foreign key 外键约束名; -- 约束名可以执行show index from xxx 查看
标识列
标识列又称为自增长列,可以不用手动地插入值,系统提供默认的序列值(从1开始)。
注意:
- 标识列必须和key(主键、唯一)搭配,这一点和外键约束一样。
- 一个表至多只能有一个标识列
- 标识列的类型只能是数值型
- 插入数据的时候,自增长列的可以设置为NULL值,系统会默认给一个自增长的值。
创建表时设置标识列
create table 表名(字段名 字段类型 primary key auto_increment,... );
修改表时设置标识列
alter table 表名 modify column 字段名 字段类型 primary key auto_increment;
删除标识列
alter table 表名 modify column 字段名 字段类型 primary key; -- 直接删掉auto_increment
如何修改自增的起始值和步长?
执行命令SHOW VARIABLES LIKE '%auto_increment%'
可以查看步长和起始值相关的变量:
执行set auto_increment_increment=3
可以改变步长,但是不能通过设置auto_increment_offset
来改变起始值,没有效果。
唯一能改变起始值的方法是直接插入一个数据,假如id是自增长列,插入id=100,那么下次再插入数据时,id就会默认从101开始了。
TCL事务控制语言
事务:一个或一组sql语句组成一个执行单元,这个执行单元要么全部执行,要么全部不执行。
存储引擎:
事务的4个属性(ACID)
- 原子性(Atomicity)
原子性是指事务是一个不可分割的工作单位,事务中的操作要么都发生,要么都不发生。 - 一致性(Consistency)
事务必须使数据库从一个一致性状态变换到另外一个一致性状态。 - 隔离性(Isolation)
事务的隔离性是指一个事务的执行不能被其他事务干扰,即一个事务内部的操作及使用的数据对并发的其他事务是隔离的,并发执行的各个事务之间不能相互干扰。 - 持久性(Durability)
持久性是指一个事务一旦被提交,它对数据库的改变就是永久性的,接下来的其他操作和数据库故障不应该对其有任何影响。
事务的创建
隐式事务:事务没有明显的开启和结束标记,比如单独的insert/update/delete语句。
执行下面这一条命令:
SHOW VARIABLES LIKE '%autocommit%'
可以发现,autocommit(自动提交)默认是开启的状态:
显式事务:事务具有明显的开启和结束的标记
前提:必须要先设置自动提交功能为禁用
set autocommit=0;
(再执行SHOW VARIABLES LIKE '%autocommit%'
,就会发现autocommit为OFF,但是注意这个改变仅对当前会话有效!)
使用步骤:
# 1. 开启事务
set autocommit = 0;
start transaction; -- 可选语句# 2. 编写一组事务的sql语句
-- update delete insert select# 3. 回滚/提交
rollback;
commit;
事务并发问题
对于同时运行的多个事务,当这些事务访问数据库中相同的数据时,如果没有采取必要的隔离机制,就会导致各种并发问题。
并发问题:
- 脏读:对于两个事务T1、T2,如果T1已经读取了已经被T2更新但还没有被提交的数据,之后若T2回滚,那么T1读取的内容就是临时且无效的。
- 不可重复读:对于两个事务T1、T2,如果T1读取了一个数据,然后T2更新了这个数据,之后,T1再次读取这个数据,值就不同了
- 幻读:对于两个事务T1、T2,如果T1从表中读取了数据,然后T2在表中插入了一些新的行。之后,如果T1再次读取同一个表,就会多出几行。
隔离级别:
查看当前mysql的隔离级别:
SELECT @@tx_isolation;
SHOW VARIABLES LIKE '%tx_isolation%';
修改隔离级别:
SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; -- 设置当前会话的隔离级别
SET GLOBAL TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; -- 设置全局的隔离级别
SET tx_isolation='read-committed';
保存点savepoint
演示:
set autocommit = 0;
start transaction;
delete from account where id = 25;
savepoint a; -- 设置保存点a
delete from account where id = 28;
rollback to a; -- 回滚到a保存点的位置
delete和truncate在事务中的区别
-- 演示delete
set autocommit = 0;
start transaction;
delete from account;
rollback;-- 演示truncate
set autocommit = 0;
start transaction;
truncate from account;
rollback;
分别执行上面的两段SQL语句,可以发现delete删除的数据可以回滚,而truncate删除的数据不能回滚。
视图
视图:虚拟表,和普通表一样使用(mysql5.1版本出现的新特性,是通过表动态生成的数据)
e.g.查询姓张的学生名和专业名:
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 '张%';
视图的好处:
- 重用SQL语句
- 简化复杂的SQL操作,不必知道它的查询细节
- 保护数据,提高安全性
视图和表的对比:
创建语法的关键字 | 是否占用实际的物理空间 | 使用 | |
---|---|---|---|
视图 | create (or replace) view | 只是保存了SQL逻辑 | 增删改查(一般不能增删改) |
表 | create table | 保存了数据 | 增删改查 |
创建视图
语法:
create view 视图名
as
查询语句;
修改视图
方式一:
create or replace view 视图名 -- 也可以创建视图
as
查询语句;
方式二:
alter view 视图名
as
查询语句;
删除视图
语法:
drop view 视图名,视图名,...;
查看视图结构
desc 视图名;
show create view 视图名; -- 查看视图创建的过程
◆查看所有已创建的视图:
SHOW TABLE STATUS WHERE COMMENT='view';
视图的更新
视图的可更新性和视图中查询的定义有关系,以下类型的视图是不能更新的:
- 包含以下关键字的SQL语句:分组函数、distinct、group by、having、union、union all
- 常量视图
- select中包含子查询
- join连接查询
- from一个不能更新的视图
- where子句的子查询引用了from子句中的表
假如有一个视图:
create or replace view myv1
as
select last_name,email,salary*12 "年薪" from employees;
假如对这个视图进行更新:
INSERT INTO myv1 VALUES('张飞','zf@google.com',1000000);
会报错(他说这个视图是not insertable-into的):
但是假如视图是下面这条,没有“年薪”那个字段:
create or replace view myv2
as
select last_name,email from employees;
执行插入操作:
INSERT INTO myv2 VALUES('张飞','zf@google.com');
可以发现插入成功:
查看employees表,也确实插入了这一条数据,也就说明视图的更新操作是直接影响原来的表的:
变量
分类:
- 系统变量
- 全局变量
- 会话变量
- 自定义变量
- 用户变量
- 局部变量
系统变量
变量由系统提供,不是用户定义的,属于服务器层面的
作用域:
- 全局变量:所有的会话,但是重启会失效(如果要永久的就要改配置文件)
- 会话变量:仅当前会话
查看所有的系统变量
show global|[session] variables; -- 查看全局或会话的系统变量(如果不指定,默认为session),golbal代表全局变量,session代表会话变量。
查看满足条件的部分系统变量
show global|[session] variables like '%char%';
查看指定的某个系统变量的值
select @@golbal.系统变量名; -- 全局变量 select @@session.系统变量名;-- 会话变量(session. 可以省略)
为某个系统变量赋值
set global|[session] 系统变量名 = 值; set @@global|[session].系统变量名=值;
自定义变量
变量是用户自定义的,不是系统提供的
使用步骤:声明、赋值、使用(查看、比较、运算等)
用户变量
作用域:当前会话
声明并初始化(用户变量在声明时必须初始化)
set @用户变量名 = 值; set @用户变量名 := 值; select @用户变量名 := 值;
赋值(更新用户变量的值)
# 方式1:通过set或者select(和声明的语法一样) set @用户变量名 = 值; set @用户变量名 := 值; select @用户变量名 := 值;# 方式2:通过select into select 字段名 into @用户变量名 from 表; -- 将查出的结果赋值给变量,要求查出来的结果必须是一行一列
查看值:
select @用户变量名;
局部变量
作用域:仅仅在定义他的begin end中有效
注:只能应用在begin end中的第一句话
声明
declare 变量名 类型; declare 变量名 类型 default 值;
赋值(和用户变量的一样,但是这个不需要加
@
符号)# 方式1:通过set或者select(和声明的语法一样) set 局部变量名 = 值; set 局部变量名 := 值; select @局部变量名 := 值;# 方式2:通过select into select 字段名 into 局部变量名 from 表;
使用
select 局部变量名;
存储过程和函数
概念:类似于java中的方法
好处:
- 提高代码的重用性
- 简化操作
存储过程
含义:一组预先编译好的SQL语句的集合,可以理解成批处理语句。
好处:
- 提高代码的重用性
- 简化操作
- 减少了编译次数,减少了和数据库服务器的连接次数,提高了效率
创建
create procedure 存储过程名(参数列表) begin 存储过程体(一组合法的SQL语句) end
注意:
参数列表包含3个部分:参数模式 参数名 参数类型
举例:IN stuname VARCHAR(20)
参数模式:
- IN:该参数可以作为输入,也就是该参数需要调用方来传入值
- OUT:该参数可以作为输出,也就是该参数可以作为返回值
- INOUT:既可以作为输入,又可以作为输出
如果存储过程体仅仅只有一句话,那么begin end可以省略。
存储过程体中的每一条SQL语句的结尾要求必须加分号。
结束符号需要使用DELIMITER重新设置:#语法: delimiter 结束标记#案例 delimiter $ -- 使用$作为结束符号
必须使用DELIMITER来重新设置结束符号,要不然begin end里面的每条语句的结束和外面SQL语句的结束都是分号,没法写了。
好像在SQLyog这些客户端是没法执行这些存储过程的语句的,必须要在cmd执行才行。
使用
call 存储过程名(实参列表);
删除
drop procedure 存储过程名;
注意:一次只能删除一个。
查看存储过程的信息
show create procedure 存储过程名;
注意:不能使用desc语句来查看存储过程
修改
存储过程不支持修改,如果要修改的话可以先删除再重新添加。
案例:
空参列表
#案例:插入到admin表中5条数据 delimiter $ create procedure myp1() begininsert into admin(`username`,`password`)values('join','0000'),('lily','0000'),('rose','0000'),('jack','0000'),('tom','0000'); end $ -- 需要前面设置过的$当成存储过程的结尾!#调用 call myp1()$ -- 已经设置了结束符号是$,所以不再使用;
创建带IN模式参数的存储过程
# 案例:根据女神名,查询对应的男神信息DELIMITER $CREATE PROCEDURE myp2(IN beautyName VARCHAR(20))BEGINSELECT bo.*FROM boys boRIGHT JOIN beauty b ON bo.id = b.boyfriend_idWHERE b.name = beautyName;END $
# 判断用户是否登录成功
create procedure myp4(in username varchar(20),in password varchar(20))
begindeclare result int default 0; -- 声明并初始化select count(*) into result -- 赋值from adminwhere admin.username = usernameand admin.password = password;select if(result > 0,'登录成功','登录失败');
end $
创建带OUT模式的存储过程
# 案例:根据女神名,返回对应的男神名 create procedure myp5(in beautyName varchar(20),out boyName varchar(20)) begin select bo.boyName into boyNamefrom boys boinner join beauty b on bo.id = b.boyfriend_idwhere b.name=beautyName end $# 调用: call myp5('小昭', @bName)$ -- 这里相当于顺便定义了用户变量bName select @bName$
创建带INOUT模式参数的存储过程
# 案例:传入a,b两个值,最终a和b都翻倍将返回 create procedure myp8(inout a int,intout b int) beginset a = a * 2;set b = b * 2; end $# 调用 set @m = 10$ set @n = 20$ call myp8(@m,@n)$ select @m,@n$
函数
含义:一组预先编译好的SQL语句的集合,可以理解成批处理语句。
好处:
- 提高代码的重用性
- 简化操作
- 减少了编译次数,减少了和数据库服务器的连接次数,提高了效率
和存储过程的区别:
- 存储过程:可以多个返回,也可以0个返回,适合做批量插入、批量更新
- 函数:只能有1个返回
创建
create function 函数名(参数列表) returns 返回类型 begin 函数体 end
注意:
- 参数列表中的参数只包含两部分(参数名、参数类型),而不包含IN、OUT、INOUT这些模式
- 函数体一定会有return语句,如果没有则会报错。如果return 语句没有放在最后也不报错,但是不建议
- 若函数体重仅有一句话,则可以省略begin end
- 同样需要使用
delimiter
指令来设置结束标记
调用语法
select 函数名(参数列表);
查看函数
show create function 函数名;
删除函数
drop function 函数名;
案例:
无参有返回
#案例: 返回公司的员工个数 create function myf1() returns int begindeclare c int default 0; -- 定义变量select count(*) into c -- 为变量赋值from employees;return c; -- 返回语句 end $
有参有返回
#案例:根据员工名,返回它的工资 create function myf2(empName varchar(20)) returns double beginset @sal = 0; -- 定义用户变量select salary into @sal -- 赋值from employeeswhere last_name = empName;return @sal; -- 返回 end $
流程控制结构
顺序结构:程序从上往下一次执行
分支结构:程序从两条或多条路径中选择一条去执行
循环结构:程序在满足一定条件的基础上,重复执行一段代码
分支结构
IF函数
功能:实现简单的双分支
语法:
IF(表达式1,表达式2,表达式3);
执行顺序:如果表达式1成立,则IF函数返回表达式2的值,否则返回表达式3的值
应用:任何地方
case结构
类似于java中的switch语句,一般用于实现等值判断
语法:
case 变量|表达式|字段 when 要判断的值 then 返回的值1或语句1 when 要判断的值 then 返回的值2或语句2 ... else 返回值n或语句n end case
类似于java中的多重if语句,一般用于区间判断
语法
case 变量|表达式|字段 when 要判断的条件1 then 返回的值1或语句1 when 要判断的条件2 then 返回的值2或语句2 ... else 返回值n或语句n end case
注:
- case结构可以作为表达式,嵌套在其他语句使用,可以放在任何地方。
- case结构也可以作为独立的语句使用,只能放在begin end中。
if结构
功能:实现多重分支
语法:
if 条件1 then 语句1; elseif 条件2 then 语句2; ... else 语句n; end if;
注意:只能应用在begin end中
循环结构
分类:
- while
- loop
- repect
- 注意:位置只能放在begin end中
循环控制:
- iterate(类似于continue)
- leave(类似于break)
while
[标签:] while 循环条件 do循环体 end while [标签];
loop
[标签:] loop循环体 end loop [标签];
这个循环没有结束条件,可以用来模拟死循环。
repect
[标签:] repect循环体 until 结束循环的条件 end repect [标签];
注:循环控制语句(iterate/leave)要循环结构加上标签才能用!
如:
a: while 循环条件 do循环体leave a; -- 结束a这个循环
end while a;
MySQL学习笔记(基础部分)相关推荐
- MySQL学习笔记-基础篇1
MySQL 学习笔记–基础篇1 目录 MySQL 学习笔记--基础篇1 1. 数据库概述与MySQL安装 1.1 数据库概述 1.1.1 为什么要使用数据库 1.2 数据库与数据库管理系统 1.2.1 ...
- MySQL学习笔记-基础篇2
MySQL学习笔记-基础篇2 目录 MySQL学习笔记-基础篇2 8.子查询 8.1 需求分析与问题解决 8.1.1 实际问题 8.1.2 子查询的基本使用 8.1.3 子查询的分类 8.2 单行子查 ...
- MySQL 学习笔记——基础 DQL 查询语言
DQL 查询语言 文章目录 DQL 查询语言 一.简单查询 1.普通简单查询 2.特殊的简单查询 二.条件查询 1.按条件表达式筛选 2.按逻辑表达式筛选 3.模糊查询 三.排序查询 四.常见函数 1 ...
- MySQL学习笔记——基础语句
MySQL默认端口号为3306: 超级用户为root: MySQL常用命令 显示当前服务器版本:select version(); 显示当前日期时间:select now(); 显示当前用户:sele ...
- mysql学习笔记 基础命令
mysql数据库 关系数据库 SQL结构化查询语言, socket介绍 root root DDL:数据定义语言 DML:(data Manioulation)数据操作语言 DCL:(data con ...
- MySQL学习笔记-恶补基础篇
目录 概述 1.初识数据库 1.1.DataBase 1.2.数据库分类 1.3.DBMS(数据库管理系统) 1.4.命令行操作数据库 2.操作数据库 2.1.操作数据库 2.2.数据库列类型 2.3 ...
- MySQL学习笔记——尚硅谷李玉婷经典版MySQL基础笔记(一)
MySQL学习笔记--尚硅谷李玉婷经典版MySQL基础笔记(一) MySQL学习笔记目录 MySQL学习笔记--尚硅谷李玉婷经典版MySQL基础笔记(一) 一.基础知识 1.MySQL的语法规范 2. ...
- Mysql学习笔记(基础)基础sql语句详细记录
数据库学习(基础) // 个人网课学习记录,如果有违规等问题,请联系我删除~ mysql下载安装( 解压版安装配置 下载版安装配置 ) 需求分析:使用cmd命令来创建一个数据库,并对数据库中得一张分类 ...
- MySQL学习笔记一之基础架构
MySQL学习笔记一之架构@TOC 架构图如下 Server层 连接器 负责跟客户端建立连接.获取权限.维持和管理连接 客户端如果太长时间没有动静,连接器会将其自动断开,时间由参数wait_timeo ...
- 【mysql学习笔记整理】
/*mysql学习笔记整理*/ /*常用的数据库操作对象*/ #库的操作 #创建 #数据库的创建 USE mysql; CREATE DATABASE db_x; #删除 #删除数据库 DROP DA ...
最新文章
- LeetCode简单题之买卖股票的最佳时机
- 大数据全体系年终总结
- [数据结构] 迷宫问题(栈和队列,深搜和广搜)
- Vue 脚手架CLI 初始化项目
- 机器学习知识点(二十)矩阵奇异值分解基础知识及Java实现
- 长在华人第一学霸家族的他,到底有多牛?
- css案例学习之id要唯一
- log4net 使用手记
- 口语化讲某些软件如BT,电驴,向日葵等穿透内网原理
- python中等于列表的某一个值为真,python – 获取值等于特定值的列表中的所有元素...
- 什么是php 的精华,在用PHP开发中的精华和技巧总结
- sql优化常用的几种方法_Hive常用性能优化方法实践全面总结
- Sniffer安全技术从入门到精通
- python 特征选择卡方_为什么pythonsklearn特征选择卡方(chi2)测试不是对称的?
- python set和frozenset 异同点学习记录
- 使用Supervisor让你的Swift Perfect服务器项目后台运行
- Java小知识点合集-面向对象
- oracle driver class not found,错误 JDBC Driver class not found: oracle.jdbc.dirver.OracleDriver
- png转pdf, pdf转png
- 上新|设计开发在线协同工具墨刀「设计画布」全新发布