数据库MYSQL笔记
1.对库的操作
create database db_itheima1 charset utf8; #创建数据库,设置编码方式
show create database db_itheima1; #查看数据库的建库信息
show create table 表名; #查看建表语句
show tables; #展示数据库中存在的表
use db_itheima1; #切换使用数据库
select database(); #查看当前数据库
desc 表名; #显示表的结构
drop 数据库 if exists; #删除数据库
drop 表名 if exists; #删除数据表
show engine; #查看数据库存在的引擎
2.字符类型
int(整数)、double(浮点数)、varchar(不固定长度字符串)、char(固定长度0-255字长)、date(时间:年月日)、datetime(时间:年月日时分秒) 、 timestamp(时间戳类型)
字段名 时间日期型 default 默认时间 : 给时间字段指定默认值
3.DDL语句(与数据库和表相关的操作)
CREATE TABLE [IF NOT EXISTS] 表名
( 字段名
列类型属性[注释], 字段名
列类型属性[注释], 字段名
列类型属性[注释] (最后一句不要逗号) )表类型[注释]``
create table stu_info(
`id` INT(4) NOT NULL AUTO_INCREMENT COMMENT '学号', #AUTO_INCREMENT 自增长
`name` VARCHAR(20) NOT NULL DEFAULT '匿名' COMMENT '姓名',
`pwd` VARCHAR(20) NOT NULL DEFAULT '123456' COMMENT'密码',
`sex` VARCHAR(2) NOT NULL DEFAULT '男' COMMENT'性别',
`birthday` DATETIME DEFAULT NULL COMMENT'出生日期',
`address` VARBINARY(100) DEFAULT NULL COMMENT'家庭住址',
`email` VARBINARY(50) DEFAULT NULL COMMENT'邮箱',
PRIMARY KEY(`id`)#id为主键,主键非空且唯一
);
comment'注释';
#unsigned:用于指定整数类型,如int usigned指出为非负数int型数字,只能表示0与正数
alter table 表名 modify 字段名 新数据类型(长度) #修改数据类型
alter table 表名 add 字段名 类型 约束 #往表中添加新的字段名
alter table 表名 change 旧字段名 新字段名 类型(长度) [约束 ] [comment 注释] [约束 ] #修改字段名和字段类型
alter table 旧表名 rename 新表名; #修改表名
alter table 表名 drop 列名; #删除某列
rename table 旧表名 to 新表名 #给表重命名
alter table 表名 add primary key(字段名) #添加主键约束
alter table 表名 drop primary key; #删除主键约束
但如果删除的主键为自增字段(例如AUTO_INCREMENT
),你还需要移除这个属性或使用其他字段作为主键。
4.DML操作(增删改操作)
insert into 表名(列1,列2)values (a1,a2),(b1,b2) #也可使用 insert into 表名 values (a1,a2),(b1,b2) values的值与表列顺序保持一致.
insert into stu(id,name,age) values(1,"周杰",15),(2,"林俊姐",18);
delete from 表名 where 条件判断; #where无条件约束则表中全部数据均删除,一条一条的删除数据记录,效率低.删除数据时,如果列类型为自增,则自增类型未清除.
delete from stu_info where id=1;
update 表名 set 列=值 [where 条件判断]; #无条件约束则表中全部数据均更改,
update stu_info set age=18 where name="王五";
drop table (if exists)表名 #删除表,删除整个表以及表中的所有数据、表结构和相关的元数据(如索引、约束等)。
truncate table 表名; #删除旧表,删除表中的数据而保留表的结构
5.DQL查询语句(基础查询select语句)
基础数据的查询(单表查询)
select [distinct] 字段名,... from 表名; #查询表内数据,以指定的列来实现去重的结果,返回去重的列的信息
select */列 from 表名 where 条件判断;#比较运算符:=、>、<、>=、<=、!=、<>(不等于)
select id from stu_info where age>5;
select的范围查询:
1.select * from 表名 where 字段名 between 范围值1 and 范围值2; #字段名取准确的范围
2.select * from 表名 where 字段名 in (准确值1,准确值2,...); #字段名取准确值
select的逻辑运算符:and(全真为真,否则为假)、or(全假则假,否则为真)、not(取反)
select的模糊查询:
select * from 表名 where 字段名 like '%某个字_';
%表示任意多个任意字符,_表示一个任意字符。
select的非空判断查询:is null/is not null 判断null对象
分组聚合
select 列a|聚合函数(按照列a分组后前面select只能选取列a与聚合函数展示) from 表名 [where 条件] group by 列a;
1)聚合函数是用于对一列数据进行统计,结果会返回一个单一的值; 2)注意:聚合函数会忽略空值进行统计处理。
select 字段名1,字段名2,... from 表名 group by 分组字段名 [having 分组条件];
#where代表筛选条件,优先查询where中的条件,减少查询次数,having条件筛选分组后的过滤数据
结果排序
select * from 表名 [where 条件] [group by 列a] order by 列 desc(降)/asc(升); 默认asc
select * from 表名 [where 条件] [group by 列a] [order by 列 desc/asc] limit n/[n,m]
#取数据n个或者从n行开始取,取m个
6.外键约束(多表查询)
外键是用来让两张表的数据建立连接,从而保证数据的一致性和完整性
父表(主表):外键所关联的表
子表(从表):带有外键的表称为子表
添加外键约束的两种方法
①在建表语句中
create table 子表名(
字段名 数据类型,
……
constraint 外键名称 foreign key(外键字段名) 主表(主表列名)
)
②在外部添加
alter table 表名 add constraint 外键名称 foreign key(外键字段名) references 主表(主表列名);
删除外键:
alter table 表名 drop foreign key 外键名称;
主键关联主键:一对一,两个主键同时同步,主键对主键
多表关系
-
一对一(单表的拆分,用于提升操作效率,在任意一方加入外键,关联另外一方的主键,设置外键为唯一的unique,或者主键对主键)
-
一对多(在数据量多的乙方建立外键.指向另外一张表的主键),
-
多对多(建立第三张中间表,中间表至少包含两个外键,分别包含两方主键),
多表查询
select * from 表1,表2 #无连接条件,笛卡尔积,取表1和表2并集
连接查询:内连接、外连接、交叉连接(union).(自查询和嵌套查询)
内连接:相当于查询两个表的交集部分数据
-
隐式内连接:select 字段列表 from 表1,表2 where 连接条件
-
显式内连接:select 字段列表 from 表1 inner join 表二 on 连接条件
外连接:查询两个表的交集部分数据和x外连接中x表中的所有数据
-
左外连接:查询左表所有数据和两个表交集部分数据
-
右外连接:查询右表所有数据,以及两张表的交集部分数据
select 字段名 from A表名 别名 left [outer] join B表名 别名 on 条件;
select 字段名 from A表名 别名 right [outer] join B表名 别名 on 条件;
自连接:当前表和自身的连接查询,自连接必须使用表别名,利用表的别名对表进行引用(涉及到一张表,对一张表连接查询两次),自连接查询可以是内连接查询,也可以是外连接查询
select * from 表 别名1,表 别名2 on 条件
联合查询:将多次查询的结果合并起来,形成一个新的查询结果集两个查询返回字段列表需要保持一致
select 字段列表 from 表A...
union [all]
select 字段列表 from 表B...
union all对所有的数据进行整合,而union对数据整合后进行去重操作.
子查询(嵌套查询):sql语句中嵌套select 的语句 select * from 表 where 条件=(select * from 表);
子查询外部的语句可以是insert/update/delete/select中的任何一个.
根据子查询结果不同:
-
标量子查询(子查询结果为单个值)、
-
列子查询(子查询结果为一列):
操作符:in在...之中、not in不在..之中、any(任意一个)与some(任意)均选取最小值、all(所有)
查询比财务部工资都高的员工信息
-
行子查询(子查询结果为一行)、
操作符:in在...之中、not in不在..之中、=、!=
-
表子查询(子查询结果为多行多列):子查询当作临时表使用
7.DCL管理用户以及用户权限
查询用户:use mysql; select * from user;
创建用户: create user '用户名'@'主机名' identified by '密码';#只能被主机名的访问,主机名可以用%通配,表示可以被所有主机访问
修改密码:alter user '用户名'@'主机名' identified with mysql_native_passward by '新密码';
删除用户: drop user '用户名'@'密码';
DCL的权限控制
-
查询权限:show grants for '用户名'@'主机名';
-
授予权限:grant 权限列表 on 数据库名.表名 to '用户名'@'主机名';
-
撤销权限:revoke 权限列表 on 数据库名.表名 from '用户名'@'主机名';
多个权限用逗号隔开,授权时数据库名和表名都可以使用*代表所有.
8.事务
事务过程
一组操作的集合叫事务,它是不可分割的工作单位,事务会把所有的操作作为一个整体一起向系统提交或者撤销操作请求,即这些操作要么同时成功,要不同时失败.例如转账操作:必须把转出金额和转入金额作为一个整体,当操作失败时,需要所有操作同时失败,否则导致数据的错误.
方式一:通过设置手动提交方式,当没有错误时,提交事务;事务出错时,回滚事务
查看事务提交方式:select @@autocommit
设置事务提交方式:set @@autocommit=0 手动提交方式
提交事务:commit; 回滚事务:rollback;
方式二:开启事务: start transaction或begin ;提交事务:commit ;回滚事务: rollback ;
create database if not exists mydb12_transcation; use mydb12_transcation; -- 创建账户表 create table account( id int primary key, -- 账户id name varchar(20), -- 账户名 money double -- 金额 ); -- 插入数据 insert into account values(1,'zhangsan',1000); insert into account values(2,'lisi',1000); -- 设置MySQL的事务为手动提交(关闭自动提交) select @@autocommit; set autocommit = 0; #手动提交事务 -- 模拟账户转账 -- 开启事务 begin; update account set money = money - 200 where name = 'zhangsan'; update account set money = money + 200 where name = 'lisi'; -- 提交事务 commit; -- 如果转账中的任何一条出现问题,则回滚事务 rollback;
事务的四大特性(ACID):
-
原子性(事务是不可分割的最小操作单元)、
-
一致性(事务完成时,使所有的数据都保持一致)、
-
隔离性(保证事务在不受外部并发操作影响的独立环境下运行)、
-
持久性(事务一旦提交或回滚,它对数据库的数据改变是永久的)
并发事务问题
脏读:一个事务读取到另外一个事务还没有提交的数据
不可重复读:一个事务先后读取同一条记录,但两次读取的数据不同,称为不可重复读
幻读:一个事务按照条件查询数据时,没有对应的数据行,但是插入数据时,又发现这行数据已经存在.
事务的隔离级别
Isolate,顾名思义就是将事务与另一个事务隔离开,为什么要隔离呢?如果一个事务正在操作的数据被另一个事务修改或删除了,最后的执行结果可能无法达到预期。如果没有隔离性还会导致其他问题。
-- 查看隔离级别 show variables like '%isolation%’; -- 设置隔离级别 /* set session transaction isolation level 级别字符串 级别字符串:read uncommitted、read committed、repeatable read、serializable */ -- 设置read uncommitted set session transaction isolation level read uncommitted; -- 设置read committed set session transaction isolation level read committed; -- 设置repeatable read set session transaction isolation level repeatable read; -- 设置serializable set session transaction isolation level serializable;
9.函数
字符函数
①length(str)函数 :字符串长度 ②concat(str1,str2,...)函数 :字符串连接 ③upper(str)、lower(str)函数 :转大写、小写 ④substr(str,start,len)函数 :从指定位置截取指定个数的字符串 ⑤instr(str,要查找的子串)函数 :判断是否存在 返回 1 或者 0 ⑥trim(str)函数 : 去除两端空格 ⑦lpad(str,len,填充字符)、rpad(str,len,填充字符)函数:左右两边指定个数填充,然后返回len长度的字符. ⑧replace(str,子串,另一个字符串)函数 : 字符串替换.
数学函数
①round(x,保留位数)函数: 四舍五入保留小数位. ②ceil(x)函数 :天花板函数--向上取整 ③floor(x)函数 :地板函数--向下取整 ④truncate(x,D)函数 : 按照D的长度值直接截取小数部分. ⑤mod(被除数,除数)函数 : 求余数 ⑥pow(x,D)函数 : x的D次方
日期函数
①日期格式 ②now()函数 :当前日期和时间 ③curdate()函数 :当前日期 ④curtime()函数 :当前时间 ⑤获取日期和时间中的年、月、日、时、分、秒 ⑥weekofyear()函数 :一年的第几周 ⑦ quarter()函数 :一年中的季度 ⑧ str_to_date()函数 :字符串转时间类型 ⑨date_format()函数 :格式化时间字符串 ⑩date_add(日期,interval num 时间)函数 :添加日期 ⑪last_day()函数 :月度最后一天 ⑫datediff(end_date,start_date)函数 : 时间差 ⑬timestampdiff(unit,start_date,end_date)函数计算两个时间返回的年/月/天数; unix_timestamp(date) : 把日期转毫秒值 from_unixtime(int): 把毫秒值转 日期
MYSQL的进阶操作
Mysql的引擎
在大数据开发期间,要处理海量数据,就需要来了解MySQL的多种引擎了。MySQL引擎:启动器。
(1)InnoDB是一个可靠和高性能的事务处理引擎,但是它不支持全文搜索; [逻辑单元]。大数据开发时,使用的是InnoDB引擎,支持事务,行级锁,提高并发访问性能,支持外键约束.引擎为InnoDB表结构产生InnoDB文件,存储表结构,数据与索引.在表空间文件中包含段,在段中包含多区,在区中包含多页,在页中包含多行.
(2)MyISAM是一个性能极高的引擎,它支持全文搜索,但不支持[事务]处理; 引擎为myisam 的表会产生三个文件:MYD存储数据;MYI存储索引;sdi存储表结构信息 (3)Memory在功能等同于MyISAM,但由于数据存储在内存中,速度很快,但占用内存大,因此几乎不使用此引擎.支持哈希索引,sdi存储表结构文件,其余数据信息存储在内存之中.
设定引擎的语句:在创建表结尾处添加【engine = 引擎名】。
create table 表名( 字段名 数据类型(长度) [约束], ... ) engine = 引擎名 default charset utf8;
MySQL的视图
MySQL的视图(View)是一种虚拟存在的表,其内容由查询定义。同真实的表一样,视图包含一系列带有名称的列和行数据。但是,视图并不在数据库中以存储的数据值集形式存在。行和列数据来自由定义视图的查询所引用的表,并且在引用视图时动态生成。
视图优点:
-
简化复杂的SQL操作:在编写复杂的SQL时,使用视图可以简化操作。
-
安全性:通过视图,可以只显示用户需要的部分数据,隐藏敏感数据。
-
逻辑数据独立性:当表结构发生变化时,可以通过修改视图来保持应用程序代码不变。
创建视图
使用CREATE VIEW
语句来创建视图。例如:
CREATE VIEW view_name AS SELECT column1, column2, ... FROM table_name WHERE condition;
使用视图
一旦创建了视图,就可以像查询普通表一样查询视图。例如:
SELECT * FROM view_name;
通过视图更新数据
如果视图是基于单个表并且没有使用聚合函数,那么可以像更新表一样更新视图。但是,如果视图基于多个表或使用了聚合函数,那么通常不能更新视图。
视图数据的更新会改变原表数据内容
UPDATE 表名 set 属性=值 where condition example: update emp_view set comm=50 where empno='1001';
删除视图
使用DROP VIEW
语句来删除视图。例如:
DROP VIEW view_name;
示例
假设我们有一个名为employees
的表,包含id
、name
、salary
和department_id
等列。如果我们只想查看薪资高于某个值的员工,可以创建一个视图:
CREATE VIEW high_salary_employees AS SELECT id, name, salary FROM employees WHERE salary > 5000;
然后,我们可以查询这个视图来获取薪资高于5000的员工信息:
SELECT * FROM high_salary_employees;
注意事项
-
视图没有实际的物理记录,每次查询视图时,都是从它所基于的表中检索数据。
-
如果视图基于的表结构发生变化,可能会影响视图的查询结果。
-
在某些情况下,直接查询视图可能比查询其基于的表更慢,因为视图可能包含复杂的查询逻辑。因此,在使用视图时应该权衡其优点和缺点。
MYSQL触发器
MySQL的触发器(Trigger)是一种特殊的存储过程,它会在某个特定的事件发生时自动执行。这些事件通常与数据表的INSERT、UPDATE或DELETE操作相关。触发器可以帮助自动检查或修改数据,保持数据完整性,或者在某些操作发生时自动记录日志等。
创建触发器
创建触发器的基本语法如下:
CREATE TRIGGER trigger_name [BEFORE | AFTER] [INSERT | UPDATE | DELETE] ON table_name FOR EACH ROW BEGIN -- 触发器要执行的SQL语句 END;
-
trigger_name
:触发器的名称。 -
BEFORE | AFTER
:指定触发器是在操作之前还是之后执行。 -
INSERT | UPDATE | DELETE
:指定触发器响应的操作类型。 -
table_name
:触发器关联的表名。 -
FOR EACH ROW
:表示触发器会对每一行数据触发。
示例
假设我们有两个表,一个是orders
表,另一个是order_logs
日志表。每当在orders
表中插入一条新订单时,我们想在order_logs
表中记录这个操作。
CREATE TABLE orders ( order_id INT AUTO_INCREMENT PRIMARY KEY, customer_id INT, amount DECIMAL(10, 2) ); CREATE TABLE order_logs ( log_id INT AUTO_INCREMENT PRIMARY KEY, action VARCHAR(50), order_id INT, timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP ); DELIMITER // CREATE TRIGGER after_order_insert AFTER INSERT ON orders FOR EACH ROW BEGIN INSERT INTO order_logs (action, order_id) VALUES ('INSERT', NEW.order_id); END; // DELIMITER ;
在这个例子中,我们创建了一个名为after_order_insert
的触发器,它在orders
表插入新行之后执行。触发器会将操作类型('INSERT')和新插入的order_id
记录到order_logs
表中。
NEW
:在INSERT
和UPDATE
触发器中,
NEW
关键字用于引用新插入或更新后的行的列值。
OLD
:在UPDATE
和DELETE
触发器中
OLD
关键字用于引用更新前或删除前的行的列值。
删除触发器
如果需要删除触发器,可以使用以下SQL命令:
DROP TRIGGER trigger_name;
将trigger_name
替换为要删除的触发器的名称。
注意事项
-
触发器是与表相关联的,当对表进行操作时,触发器会自动执行。
-
触发器可以引用
NEW
和OLD
关键字来访问触发事件中涉及的新值和旧值。 -
在使用触发器时,需要注意性能和逻辑复杂性,因为触发器会在每个相关行上执行,可能会影响数据库性能。
-
触发器中执行的SQL语句应该尽量简单且高效,以避免不必要的性能开销。
数据库的备份
全量备份与增量备份
-
全量备份:备份整个数据库,并存储备份文件。需要较长时间完成,并占用较大存储空间,但恢复时较为简单方便。
-
增量备份:在全量备份的基础上,只备份新增或发生改变的数据。节省备份时间和存储空间,但恢复时需要先还原全量备份,再应用增量备份。
mysqldump
-
描述:逻辑备份工具,适用于所有存储引擎,支持温备、完全备份、部分备份,对InnoDB存储引擎支持热备。
热备和冷备是数据库备份中的两种主要策略,它们在多个方面存在显著区别。
热备(Hot Standby):
定义:热备是指备份系统在主系统正常运行时也处于运行状态,并随时准备接管主系统的工作。
特点:实时性强,故障发生时能立即接管工作,确保业务连续性。
成本:相对较高,因为需要维护两个同时运行的系统。
应用场景:适用于对系统可用性要求极高的场景,如金融交易系统、在线服务等。
冷备(Cold Standby):
定义:冷备是指备份系统在主系统发生故障或停机后才启动运行,并承担故障设备的工作任务。
特点:成本较低,因为备份系统在大多数情况下都处于待机状态。但切换时需要手动操作。
成本:相对较低,因为备份系统大部分时间不运行。
应用场景:适用于对系统可用性要求不太高,但需要考虑数据安全的场景。
#基本语法 mysqldump [options] database [tables] > outputfile.sql 备份整个数据库 mysqldump -u root -p --single-transaction mydatabase > mydatabase_backup.sql 备份多个数据库 mysqldump -u root -p --databases database1 database2 > databases_backup.sql 备份表 mysqldump -u root -p mydatabase mytable > mytable_backup.sql
9.python连接mysql数据库
from pymysql import Connection#导入库 conn=Connection(host='localhost',user='root',port=3306,password='123456',charset='utf8',autocommit=True)#建立python与数据库的连接 cursor=conn.cursor()#获取游标对象 conn.select_db("db_user")#选择数据库 cursor.execute("drop table if exists company1;") cursor.execute("drop database if exists company1;")#执行数据库操作 result=cursor.fetchall()#获取查询语句的结果 #conn.close()#断开连接 cursor.execute("insert into user values(2,'赵四','狗剩')") cursor.commit() #添加操作需要确认,在连接的时候选择autocommit参数为True表示自动确认;或者在每次的插入操作之后使用commit()方法手动确认 conn.close()#断开连接
数据库开发
MYSQL的存储过程: 存储过程就是一组SQL语句集,功能强大,可以实现一些比较复杂的逻辑功能,类似于JAVA语言中的方法; 存储过程就是数据库 SQL 语言层面的代码封装与重用。
特性:
有输入输出参数,可以声明变量,有if/else, case,while等控制语句,通过编写存储过程,可以实现复杂的逻辑功能; 函数的普遍特性:模块化,封装,代码复用; 速度快,只有首次执行需经过编译和优化步骤,后续被调用可以直接执行,省去以上步骤;
存储过程与数据库相关联,同个数据库中不存在名字相同的存储过程
存储过程的定义:
delimiter 自定义结束符号 create procedure 储存名([ in ,out ,inout ] 参数名 数据类形...) begin sql语句 end 自定义的结束符合 delimiter;
example:
delimiter $$ create procedure proc01() begin select empno,ename from emp; end $$ delimiter ; -- 调用存储过程proc01 call proc01(); ---删除存储过程proc01 drop procedure proc01;
声明局部变量:用户自定义,在begin/end块中有效
--声明变量 declare var_name type [default var_value]; --举例: declare nickname varchar(32); ---操作: delimiter $$ create procedure proc02() begin declare var_name01 varchar(20) default ‘aaa’; -- 定义局部变量,默认值为aaa set var_name01 = ‘zhangsan’; select var_name01; end $$ delimiter ; -- 调用存储过程 call proc02(); call mydb7_procedure(数据库名).proc02(); --也可以通过数据库名.存储过程调用()
select ... into 变量赋值
select col_name [...] into var_name[,...] from table_name wehre condition 其中: col_name 参数表示查询的字段名称; var_name 参数是变量的名称; table_name 参数指表的名称; condition 参数指查询条件。 注意:当将查询结果赋值给变量时,该查询语句的返回结果只能是单行单列 example: delimiter $$ create procedure proc03() begin declare my_ename varchar(20) ; select ename into my_ename from emp where empno=1001; #赋值语句,无输出值 select my_ename; end $$ delimiter ; -- 调用存储过程 call proc03(); '''该存储过程将empno=1001数据中的ename值赋值给了my_ename empno=1001时,ename='甘宁',接着进行into赋值将'甘宁'赋值给my_ename'''
用户变量:当前会话(连接)有效
语法: @var_name 不需要提前声明,使用即声明 delimiter $$ create procedure proc04() begin set @var_name01 = 'ZS'; end $$ delimiter; call proc04() ; select @var_name01 ; --可以看到结果
系统变量:
系统变量又分为全局变量与会话变量 全局变量在MYSQL启动的时候由服务器自动将它们初始化为默认值,这些默认值可以通过更改my.ini这个文件来更改。 会话变量在每次建立一个新的连接的时候,由MYSQL来初始化。MYSQL会将当前所有全局变量的值复制一份,作为会话变量。也就是说,如果在建立会话以后,没有手动更改过会话变量与全局变量的值,那所有这些变量的值都是一样的。 全局变量与会话变量的区别就在于,对全局变量的修改会影响到整个服务器,但是对会话变量的修改,只会影响到当前的会话(也就是当前的数据库连接)。 有些系统变量的值是可以利用语句来动态进行更改的,但是有些系统变量的值却是只读的,对于那些可以更改的系统变量,我们可以利用set语句进行更改。
系统变量-会话变量:由系统提供,当前会话(连接)有效
语法: @@session.var_name -- 查看会话变量 show session variables; -- 查看某会话变量 select @@session.auto_increment_increment; -- 修改会话变量的值 set session sort_buffer_size = 50000; set @@session.sort_buffer_size = 50000 ; --只能修改会话变量,无法创建会话变量
参数的传递
--in 表示传入的参数,可以传入数值或者变量,即使传入变量,并不会更改变量的值,可以内部更改,仅仅作用在函数范围内。 ---------------------------------传入参数 :in------------------------------------------ -- 封装有参数的存储过程 传入员工编号,查找员工信息 delimiter $$ create procedure dec_param01(in param_empno varchar(20)) begin select * from emp where empno = param_empno; end $$ delimiter ; call dec_param01('1001'); -- 封装有参数的存储过程,可以通过传入部门名和薪资,查询指定部门,并且薪资大于指定值的员工信息 delimiter $$ create procedure dec_param0x(in dname varchar(50),in sal decimal(7,2)) begin select * from dept a, emp b where b.sal > sal and a.dname = dname; end $$ delimiter ; call dec_param0x('学工部',20000); --out 表示从存储过程内部传值给调用者 ----------------------------------传出参数:out---------------------------------------- use mysql7_procedure; -- 封装有参数的存储过程,传入员工编号,返回员工名字 delimiter $$ create procedure proc08(in empno int ,out out_ename varchar(50) ) begin select ename into out_ename from emp where emp.empno = empno; end $$ delimiter ; call proc08(1001, @o_ename); select @o_ename; -- 封装有参数的存储过程,传入员工编号,返回员工名字和薪资 delimiter $$ create procedure proc09(in empno int ,out out_ename varchar(50) ,out out_sal decimal(7,2)) begin select ename,sal into out_ename,out_sal from emp where emp.empno = empno; end $$ delimiter ; call proc09(1001, @o_dname,@o_sal); select @o_dname; select @o_sal; in 输入参数,意思说你的参数要传到存储过程的过程里面去,在存储过程中修改该参数的值不能被返回 out 输出参数:该值可在存储过程内部被改变,并向外输出 inout 输入输出参数,既能输入一个值又能传出来一个值)
if条件判断
语法
if 判断条件 then ....; elseif 判断条件 then ...; else ....; end if;
操作:
------------------流程控制-->判断------------------------------------------------------ -- 输入学生的成绩,来判断成绩的级别: /* score < 60 :不及格 score >= 60 , score <80 :及格 score >= 80 , score < 90 :良好 score >= 90 , score <= 100 :优秀 score > 100 :成绩错误 */ delimiter $$ create procedure proc_12_if(in score int) begin if score < 60 then select '不及格'; elseif score < 80 then select '及格' ; elseif score >= 80 and score < 90 then select '良好'; elseif score >= 90 and score <= 100 then select '优秀'; else select '成绩错误'; end if; end $$ delimiter ; call proc_12_if(120) -- 输入员工的名字,判断工资的情况。 delimiter $$ create procedure proc12_if(in in_ename varchar(50)) begin declare result varchar(20); declare var_sal decimal(7,2); select sal into var_sal from emp where ename = in_ename; if var_sal < 10000 then set result = '试用薪资'; elseif var_sal < 30000 then set result = '转正薪资'; else set result = '元老薪资'; end if; select result; end$$ delimiter ; call proc12_if('庞统');
case when条件判断
语法
-- 语法一(类比java的switch): case case_value when when_value then statement_list; [when when_value then statement_list] ...; [else statement_list]; end case; -- 语法二 case when 判断条件(example:i=1) then statement_list; [when 判断条件 then statement_list] ...; [else statement_list]; end case;
操作
---CASE是另一个条件判断的语句,类似于编程语言中的switch语法 -- 语法一(类比java的switch): delimiter $$ create procedure proc14_case(in pay_type int) begin case pay_type when 1 then select '微信支付' ; when 2 then select '支付宝支付' ; when 3 then select '银行卡支付'; else select '其他方式支付'; end case ; end $$ delimiter ; call proc14_case(2); call proc14_case(4); -- 语法二: delimiter $$ create procedure proc_15_case(in score int) begin case when score < 60 then select '不及格'; when score < 80 then select '及格' ; when score >= 80 and score < 90 then select '良好'; when score >= 90 and score <= 100 then select '优秀'; else select '成绩错误'; end case; end $$ delimiter ; call proc_15_case(88);
while循环的使用
格式:
## 标签的作用类似于定位符,方便leave和iterate跳出循环的时候定位while 【标签:】while 循环条件 do 循环体; end while 【标签】; while+leave(跳出循环) 【标签:】while 循环条件 do 循环体; if 判断条件 then leave [标签] #跳出循环 end while 【标签】; while+iterate(跳出本次循环,进行下次循环) 【标签:】while 循环条件 do 循环体; if 判断条件 then iterate [标签] #跳出循环 end while 【标签】;
操作
-- -------存储过程-while delimiter $$ create procedure proc16_while1(in insertcount int) begin declare i int default 1; label:while i<=insertcount do insert into user(uid,username,`password`) values(i,concat('user-',i),'123456'); set i=i+1; end while label; end $$ delimiter ; call proc16_while(10); ---------- 存储过程 while + leave跳出循环 truncate table user; delimiter $$ create procedure proc16_while2(in insertcount int) begin declare i int default 1; label:while i<=insertcount do insert into user(uid,username,`password`) values(i,concat('user-',i),'123456'); if i=5 then leave label; end if; set i=i+1; end while label; end $$ delimiter ; call proc16_while2(10); -- -------存储过程-while+iterate(跳出当前循环,接着进行下次循环过程) truncate table user; delimiter $$ create procedure proc16_while3(in insertcount int) begin declare i int default 1; label:while i<=insertcount do set i=i+1; if i=5 then iterate label; end if; insert into user(uid,username,`password`) values(i,concat('user-',i),'123456'); end while label; end $$ delimiter ; call proc16_while3(10);
repeat循环
格式:
[标签:]repeat 循环体; until 条件表达式 end repeat [标签];
操作:
-- -------存储过程-循环控制-repeat use mysql7_procedure; truncate table user; delimiter $$ create procedure proc18_repeat(in insertCount int) begin declare i int default 1; label:repeat insert into user(uid, username, password) values(i,concat('user-',i),'123456'); set i = i + 1; until i > insertCount end repeat label; select '循环结束'; end $$ delimiter ; call proc18_repeat(100);
循环loop
loop允许你重复执行一段代码,直到满足某个条件来退出循环。与 WHILE
和 REPEAT
循环不同,LOOP
循环没有内置的退出条件,你需要使用 LEAVE
语句来明确地退出循环。
格式:
[标签:] loop 循环体; if 条件表达式 then leave [标签]; end if; end loop;
操作:
-- -------存储过程-循环控制-loop truncate table user; delimiter $$ create procedure proc19_loop(in insertCount int) begin declare i int default 1; label:loop insert into user(uid, username, password) values(i,concat('user-',i),'123456'); set i = i + 1; if i > 5 then leave label; end if; end loop label; select '循环结束'; end $$ delimiter ; call proc19_loop(10);
游标
游标(cursor)是用来存储查询结果集的数据类型 , 在存储过程和函数中可以使用光标对结果集进行循环的处理。光标的使用包括光标的声明、OPEN、FETCH 和 CLOSE.
格式:
-- 声明游标 declare cursor_name cursor for select_statement -- 打开游标 open cursor_name -- 取值游标 fetch cursor_name into var_name [, var_name] ... -- 关闭游标 close cursor_name
操作:
use mysql7_procedure; delimiter $$ create procedure proc20_cursor(in in_dname varchar(50)) begin -- 定义局部变量 declare var_empno varchar(50); declare var_ename varchar(50); declare var_sal decimal(7,2); -- 声明游标 declare my_cursor cursor for select empno , ename, sal from dept a ,emp b where a.deptno = b.deptno and a.dname = in_dname; -- 打开游标 open my_cursor; -- 通过游标获取每一行数据 label:loop fetch my_cursor into var_empno, var_ename, var_sal; select var_empno, var_ename, var_sal; leave label; end loop label; -- 关闭游标 close my_cursor; end -- 调用存储过程 call proc20_cursor('销售部');
异常处理-HANDLER句柄
MySql存储过程也提供了对异常处理的功能:通过定义HANDLER来完成异常声明的实现. 官方文档:MySQL :: MySQL 5.7 Reference Manual :: 13.6.7.2 DECLARE ... HANDLER Statement
格式:
DECLARE handler_action HANDLER FOR condition_value [, condition_value] ... statement handler_action: { CONTINUE #继续 | EXIT #退出 | UNDO #撤销 } condition_value: { mysql_error_code #MySQL的特定错误代码。 | condition_name #自定义的条件名。使用 DECLARE ... CONDITION 语句定义自己的条件,并在 后续的 DECLARE ... HANDLER 中引用它们。 | SQLWARNING #表示任何非严重的SQL警告 | NOT FOUND #与游标(cursor)一起使用,表示游标中没有更多的行可供检索。 | SQLEXCEPTION #表示除了 NOT FOUND 以外的任何SQL错误或警告。这是一个通用的异常处理器, 用于捕获未明确列出的其他所有错误或警告。
在语法中,变量声明、游标声明、handler声明是必须按照先后顺序书写的,否则创建存储过程出错。
操作:
drop procedure if exists proc21_cursor_handler; -- 需求:输入一个部门名,查询该部门员工的编号、名字、薪资 ,将查询的结果集添加游标 delimiter $$ create procedure proc20_cursor(in in_dname varchar(50)) begin -- 定义局部变量 declare var_empno int; declare var_ename varchar(50); declare var_sal decimal(7,2); declare flag int default 1; -- --------------------- -- 声明游标 declare my_cursor cursor for select empno,ename,sal from dept a, emp b where a.deptno = b.deptno and a.dname = in_dname; -- 定义句柄,当数据未发现时将标记位设置为0 declare continue handler for NOT FOUND set flag = 0; -- 打开游标 open my_cursor; -- 通过游标获取值 label:loop fetch my_cursor into var_empno, var_ename,var_sal; -- 判断标志位 if flag = 1 then select var_empno, var_ename,var_sal; else leave label; end if; end loop label; -- 关闭游标 close my_cursor; end $$; delimiter ; call proc21_cursor_handler('销售部');
预处理
准备(Prepare)SQL语句
使用PREPARE
语句来准备一条SQL语句,并用占位符(通常是?
)替换要参数化的值。
stmt_name为预处理语句的名字,可以使用名字调用
PREPARE stmt_name FROM sql语句模板; #准备(或编译)一个SQL语句模板。 --PREPARE stmt_name FROM 'SELECT * FROM users WHERE username = ? AND password = ?'; ?为占位符
设置参数
SET @p1 = 'john_doe'; SET @p2 = 'password123';
执行处理:
EXECUTE stmt_name USING @p1, @p2; 或 EXECUTE stmt_name USING 'john_doe', 'password123';
释放资源:
DEALLOCATE PREPARE stmt_name; 或 DROP PREPARE stmt_name;
-- EXTRACT(unit FROM date)截取时间的指定位置值
unit为参数:year(年)/month(月)/week(周末)/day(天)/hour(小时)/quarter(刻度)/minute(分钟)/秒
date需要是一个日期类型的数据,从非日期或时间值中提取部分,MySQL将返回一个错误。
-- DATE_ADD(date,INTERVAL expr unit) 日期运算 -- LAST_DAY(date) 获取日期的最后一天 -- YEAR(date) 返回日期中的年 -- MONTH(date) 返回日期的月 -- DAYOFMONTH(date) 返回日
example:
-- 思路:循环构建表名 user_2021_11_01 到 user_2020_11_30;并执行create语句。 use mysql7_procedure; drop procedure if exists proc22_demo; delimiter $$ create procedure proc22_demo() begin declare next_year int; declare next_month int; declare next_month_day int; declare next_month_str char(2); declare next_month_day_str char(2); -- 处理每天的表名 declare table_name_str char(10); declare t_index int default 1; -- declare create_table_sql varchar(200); -- 获取下个月的年份 set next_year = year(date_add(now(),INTERVAL 1 month)); -- 获取下个月是几月 set next_month = month(date_add(now(),INTERVAL 1 month)); -- 下个月最后一天是几号 set next_month_day = dayofmonth(LAST_DAY(date_add(now(),INTERVAL 1 month))); if next_month < 10 then set next_month_str = concat('0',next_month); else set next_month_str = concat('',next_month); end if; while t_index <= next_month_day do if (t_index < 10) then set next_month_day_str = concat('0',t_index); else set next_month_day_str = concat('',t_index); end if; -- 2021_11_01 set table_name_str = concat(next_year,'_',next_month_str,'_',next_month_day_str); -- 拼接create sql语句 set @create_table_sql = concat( 'create table user_', table_name_str, '(`uid` INT ,`ename` varchar(50) ,`information` varchar(50)) COLLATE=\'utf8_general_ci\' ENGINE=InnoDB'); -- FROM后面不能使用局部变量! prepare create_table_stmt FROM @create_table_sql; execute create_table_stmt; DEALLOCATE prepare create_table_stmt; set t_index = t_index + 1; end while; end $$ delimiter ; call proc22_demo();
数据库的索引
索引:存储引擎用来快速查找记录的一种数据结构
索引的分类:hash索引和B+Tree索引
Hash索引: Hash索引通过哈希函数将数据的键值映射为一个哈希值。
B+Tree索引:
B+Tree是一种平衡的树结构,能够自动调整自身的高度以适应插入和删除操作。 高度平衡:B+Tree是一种平衡的树结构,能够自动调整自身的高度以适应插入和删除操作。 多路搜索:B+Tree的每个节点可以容纳多个键和指针,这意味着每个节点可以存储更多的数据,减少了树的深度,从 而减少了磁盘I/O次数。 有序存储:B+Tree的叶子节点通过指针相互连接,形成一个有序的链表。 可扩展性:B+Tree支持高效的插入和删除操作,并且可以在不改变树结构的情况下扩展或收缩。 支持重复键和范围查询:B+Tree允许存在重复的键,这对于处理现实世界中的数据非常重要。此外,B+Tree还支持范围查询,可以获取一个范围内的所有数据,而不仅仅是匹配给定键的数据。 高效的文件系统索引:B+Tree常被用作文件系统中的索引结构,因为它能够高效地处理大量的数据。文件系统通常需要快速的读取和写入操作,而B+Tree正是满足这些要求的理想选项。 易于实现和维护:相比其他树结构,B+树的实现较为简单。它的算法和数据结构容易理解,并且有许多已经实现好的库可以直接使用。此外,B+树的维护也相对简单,因为它具有自平衡的特性。
索引的特点:
索引的优点:
大大加快数据的查询速度
使用分组和排序进行数据查询时,可以显著减少查询时分组和排序的时间
创建唯一索引,能够保证数据库表中每一行数据的唯一性
在实现数据的参考完整性方面,可以加速表和表之间的连接
索引的缺点:
创建索引和维护索引需要消耗时间,并且随着数据量的增加,时间也会增加
索引需要占据磁盘空间
对数据表中的数据进行增加,修改,删除时,索引也要动态的维护,降低了维护的速度
创建索引的原则 创建索引的原则 更新频繁的列不应设置索引 数据量小的表不要使用索引(毕竟总共2页的文档,还要目录吗?) 重复数据多的字段不应设为索引(比如性别,只有男和女,一般来说:重复的数据超过百分之15就不该建索引) 首先应该考虑对where 和 order by 涉及的列上建立索引
查看数据库所有索引 -- select * from mysql.innodb_index_stats
a where a.database_name
= '数据库名’; select * from mysql.innodb_index_stats
a where a.database_name
= 'mydb5';
查看表中所有索引
--select * from mysql.innodb_index_stats
a where a.database_name
= '数据库名' and a.table_name like '%表名%’; select * from mysql.innodb_index_stats
a where a.database_name
= 'mydb5' and a.table_name like '%student%';
-- 3、查看表中所有索引 --show index from table_name; show index from student;
删除索引
drop index 索引名 on 表名 -- 或 alter table 表名 drop index 索引名
普通索引
MySQL中基本索引类型,没有什么限制,允许在定义索引的列中插入重复值和空值,纯粹为了查询数据更快一点。
#添加普通索引的方式 create database mydb5; use mydb5; -- 方式1-创建表的时候直接指定 create table student( sid int primary key, card_id varchar(20), name varchar(20), gender varchar(20), age int, birth date, phone_num varchar(20), score double, index index_name(name) -- 给name列创建索引 ); -- 方式2-直接创建 -- create index indexname on tablename(columnname); create index index_gender on student(gender); -- 方式3-修改表结构(添加索引) -- alter table tablename add index indexname(columnname) alter table student add index index_age(age);
唯一索引
-- 方式1-创建表的时候直接指定 create table student2( sid int primary key, card_id varchar(20), name varchar(20), gender varchar(20), age int, birth date, phone_num varchar(20), score double, unique index_card_id(card_id) -- 给card_id列创建索引 ); -- 方式2-直接创建 -- create unique index 索引名 on 表名(列名) create unique index index_card_id on student2(card_id); -- 方式3-修改表结构(添加索引) -- alter table 表名 add unique [索引名] (列名) alter table student2 add unique index_phone_num(phone_num)
主键索引
每张表一般都会有自己的主键,当我们在创建表时,MySQL会自动在主键列上建立一个索引,这就是主键索引。主键是具有唯一性并且不允许为NULL,所以他是一种特殊的唯一索引。
-- 方式1-创建表的时候直接指定 create table student2( sid int primary key, card_id varchar(20), name varchar(20), gender varchar(20), age int, birth date, phone_num varchar(20), score double, unique index_card_id(card_id) -- 给card_id列创建索引 ); -- 方式2-直接创建 -- create unique index 索引名 on 表名(列名) create unique index index_card_id on student2(card_id); -- 方式3-修改表结构(添加索引) -- alter table 表名 add unique [索引名] (列名) alter table student2 add unique index_phone_num(phone_num)
组合索引
组合索引也叫复合索引,指的是我们在建立索引的时候使用多个字段,例如同时使用身份证和手机号建立索引,同样的可以建立为普通索引或者是唯一索引。 复合索引的使用复合最左原则。
-- 组合索引 use mydb5; -- 创建索引的基本语法-- 普通索引 -- create index indexname on table_name(column1(length),column2(length)); create index index_phone_name on student(phone_num,name); -- 操作-删除索引 drop index index_phone_name on student; -- 创建索引的基本语法-- 唯一索引 create unique index index_phone_name on student(phone_num,name);
select * from student where name = '张三';
select * from student where phone_num = '15100046637';
select * from student where phone_num = '15100046637' and name = '张三';
select * from student where name = '张三' and phone_num = '15100046637';
/* 三条sql只有 2 、 3、4能使用的到索引idx_phone_name,因为条件里面必须包含索引前面的字段 才能够进行匹配。 而3和4相比where条件的顺序不一样,为什么4可以用到索引呢?是因为mysql本身就有一层sql优化,他会根据sql来识别出来该用哪个索引,我们可以理解为3和4在mysql眼中是等价的。 */
全文索引
全文索引主要用来查找文本中的关键字,而不是直接与索引中的值相比较,它更像是一个搜索引擎,基于相似度的查询,而不是简单的where语句的参数匹配。 用 like + % 就可以实现模糊匹配了,为什么还要全文索引?like + % 在文本比较少时是合适的,但是对于大量的文本数据检索,是不可想象的。全文索引在大量的数据面前,能比 like + % 快 N 倍,速度不是一个数量级,但是全文索引可能存在精度问题。
空间索引
MySQL在5.7之后的版本支持了空间索引,而且支持OpenGIS几何数据模型 空间索引是对空间数据类型的字段建立的索引,MYSQL中的空间数据类型有4种,分别是GEOMETRY、POINT、LINESTRING、POLYGON。 MYSQL使用SPATIAL关键字进行扩展,使得能够用于创建正规索引类型的语法创建空间索引。 创建空间索引的列,必须将其声明为NOT NULL。 空间索引一般是用的比较少,了解即可。
MYSQL的优化
从设计上优化 从查询上优化 从索引上优化 从存储上优化
查看SQL执行频率:
--下面的命令显示了当前 session 中所有统计参数的值
show session status like 'Com_______'; -- 查看当前会话统计结果
show global status like 'Com_______'; -- 查看自数据库上次启动至今统计结果
show status like 'Innodb_rows_%’; -- 查看针对Innodb引擎的统计结果
--Com_select 总共执行select的次数
show profile查询分析sql
-- 通过 have_profiling 参数,能够看到当前MySQL是否支持profile:
select @@have_profiling;
set profiling=1; -- 开启profiling 开关;
show databases;
show tables;
select * from user;
select count(*) from user;
show profiles; -- 执行完上述命令之后,再执行show profiles 指令, 来查看SQL语句执行的耗时
--通过show profile for query query_id 语句可以查看到该SQL执行过程中每个线程的状态和消耗的时间
show profile for query 查询id;
-- 在获取到最消耗时间的线程状态后,MySQL支持进一步选择all、cpu、block io 、context switch、page faults等明细类型类查看MySQL在使用什么资源上耗费了过高的时间。例如,选择查看CPU的耗费时间
show profile cpu for query 133;
索引优化
数据准备:
create table `tb_seller` (
`sellerid` varchar (100),
`name` varchar (100),
`nickname` varchar (50),
`password` varchar (60),
`status` varchar (1),
`address` varchar (100),
`createtime` datetime,
primary key(`sellerid`)
);
-- 创建组合索引
create index idx_seller_name_sta_addr on tb_seller(name,status,address);
-- sql的优化
create table `tb_user` (
`id` int(11) not null auto_increment,
`username` varchar(45) not null,
`password` varchar(96) not null,
`name` varchar(45) not null,
`birthday` datetime default null,
`sex` char(1) default null,
`email` varchar(45) default null,
`phone` varchar(45) default null,
`qq` varchar(32) default null,
`status` varchar(32) not null comment '用户状态',
`create_time` datetime not null,
`update_time` datetime default null,
primary key (`id`),
unique key `unique_user_username` (`username`)
);
1) 主键顺序插入 因为InnoDB类型的表是按照主键的顺序保存的,所以将导入的数据按照主键的顺序排列,可以有效的提高导入数据的效率。如果InnoDB表没有主键,那么系统会自动默认创建一个内部列作为主键,所以如果可以给表创建一个主键,将可以利用这点,来提高导入数据的效率。 例如: 对tb_user插入数据时,可以按照id的顺序进行数据的插入 2)insert语句优化 -- 如果需要同时对一张表插入很多行数据时,应该尽量使用多个值表的insert语句,这种方式将大大的缩减客户端与数据库之间的连接、关闭等消耗。使得效率比分开执行的单个insert语句快。 -- 原始方式为:
insert into tb_test values(1,'Tom');
insert into tb_test values(2,'Cat');
insert into tb_test values(3,'Jerry');
-- 优化后的方案为 : insert into tb_test values(1,'Tom'),(2,'Cat'),(3,'Jerry'); 3)优化子查询 -- 优化前
select * from user where uid in (select uid from user_role );
-- 优化后的方案
select * from user u , user_role ur where u.uid = ur.uid;
标签:name,--,数据库,表名,查询,学习,索引,MYSQL,select
From: https://blog.csdn.net/qq_51050225/article/details/144895872