Mysql数据库
1.安装配置Mysql
1.Windows操作Mysql服务器
安装成功Mysql之后,会在"控制面板->管理工具->服务"中出现Mysql服务,选中Mysql服务右键选择启动,停止,重启选项。
2.Linux操作Mysql服务器
0.在线安装
sudo apt install mysql-sever-5.7
(Ubuntu 16.10和17.04这两个版本对于5.7支持比较好)
在安装过程中有一个需要输入“root(此root非彼root)”用户密码过程,需要输入两次。
1.启动
1、使用 service 启动:service mysql start
2、使用 mysqld 脚本启动:/etc/inint.d/mysql start
3、使用 safe_mysqld 启动:safe_mysql&
2.停止
1、使用 service 启动:service mysql stop
2、使用 mysqld 脚本启动:/etc/inint.d/mysql stop
3、mysqladmin shutdown
3.重启
1、使用 service 启动:service mysql restart
2、使用 mysqld 脚本启动:/etc/inint.d/mysql restart
4.配置客户端登录
在家目录下 vi .my.cnf
[client]
host=‘127.0.0.1’
port=3306
user=‘root’
password=‘briup’
default-character-set=UTF8
3.Mac操作Mysql服务器
1.启动MySQL服务
sudo /usr/local/MySQL/support-files/mysql.server start
2.停止MySQL服务
sudo /usr/local/mysql/support-files/mysql.server stop
3.重启MySQL服务
sudo /usr/local/mysql/support-files/mysql.server restart
也可以改进一下,让Mac系统管理Mysql服务。
编辑vi .bash_profile文件
新增
export MYSQL_HOME=/usr/local/mysql
export PATH= P A T H : PATH: PATH:CLASSPATH
export PATH= P A T H : PATH: PATH:MYSQL_HOME/bin
alias mysqlstart=‘sudo /usr/local/mysql/support-files/mysql.server start’
alias mysqlstop=‘sudo /usr/local/mysql/support-files/mysql.server stop’
source .bash_profile
后期通过系统偏好设置启动关闭Mysql服务。
2.Mysql基本概念
数据库 DB DataBase ---->存储持久数据 … 将数据按照一定的规则组织到一起,持久存储在计算机中。
数据库系统 DBS 在计算机系统中安装数据库
数据库管理系统 DBMS 数据库管理系统是用来管理数据库的。
数据发展据管理技术的阶段
1.人工管理阶段
2.文件系统阶段
3.数据库系统阶段
数据库技术发展阶段
1.层次数据库和网格数据库技术阶段
2.关系数据库技术阶段 Mysql Oracle SqlServer DB2 Access
3.后关系数据库技术阶段 非关系型数据库 Nosql Hbase(列式数据库) redis Mongdb
对于操作数据库的程序人员来说,发送一条SQL命令到获取到相应结果,中间需要经过的步骤:
数据库接收到SQL之后:
SQL命令分为两类:
1.固定命令 show databases;
2.查询命令 DML DDL
1.用户发送SQL语句
2.数据库管理系统接收
3.对SQL语句进行解析 绑定 优化 执行(查询-增删改查 DML DDL)
4.返回执行结果
数据库管理系统提高的功能
1.数据定义语言(Data Definition Language) DDL
创建/删除/修改 table database view trigger index
2.数据操作语言(Data Manipulation Language)DML
增删改查
insert
delete
update
select
3.数据控制语言(Data Control Language)DCL
对事务进行管理
提交事务
回滚事务
grant 赋予权限
revoke 撤销权限
SQL结构化查询语言Structed Query Language
关系型数据库中的SQL语言基本一致。但数据类型以及函数以及一些关键字可能不相同。
3.数据库操作
1.数据库基本操作
标识符
1.字母,数字,下划线,@,#, 符 合 组 成 2. 首 字 母 不 能 是 数 字 和 符合组成 2.首字母不能是数字和 符合组成2.首字母不能是数字和
3.不允许是Mysql的关键字以及保留字
4.不允许出现空格和特殊字符
5.长度小于128位
查看数据库
show databases;
创建数据库
create database databaseName [character set utf8];
选择数据库
use databaseName;
删除数据库
delete database databaseName;
修改数据库的编码格式
alter database <数据库名> character set utf8;
查看Mysql数据库文件存储在哪个目录
show global variables like “%datadir%”
2.存储引擎
为了提高Mysql数据库管理系统的使用效率和灵活性,可以根据实际需求选择存储引擎。
存储引擎指定了表的类型(即如何存储和索引数据,是否支持事物等)。
1.查看Mysql支持的存储引擎
show engines;
show engines\g
show engines\G
show variables like 'have%';
2.操作默认存储引擎InnoDB
1.查询默认存储引擎
show variables like 'default_storage_engine%';
2.修改默认存储引擎
1.安装版的时候在安装的时候选择存储引擎
2.解压版直接修改my.ini配置文件,修改default-storage-engine的值。
3.Mysql常用的引擎
1. InnoDB
InnoDB的存储文件有两个,后缀名分别是.frm和.idb,其中.frm是表的定义文件,而idb是数据文件。
InnoDB中存在表锁和行锁,不过行锁是在命中索引的情况下才会起作用。
InnoDB支持事务,且支持四种隔离级别(读未提交、读已提交、可重复读、串行化),默认的为可重复读;而在Oracle数据库中,只支持串行化级别和读已提交这两种级别,其中默认的为读已提交级别。
InnoDB中的B+Tree
InnoDB是以ID为索引的数据存储。采用InnoDB引擎的数据存储文件有两个,一个定义文件,一个是数据文件。
InnoDB通过B+Tree结构对ID建索引,然后在叶子节点中存储记录。
若建索引的字段不是主键ID,则对该字段建索引,然后在叶子节点中存储的是该记录的主键,然后通过主键索引找到对应的记录。
2. Myisam
Myisam 的存储文件有三个,后缀名分别是.frm、.MYD、MYI,其中.frm是表的定义文件,.MYD是数据文件,.MYI是索引文件。Myisam只支持表锁,且不支持事务。Myisam由于有单独的索引文件,在读取数据方面的性能很高 。
Myisam中的 B+Tree:
Myisam引擎也是采用的B+Tree结构来作为索引结构。由于Myisam中的索引和数据分别存放在不同的文件,所以在索引树中的叶子节点中存的数据是该索引对应的数据记录的地址,由于数据与索引不在一起,所以Myisam是非聚簇索引。
InnoDB和Myisam都是用B+Tree来存储数据的,目前常用的Mysql引擎是InnoDB,原因在于它支持行级锁、支持事务。
3.数据类型
查看系统帮助文档
help contents;
查看数据类型
help data types;
查看具体某一个类型
help int;
1.整数类型
标准SQL中的所有整数类型(smallint和int)外,tinyint 和mediumint和bigint。
整数类型 字节 范围
tinyint 1 -128~127或0~255
smallint 2 -2^15~2^15-1或0~2^16-1
mediumint 3 -2^23~2^23-1或0~2^24-1
int和integer 4 -2^31~2^31-1或0~2^32-1
bigint 8 -2^63~2^63-1或0~2^64-1
2.浮点数类型
标准SQL中的所有浮点类型(float(4)和double(8)),定点数类型(dec,decimal)外,还支持位类型(bit)。
dec(m,d)和decimal(m,d)字节为m+2,范围与double类型一致。
bit(m),字节为1-8,范围bit(1)~bit(64)。
练习1:
create table s_test(a float(38,30),b decimal(38,30));
insert into f_test values(123450.000000000000000000000001,123450.000000000000000000000001);
select * from f_test \G
float和double数据类型存储数据室存储的是近似值,而decimal存储的是字符串,因此精确度更高,在需要表示金额等货币类型时优先选择decimal数据类型。
练习2:
create table s_bit(id bit(8));
insert into s_bit values(11),(b'0011');
select id+0 from bit_test ;
select bin(id+0) from bit_test ;
存储的第一个数字为十进制的数字“11”,
存储的第二个数字为二进制的数字“11”。
3.日期时间类型
类型 字节 范围
date 4 1000-01-01~9999-12-31
datetime 8 1000-01-01 00:00:00~9999-12-31 23:59:59
timestamp 4 19700101080001~2038 年的某个时刻
time 3 -835:59:59~835:59:59
year 1 1901~2155
每个日期和时间数据类型都有一个取值范围,如果插入的值超过了该类型的取值范围,则会插入默认值。
4.字符串类型
char(m)
varchar(m)
tinytext
text
mediumtext
longtext
binary(m)
varbinary(m)
tinyblob
blob
mediumblob
longblob
4.表操作
1.数据库设计:
系统设计中一个重要的环节就是数据库设计.
数据库设计的时候需要先进行数据建模(实体关系图 E-R图)
数据建模的依据就是前期所做的需求分析
实体-关系图(Entity Relationship Diagram),也称为E-R图,提供了表示实体、属性和关系的方法,用来描述现实世界的概念模型。
构成E-R图的基本要素是实体、属性和关系
实体(Entity):实体用来表示具有相同特征和性质的事物(类似于java的类),实体由实体名和实体属性来表示。
属性(Attribute):实体所具有的某一特性,一个实体可以有若干个属性
关系(Relationship):实体彼此之间相互连接的方式称为关系。一般可分为以下 3 种类型:
一对一关系 (1 ∶ 1)
一对多关系 (1 ∶ N)
多对多关系 (M ∶ N)
may-be 和 must-be
在实体与实体之间的关系中,都会存在着may-be和must-be这俩种情况,例如:
系统中有顾客和订单俩个实体(1:N关系),一个顾客对应多个订单,一个订单对应一个顾客,而且一个顾客可以(may be)没有订单和他对应,一个订单一定(must be)会有顾客和它对应.
ER图中符号的表示
1) # : 唯一, 以后可能表示为主键
2) * : 非空
3) o : 可有可无
4) 虚线: may be 顾客这边虚线,顾客可能没有订单
5) 实线: must be 订单这边实线,订单一定是属于某个客户。
6) 竖杠(|): 代表要强制在(|)一方建立一个联合主键,将对方ID拿过来做联合主键
7) 伞状图标代表多的一方,不是伞状图标则代表一的一方
数据库设计
数据建模完成之后,可以把ER图转换成数据中的表
1.实体的名字转换为表的名字
2.实体的属性转换为表中的列
3.具有唯一特点的属性设置为表中的主键
4.根据实体之间的关系设置为表中某列为外键列(主外键关联)
注意:第四步主要是:实体关系--->表关系
2.数据库范式:
设计关系数据库时,遵从不同的规范要求,才能设计出合理的关系型数据库,这些不同的规范要求被称为不同的范式,各种范式呈递次规范,越高的范式数据库冗余越小。
目前关系数据库有六种范式:
第一范式(1NF)
第二范式(2NF)
第三范式(3NF)
巴斯-科德范式(BCNF)
第四范式(4NF)
第五范式(5NF,又称完美范式)
注:满足最低要求的范式是第一范式(1NF)。在第一范式的基础上进一步满足更多规范要求的称为第二范式(2NF),其余范式以次类推。一般说来,数据库只需满足第三范式(3NF)就行了
第一范式:
一个表中,每个列里面的值是不能再分割的.
例如:我们设计的表中有一个列是:爱好
这个列的值可能会是这样:足球篮球乒乓球
但是这值是可以再分割的:足球、篮球、乒乓球
所以这种设计是不满足第一范式
课程管理表 40门课
课程选择表 8门课
用户表-->学生
bm_coursechoice_user
user
id name
1 zhangsan
user_likes
id userId likedId
1 1 1
2 1 2
likes
id name
1 足球
2 篮球
3 羽毛球
。。。。
第二范式:
第二范式是在满足第一范式的基础上
表中的非主键列都必须依赖于主键列
例如:
订单表: 订单编号 是主键
订单编号 订单名称 订单日期 订单中产品的生产地
这几个非主键列中,产品生产地是不依赖于订单编号的,所以这种设计是不满足第二范式
第三范式:
第三范式是在满足第二范式的基础上
表中的非主键列都必须直接依赖于主键列,而不能间接的依赖.
(不能产生依赖传递)
例如:
订单表: 订单编号 是主键
订单编号 订单名称 顾客编号 顾客姓名
顾客编号依赖于订单编号,顾客姓名依赖于顾客编号,从而顾客姓名间接的依赖于订单编号,那么这里产生了依赖传递,所以这个设计是不满足第三范式的
了解主键和外键
主键:
1.能做主键的列必要满足非空唯一的特点
2.只要满足非空唯一的任何列都可以做主键
3.可以让表中一个有意义的列做主键,比如说学号,它既表示学生学号又作为表中的主键,因为这个列满足非空唯一的条件
4.也可以找一个没有意义的列做主键,就是用来唯一标识一行记录的
5.我们可以让多个列联合在一起做表中的主键,那么它就是联合主键,要求这几个列的值联合在一起是非空唯一的
外键:
1.表中的某一个列声明为外键列,一般这个外键列的值都会引用于另外一张表的主键列的值(有唯一约束的列就可以,不一定非要引用主键列)
2.另外一张表的主键列中出现过的值都可以在外键列中使用,没有出现过的值,都不能使用
3.外键列值也可以为空的,提前是这个外键列在表中不做主键,因为我们也可以把表中的外键列当做主键来使用(只有满足非空唯一的要求就可以)
4.如果把B表中的联合主键的值引用到A表中做外键,因为是俩个列在B表中做联合主键,那么A表引用过来的时候也要把俩个列的值都引用过来,那么它们在A表中就会作为一个联合外键出现
3.具体操作:
1.创建表
create table if not exists table_name(
列名 数据类型 [列级约束],
列名 数据类型 [约束],
.
.
.
列名 数据类型 [约束],
constraint 约束名1 表级约束1,
constraint 约束名2 表级约束2
);
特殊的建表:建立一张表和s_user一模一样的表
create table 表名 as select语句;
例如1:s_user的表结构和表中的数据全部复制过来
create table s_test1
as
select * from s_user;
例如2:只拿来s_user的表结构,没有数据
create table s_test2
as
select * from s_user
where 1=2;
例如3:只复制表中某几个列以及数据
create table s_test3
as
select userId,userName,password from s_user;
2.查看表结构
describe tableName;
desc tableName;
show create table tableName;
3.删除表
drop table tableName;
drop table if exists tableName;
4.修改表
alter table 表名 add|drop|modify|change 属性名|索引名|约束名
修改表名:alter table old_table_name rename [to] new_table_name;
增加字段:alter table table_name add 属性名 属性类型 [first];
alter table table_name add 属性名 属性类型 after 属性名;
删除字段:
alter table table_name drop 属性名;
修改字段:
alter table table_name modify 属性名 数据类型;
alter table table_name change 旧属性名 新属性名 旧数据类型;
alter table table_name change 旧属性名 新属性名 新数据类型;
alter table table_name modify 属性名1 数据类型 [first|after 属性名];
修改表编码格式:
alter table <表名> character set utf8;
5.表的约束:
完整性约束
not null 非空约束
default 默认值
unique [(UK)] 唯一约束
primary key[(PK)] 主键约束
foreign key[(FK)] 外键约束
auto_increment 自动增长
Mysql不支持check约束,不生效。
1.根据约束数据列限制,约束分为:
单列约束(列级约束),即每个约束只约束一列数据;
多列约束(表级约束),即每个约束可以约束多列数据;
2.根据约束的位置,约束分为:
列级约束(因为是跟在列的声明后面写的)
表级约束(因为是在全部列声明完之后写的)
列级约束和表级约束都是对列中的值进行约束的,例如:列的值不能为空,列的值必须是唯一的等等。
constraint关键字
1.constraint是约束的意思.
2.建表的时候可以给约束起一个名字,这个名字起的规律一般会是:表名_列名_约束类型.
3.如果没有给约束起名字,那么系统也会给这个约束起一个默认的名字,这不过这个默认的名字对我们来说并不友好(我们看不懂).
4.将来我们可以根据我们之前给约束起好的名字而找到这个约束,然后进行修改.
可以在创建表的时候添加约束,也可以在创建表之后,修改表,给表添加/删除约束。
添加主键约束:
alter table 表名 add primary key(主键列名);
删除主键约束:
alter table 表名 drop primary key;
添加唯一约束:
alter table 表名 add constraint 索引名 unqiue(唯一列名);
删除唯一约束:
alter table 表名 drop index 索引名;
drop index 索引名 on 表名;
添加外键约束:
alter table 表名 add constraint 外键索引名 foreign key(外键列名) references 外键表(外键表中的列名);
删除外键约束:
alter table 表名 drop foreign key 外键索引名;
drop index 外键索引名 on 表名;
#外键中的级联关系有以下几种情况:
#ON DELETE CASCADE 删除主表中的数据时,从表中的数据随之删除
#ON UPDATE CASCADE 更新主表中的数据时,从表中的数据随之更新
#ON DELETE SET NULL 删除主表中的数据时,从表中的数据置为空
#默认 删除主表中的数据前需先删除从表中的数据,否则主表数据不会被删除
注:
1.列级约束也称为行级约束.
2.NOT NULL约束只能在列级别定义,作用在多个列上的约束只能定义在表级别,例如复合主键约束.
3.列级别上不能定义外键约束,并且不能给约束起名字,由MySQL自动命名(NOT NULL除外.
4.表级别上定义的约束可以给约束起名字.
6.练习
练习1:构建一张用户表:用户名Id 用户名 密码 手机号码 邮箱 个人简介(备注)
create table s_user(
userId int primary key auto_increment,
userName varchar(10) unique not null,
password varchar(10) not null,
phone char(11) unique not null,
email varchar(30) not null,
gender char(1) default '男',
demo varchar(250) default '这个人很懒,没有填写个性签名。'
);
insert into s_user(userName,password,phone,email) values('briup1','briup123','18230981230','[email protected]');
练习2:构建一张订单表
create table book_user(
userId int primary key auto_increment,
userName varchar(10) ,
password varchar(20) not null,
demo varchar(50) default '很懒,没有填写签名。',
constraint userName_unique unique(userName)
);
create table book_order1(
orderId int primary key auto_increment,
price double not null,
orderTime datetime not null,
userId int references user(userId)
);
create table book_order3(
orderId int primary key auto_increment,
price double not null,
orderTime datetime not null,
userId int,
constraint userId_fk foreign key(userId) references book_user(userId)
);
5.数据操作
1.插入数据
insert into tbale_name(field1,field2...,fieldn) values(value1,value2...,valuen),(value1,value2...,valuen)...,(value1,value2...,valuen);
insert into tbale_name(field1,field2...,fieldn) select field1,field2...,fieldn from table_name2 where ...;
2.更新数据
update table_name set field1=value1,field2=value2,...,fieldn=valuen [where condition];
3.删除数据
delete from table_name [where condition];
truncate table table_name;
4.查询数据
4.1单表查询
select [distinct] field1,field2...,fieldn|*
from table_name
where 限制行条件
group by 分组列名,一般跟主键
having 限制分组之后的条件
order by 排序列 [asc|desc];
注:除了select和from之外其他的都不是必须的。
假如select..from..后面的语句都出现了,那么他们的执行顺序为:
where-->group by分组-->执行组函数-->having筛选->order by/select
1.关系运算符: + - * / %
2.条件语句
关系运算符和逻辑运算符 && || & | and or
between .. and ..
is [not] null
[not] in (value1,value2...,valuen)
[not] like '%*_*%'
3.排序
order by 列1 asc,列2 desc;
4.限制数据行数
limit [offser_start,]row_count;
select * from s_dept where dept_id is null limit 2;
select * from s_dept where dept_id is null limit 0,5;
分页展示数据
两个参数
p页码
r每页显示的行数
select * from 表 limit (p-1)*r,r
每页展示5条
第一页 limit 0,5
第二页 limit 5,5
第三页 limit 10,5
第N页 limit (p-1)*r,r
例如:
select * from bm_course limit 起始行,每页行数;
select * from bm_course where rowNum>=起始行 limit 每页行数;
select @rowNum:=@rowNum+1 rowId,a.*
from bm_course a,(select @rowNum:=0) b)
where rowId >= 起始页 limit 每页行数;
测试limit分页优化:
create table pageTest as select * from bm_course;
insert into pageTest select * from pageTest; 执行N次插入数据
create table pageRowId as select @rowNum:=@rowNum+1 rowId,p.* from pageTest p , (select @rowNum:=0) r;
alter table pageRowId add index rowIdIndex(rowId);
select count(*) from pageRowId;
+----------+
| count(*) |
+----------+
| 851968 |
+----------+
select * from pageRowId limit 10, 100;
select * from pageRowId where rowId >= (≠select rowId from pageRowId limit 10,1) limit 100;
select * from pageRowId where rowId >= 10 limit 100;
select * from pageRowId limit 1000, 100;
select * from pageRowId where rowId >= (select rowId from pageRowId limit 1000,1) limit 100;
select * from pageRowId where rowId >= 1000 limit 100;
select * from pageRowId limit 100000, 100;
select * from pageRowId where rowId >= (select rowId from pageRowId limit 100000,1) limit 100;
select * from pageRowId where rowId >= 100000 limit 100;
select * from pageRowId limit 800000, 100;
select * from pageRowId where rowId >= (select rowId from pageRowId limit 800000,1) limit 100;
select * from pageRowId where rowId >= 800000 limit 100;
select * from pageRowId where rowId between 800000 and 800100;
5.统计函数和分组函数
分组函数:
avg sum max min count
语法格式:
select 组函数(field|*)
from table_name
where condition
group by field1,field2,field3
[having condition];
需要注意:
1.组函数出现的位置:
1.select后面
2.having后面
3.order by后面
4.where后面一定【不能】出现组函数
注意:如果select/having语句后面出现了组函数,那么select/having后面没有被组函数修饰的列,就必须出现在group by 后面
2.where和having对比:
1.where和having都是做条件筛选的
2.where执行的时间比having要早
3.where后面不能出现组函数
4.having后面可以出现组函数
5.where语句要紧跟from后面
6.having语句要紧跟group by后面
3.group by和having的关系:
1.group by可以单独存在,后面可以不出现having语句
2.having不能单独存在,有需要的话,必须出现在group by后面
4.order by语句
1.如果sql语句中需要排序,那么就一定要写在sql语句的最后面
2.order by后也可以出现组函数
4.2多表查询
多表查询,又称表联合查询,即一条sql语句涉及到的表有多张,数据通过特定的连接进行联合显示.
1.关系数据的各种操作
笛卡尔积 cartesian product
在数学中,两个集合X和Y的笛卡尓积(Cartesian product),又称直积,表示为X × Y.
假设集合A={a, b},集合B={0, 1, 2},则两个集合的笛卡尔积为{(a, 0), (a, 1), (a, 2), (b, 0), (b, 1), (b, 2)}。
在数据库中,如果直接查询俩张表,那么其查询结果就会产生笛卡尔积
select *from s_emp,s_dept;
1.1连接查询 join
1.内连接inner join:只保留表关系中所有匹配的数据记录,舍弃不匹配的数据记录。
1.自然连接 natural join:根据表关系中相同名称的字段自动进行记录匹配,然后去掉重复的字段。
2.等值连接:表关系的笛卡尔积中,选择所匹配字段值相等(=)的数据记录。
例如:查询开设课程的课程名称。
开设课程表 bm_course_choice id course_id
课程管理表 bm_course courseNum sportsEvent
select course_id,sportsEvent
from bm_course_choice bcc,bm_course bc
where bcc.course_id=bc.couserNum;
3.不等值连接:选择所匹配字段值不想等(!=)的数据记录。
例如:假设数据库中还有一张工资等级表:salgrade s
where
工资等级表salgrade:
gradeName 列表示等级名称
losal 列表示这个级别的最低工资数
hisal 列表示这个级别的最高工资数
表中的数据类似于下面内容:
id salgrade losal hisal;
1 初级程序员 2000 4000
2 中级程序员 4000 6000
s_emp
张三 2500
李四 4800
select name,salary,salgrade
from s_emp e, salgrade s
where e.salary >= s.losal and e.salary < s.hisal;
select name,salary,salgrade
from s_emp e, salgrade s
where e.salary between s.losal and s.hisal;
查询出员工的名字、职位、工资、工资等级名称
select e.name, e.title, e.salray, s.gradeName
from s_emp e, salgrade s
where e.salray BETWEEN s.losal AND s.hisal
2.外连接outer join:不仅保留表关系中所有匹配的数据记录,而且还会保留部分不匹配的数据记录。
注意:outer可以省去不写
1.左外连接:保留表关系中所有匹配的数据记录,包含关联左边表中不匹配的数据记录。
...
from 表1 left [outer] join 表2 on 条件
...
例如:查询所有员工 以及对应的部门的名字,没有部门的员工也要显示出来
select name,dept_id,name
from s_emp left outer join s_dept
on s_emp.dept_id=s_dept.id;
2.右外连接:保留表关系中所有匹配的数据记录,包含关联右边表中不匹配的数据记录。
...
from 表1 right [outer] join 表2 on 条件
...
例如:查询所有员工 以及对应的部门的名字,没有任何员工的部门也要显示出来
select name,dept_id,name
from s_emp right outer join s_dept
on s_emp.dept_id=s_dept.id ;
3.全连接:保留表关系中所有匹配的数据记录,包含关联左右两边表中不匹配的数据记录。
...
from 表1 full [outer] join 表2 on 条件
...
例如:查询所有员工 以及对应的部门的名字,没有任何员工的部门也要显示出来,没有部门的员工也要显示出来
select name,dept_id,name
from s_emp full outer join s_dept
on s_emp.dept_id=s_dept.id;
3.交叉连接 cross join:表关系笛卡尔积后数据记录,不需要任何匹配条件,有时候该操作的结果没有任何实际意义。
4.自连接:一张表,自己和自己连接
例如:查询每个员工的名字以及员工对应的经理的名字
id name salary dept_id mananger_id
3 larry ***** 1 null
11 张三 10000 10 3
select s1.name,s2.name manager_name
from s_emp s1,s_emp s2
where s1.manager_id = s2.id;
1.2对查询结果集的操作
如果有俩条sql语句,每一条sql都可以查询出一个结果,这个被称之为结果集。那么我们可以使用下面的关键字对俩个结果集进行操作
union 获得俩个结果集的并集 有去重
select sportsEvent,week
from bm_course
where week='周一' or week='周二'
union
select sportsEvent,week
from bm_course
where week='周二' or week='周三';
union all 把俩个结果集 合在一起显示出来 没有去重
select sportsEvent,week
from bm_course
where week='周一' or week='周二'
union all
select sportsEvent,week
from bm_course
where week='周二' or week='周三';
minus 差集 第一个结果集除去第二个结果集和它相同的部分
Mysql不支持minus
select c1.* from (select courseNum,sportsEvent,week
from bm_course
where week='周一' or week='周二') c1 left join
(select courseNum,sportsEvent,week
from bm_course
where week='周二' or week='周三') c2 on c1.courseNum=c2.courseNum where c2.week is null;
intersect 获得俩个结果集的交集
Mysql不支持intersect
select c1.* from (select courseNum,sportsEvent,week
from bm_course
where week='周一' or week='周二') c1 join
(select courseNum,sportsEvent,week
from bm_course
where week='周二' or week='周三') c2 on c1.courseNum=c2.courseNum;
注意:
1.前提条件 俩个结果集中【查询的列】要完全一致
2.union和union all关键字都是将两个结果集合并为一个,但这两者从使用和效率上来说都有所不同。
2.1、对重复结果的处理:union在进行表链接后会筛选掉重复的记录,union all不会去除重复记录。
2.2union all只是简单的将两个结果合并后就返回。
2.3从效率上说,union all要比union快很多,所以,如果可以确认合并的两个结果集中不包含重复数据且不需要排序时的话,那么就使用union all。
2.子查询:指在一个查询之中嵌套了其他的若干查询,即在一个select查询语句的where或from子句中包含另一个select查询语句。在查询语句中,外层select查询语句称为主查询,where子句中的select查询语句被称为子查询,也被称为嵌套查询。
select
from 表|(select子句)
where 列 >=|in (select子句)
5.练习:
1.请查询课程管理表中的数据。
bm_course 16条数据
courseNum 课程编号
sportsEvent 课程名称
location 课程地点
week 课程时间
fee 价格
2.请查询本学期开设课程表中的数据。
bm_course_choice
desc bm_course_choice;
select count(*) from bm_course_choice;
6条数据 id course_id
3.请查询公告表中的数据。
4.请查询用户表中的数据。
bm_registration
stuName 学生名字
select * from bm_registration \G;
5.请查询周一开设的课程名,课程地点以及价格。
sportsEvent location week fee
--------
select *
from bm_course
where week='周一';
--------
select sportsEvent,location,fee,week from bm_course bc , bm_course_choice bcc where bcc.course_id=bc.courseNum and week='周一';
6.请查询所有乒乓球课程的课程地点,开课日期,并按照价格降序排列。
sportsEvent location week fee
思考过程:
1.列:课程地点,开课日期 ,课程名字, 价格;
2.条件:乒乓球课程;
3.其他:按照价格降序排列;
select location,week,sportsEvent,fee
from bm_course
where sportsEvent like '%乒乓球%'
order by fee desc;
7.按照课程编号升序排列,分页展示课程管理表中的数据,每页展示5条数据。
select * from bm_course order by id asc limit (页数-1)*每页展示的条数,每页展示的条数\G
select * from bm_course where id >= (select id from bm_course limit (页数-1)*每页展示的条数,1) limit 每页展示的条数\G
select * from bm_course where id between (页数-1)*每页展示的条数+1 and 页数*每页展示的条数;
select * from bm_course order by id asc limit 10,5\G
select * from bm_course where id >=(select id from bm_course limit 10,1) limit 5\G
select * from bm_course where id between 11 and 15;
8.请查询本学期开设课程表中的课程名称,课程编号,价格。
bm_course_choice id course_id schoolterm_id year_id
select course_id,sportsEvent,fee from bm_course_choice ,bm_course c where course_id=c.id;
9.请模拟用户选择课程,向用户选择课程表中保存3条数据。
insert into bm_coursechoice_user(id,insertTime,coursechoice_id,user_id,amount) values(1,now(),1,1,100);
insert into bm_coursechoice_user(id,insertTime,coursechoice_id,user_id,amount) values(2,now(),4,1,770);
insert into bm_coursechoice_user(id,insertTime,coursechoice_id,user_id,amount) values(3,now(),1,2,100);
10.请查询各门课程已经报名的用户人数。
报名表 bm_coursechoice_user
coursechoice_id=bcc.id and bcc.course_id=bc.courseNum
开设课程信息 bm_course_choice
course_id
课程信息 bm_course
sportsEvent courseNum
组函数:count(*)
分组: 课程编号
select bc.id,bc.sportsEvent,count(*) sum
from bm_coursechoice_user bcu,bm_course_choice bcc,bm_course bc
where bcu.coursechoice_id=bcc.id and bcc.course_id=bc.id
group by bc.id,bc.sportsEvent;
select coursechoice_id,count(*) from bm_coursechoice_user group by coursechoice_id;
11.请查询各门课程已经报名的用户人数,以及对应的课程名称。
select sportsEvent,num from bm_course c,bm_course_choice cc,(select coursechoice_id,count(*) num from bm_coursechoice_user group by coursechoice_id) tmp where c.id=cc.course_id and cc.course_id=coursechoice_id;
12.请查询"李祺烁"已经报名成功的课程信息(课程名称,课程地址,课程日期,课程价格)。
1.获取"李祺烁"的用户编号
select id from bm_registration where stuName='李祺烁';
2.根据用户编号在用户报名课程表中查询该用户报名的开设课程编号
select coursechoice_id from bm_coursechoice_user where user_id=(第一步的结果);
select coursechoice_id from bm_coursechoice_user where user_id=(select id from bm_registration where stuName='李祺烁');
3.根据报名的开设课程编号在开设课表中查询对应课程编号
select course_id
from bm_course_choice
where id in (第二步结果);
4.根据报名的课程编号在课程管理表中查询对应课程的具体信息
select sportsEvent,location,week,fee from bm_course where id in (第三步结果);
列:sportsEvent,location,week,fee
表:bm_course bc,bm_registration br,bm_coursechoice_user bcu,bm_course_choice bcc
多表及联条件:br.id=bcu.user_id
and bcu.coursechoice_id=bcc.id
and bcc.course_id=bc.id
查询条件:stuName='李祺烁'
select sportsEvent,location,week,fee
from bm_course bc,bm_registration br,bm_coursechoice_user bcu,bm_course_choice bcc where br.id=bcu.user_id
and bcu.coursechoice_id=bcc.id
and bcc.course_id=bc.id and stuName='李祺烁';
13.请查询课程管理表中最大的课程价格,并且显示出这个最大的课程价格的课程名字.
1.使用连接查询
1.查询课程管理表中最大的课程价格
select max(fee+0)
from bm_course;
2.加上课程名字
select max(fee+0),sportsEvent
from bm_course;
3.select后面出现组函数,没有被组函数修饰的列放到group by后面,但是发现查询结果并不是想要结果
select max(fee+0),sportsEvent
from bm_course
group by sportsEvent;
4.修改为多表查询(起别名),从bc表中查询出最大的课程价格是多少,然后再和bc2表连接起来,选出bc2表中这个最大课程价格的员工名字
select max(bc.fee+0),bc2.sportsEvent
from bm_course bc,bm_course bc2
where max(bc.fee+0)=bc2.fee
group by bc2.sportsEvent;
5.where后面不能出现组函数,所以改为having
select max(bc2.fee+0),bc.sportsEvent
from bm_course bc,bm_course bc2
group by bc2.sportsEvent,bc.fee
having bc2.fee=max(bc.fee+0);
2.使用子查询
1.查询课程管理表中最大的课程价格
select max(fee+0)
from bm_course;
2.查询最大的课程价格对应的课程编号以及对应的课程名字
select courseNum,sportsEvent,fee
from bm_course
where fee = (select max(fee+0)
from bm_course);
14.请查询选择兵乓球课程的用户信息。
7.索引操作
1.索引是一种排好序的数据结构。
2.索引的作用是帮助数据库提高数据检索效率,但是会降低插入删除更新表的速度以及索引过多则会占据许多磁盘空间。
3.Mysql支持4类索引:单列索引(普通索引,唯一索引,主键索引),多列索引,全文索引(只适合只在MyISAM引擎上才能使用,只能在CHAR,VARCHAR,TEXT类型字段上使用全文索引),空间索引( 空间索引是对空间数据类型的字段建立的索引,只在MyISAM引擎上才能使用,MySQL中的空间数据类型有四种,GEOMETRY、POINT、LINESTRING、POLYGON。)
4.索引的遵循原则:
1、最左侧原则,表的最左侧的一列,往往数据不会发生改变,不影响其他列的数据;
2、命名短小原则,索引命名过长会使索引文件变大,损耗内存。
5.适合创建索引的场景:
1.对经常用于查询的字段应该创建索引,即在where子句种出现的字段。
2.在一个字段上不同值较多可以建立索引。
3.在分组的字段,即在group by子句种出现的字段。
4.存在依赖关系得到子表和父表之间的联合查询,即主键或外键字段。
5.设置唯一完整性约束的字段。
6.不适合创建索引的场景:
1.对查询很少被使用的字段时不要建立索引。
2.在一同值少的列上(字段上)不要建立索引,比如在学生表的"性别"字段上只有男,女两个不同值。
3.对经常更新的表就避免对其进行过多的索引。
4.数据量小的表最好不要使用索引,因为由于数据较少,可能查询全部数据花费的时间比遍历索引的时间还要短,索引就可能不会产生优化效果。
7.索引数据结构:
二叉树:有序的列值会出现单边问题
红黑树:数据量大的时候,树的高度不受控制,会影响查询效率
Hash表:范围查询效率低
B Tree:1.叶子节点具有相同的深度
2.叶子节点的指针为空
3.节点中的数据索引从左往右递增排列
B+Tree:
非叶子结点不存储data(数据行地址),只存储索引
叶子节点存储指针
顺序访问指针,提高区间访问性能
所有的叶子节点组合到一起,存储了完整的data(数据行地址|数据)。
mysql设置了每个节点存储的数据大小为16KB(可以进行修改的);
可以通过以下SQL进行查询
show GLOBAL STATUS LIKE 'Innodb_page_size'
InnoDB聚集索引:叶子节点包含了完整的数据记录。
MylSAM非聚集索引:叶子节点只包含了索引和数据所在行的地址。
InnoDB表必须有主键,并且推荐使用整形自增主键。
mysql的索引分为聚簇索引和非聚簇索引
mysql中,不同的存储引擎对索引的实现方式不同,大致说下MyISAM(非聚簇索引)和InnoDB(聚簇索引)两种存储引擎。
1.聚集索引表示表中存储的数据按照索引的顺序存储,检索效率比非聚集索引高,但对数据更新影响较大。
2.非聚集索引表示数据存储在一个地方,索引存储在另一个地方,索引带有指针指向数据的存储位置,非聚集索引检索效率比聚集索引低,但对数据更新影响较小。
聚簇索引的数据的物理存放顺序与索引顺序是一致的,即:只要索引是相邻的,那么对应的数据一定也是相邻地存放在磁盘上的。如果主键不是自增id,那么可以想象,它会干些什么,不断地调整数据的物理地址、分页,当然也有其他一些措施来减少这些操作,但却无法彻底避免。但,如果是自增的,那就简单了,它只需要一页一页地写,索引结构相对紧凑,磁盘碎片少,效率也高。因此采用innoDB存储引擎的数据库,表一定要设置自增列作为主键,这样才能提高数据查询以及插入的效率。
聚簇索引不但在检索上可以大大滴提高效率,在数据读取上也一样。比如:需要查询f~t的所有单词。
一个使用MyISAM的主索引,一个使用InnoDB的聚簇索引。两种索引的B+Tree检索时间一样,但读取时却有了差异。
因为MyISAM的主索引并非聚簇索引,那么他的数据的物理地址必然是凌乱的,拿到这些物理地址,按照合适的算法进行I/O读取,于是开始不停的寻道不停的旋转。聚簇索引则只需一次I/O。
不过,如果涉及到大数据量的排序、全表扫描、count之类的操作的话,还是MyISAM占优势些,因为索引所占空间小,这些操作是需要在内存中完成的。
创建和查看普通索引:
1.创建表时创建普通索引
create table table_name(
属性名 数据类型 [约束],
属性名 数据类型 [约束],
.
.
.
属性名 数据类型 [约束],
index|key 索引名(属性名1[(长度)][asc|desc])
);
练习:
use mysql_test;
drop table if exists shop;
create table shop(
shopId int primary key,
shopName varchar(20) not null,
shopInfo varchar(50),
index shopNameIndex(shopName)
);
explain select * from shop where shopName=''\G
2.在已经存在的表上创建普通索引
create index 索引名 on 表名(属性名[(长度)][asc|desc]);
练习:create index shopInfoIndex on shop(shopInfo);
3.通过SQL语句alter table创建普通索引
alter table tableName add index|key 索引名(属性名[(长度)][asc|desc]);
练习:--
查看表的创建信息,包含约束和索引
show create table shop \G
创建和查看唯一索引:
1.创建表时创建唯一索引:
create table table_name(
属性名 数据类型 [约束],
属性名 数据类型 [约束],
.
.
.
属性名 数据类型 [约束],
unique index|key [索引名](属性名1[长度][asc|desc])
);
2.在已经存在的表上创建唯一索引
create unique index 索引名 on 表名(属性名[(长度)][asc|desc]);
3.通过SQL语句alter table创建唯一索引
alter table table_name add unique index|key [索引名](属性名1[长度][asc|desc]);
alter table table_name drop index 索引名;
创建和查看全文索引:
1.创建表时创建全文索引:
create table table_name(
属性名 数据类型 [约束],
属性名 数据类型 [约束],
.
.
.
属性名 数据类型 [约束],
fulltext index|key [索引名](属性名1[长度][asc|desc])
)engine=MyISAM;
2.在已经存在的表上创建全文索引
create fulltext index 索引名 on 表名(属性名[(长度)][asc|desc]);
3.通过SQL语句alter table创建全文索引
alter table table_name add fulltext index|key [索引名](属性名1[长度][asc|desc]);
创建和查看空间索引:存储地图信息
1.创建表时创建空间索引:
create table table_name(
属性名 数据类型 [约束],
属性名 数据类型 [约束],
.
.
属性名 数据类型 [约束],
spatial index|key [索引名](属性名1[长度][asc|desc])
)engine=MyISAM;
2.在已经存在的表上创建空间索引
create spatial index 索引名 on 表名(属性名[(长度)][asc|desc]);
3.通过SQL语句alter table创建空间索引
alter table table_name add spatial index|key [索引名](属性名1[长度][asc|desc]);
创建和查看多列索引:
1.创建表时创建多列索引:
create table table_name(
属性名 数据类型 [约束],
属性名 数据类型 [约束],
.
.
.
属性名 数据类型 [约束],
index|key [索引名] (属性名1[长度][asc|desc],...属性名n[长度][asc|desc])
);
2.在已经存在的表上创建多列索引
create index 索引名 on 表名 (属性名[(长度)][asc|desc],...属性名1[长度][asc|desc]);
3.通过SQL语句alter table创建多列索引
alter table table_name add index|key [索引名] (属性名1[长度][asc|desc],...属性名n[长度][asc|desc]);
删除索引
alter table 表名 drop index 索引名;
drop index index_name on table_name;
普通索引:(由关键字KEY或INDEX定义的索引)的唯一任务是 加快对数据的访问速度。普通索引允许被索引的数据列包含重复的值。如果能确定某个数据列将只包含彼此各不相同的值,在为这个数据列常创建索引时应该用就用关键字UNIQUE把他定义成一个唯一索引。也就是说,唯一索引可以保证数据记录的唯一性。
唯一索引:不允许两行具有相同的索引值。
主键:是一种特殊的唯一索引,一张表中只能定义一个主键索引,通常有一列或列组合,用于唯一标识一条记录,使用关键字PRIMARY KEY来创建。为表定义一个主键将自动创建主键索引(聚簇索引)。当在查询中使用主键索引时,它还允许快速访问数据。
联合索引 :可以覆盖多个数据列,像INDEX(columnA, columnB)索引,这就是联合索引。
主键索引和唯一索引的区别:
(1) 对于主键/unique constraint , oracle/sql server/mysql等都会自动建立唯一索引;
(2) 主键不一定只包含一个字段,所以在主键的其中一个字段建唯一索引还是有必要的;
(3) 主键可作外键,唯一索引不可;
(4) 主键不可为空,唯一索引可;
(5) 主键可是多个字段的组合;
(6) 主键与唯一索引不同的是:
a.有not null属性;
b.每个表只能有一个。
(7) 主键索引一定是唯一索引, 唯一索引不是主键索引
(8) 主键可以与外键构成参照完整性约束,防止数据不一致
8.视图操作
视图,虚拟表,其内容与真实的表相似,包含一系列带有名称的列和行数据。
但是,视图并不在数据库中以存储数据值的形式存在。行和列数据来自定义视图的查询所引用基本表,并且在具体引用视图时动态生成。
视图使程序员只关心感兴趣的某些特定数据和他们所负责的特定任务。这样程序员只能看到视图中所定义的数据,而不是视图所引用表中的数据,从而提高数据库中数据的安全性。
优缺点:
优点:
1.简单化,数据所见即所得;
2.安全性,用户只能查询或修改他们所能见到的数据;
3.逻辑独立性,可以屏蔽真实表结构变化带来的影响;
缺点:
1.性能相对较差,简单的查询也会变的稍显复杂;
2.修改不方便,特别是复杂的聚合视图基本无法修改;
具体操作:
1.创建视图
create [algorithm={undefined|merge|temptable}] view view_name as 查询语句 [with [cascaded|local|]check option];
释义:
1.cascaded默认值 更新视图时要满足所有相关视图和表的条件,
2.local表示更新视图时满足该视图本身定义的条件即可。
2.查看视图
show tables;
show table status [from db_name] [like 'pattern'];
3.查看关于视图的定义信息
show create view viewname;
4.查看视图设计信息
describe|desc viewname
5.通过系统表查看视图信息
use information_schema;
select * from views where table_name='shopnameview'\G
6.删除视图
drop view view_name [,view_name...];
7.修改视图
create or replace view as 查询语句;
alter view viewname as 查询语句;
8.视图操作基本表
检索查询数据
select * from view_name;
操作基本表数据
insert into view_name(id,name) values(11,'testttt');
delete form view_name where name='testttt';
update view_name set name='tom';
9.练习:
1.在单表中创建视图
create view view_1 as select id,stuName from bm_registration;
2.创建视图并指定视图字段名
create view view_2(vid,name) as select id,stuName from bm_registration;
3.在多表中创建视图
1.获取开设课程表中每门课程的名称,价格,课程地点信息。
create view view_3 as
select bcc.course_id,bc.sportsEvent,bc.fee,bc.location
from bm_course bc join bm_course_choice bcc
on bc.id=bcc.course_id;
2.获取每个用户报名的课程名称,价格,课程地点信息。
create view view_4 as
select br.stuName,bc.sportsEvent,bc.fee,bc.location
from bm_course bc , bm_course_choice bcc , bm_coursechoice_user bcu,bm_registration br
where bc.id=bcc.course_id and bcc.id=bcu.coursechoice_id and bcu.user_id=br.id;
create view view_5 as
select br.stuName,bc.sportsEvent,bc.fee,bc.location
from bm_course bc join bm_course_choice bcc on bc.id=bcc.course_id join bm_coursechoice_user bcu on bcc.id=bcu.coursechoice_id join bm_registration br on bcu.user_id=br.id;
9.触发器操作
1.基本概念:
触发器是一种特殊类型的存储过程,它不同于存储过程,主要是通过事件触发而被执行的,即不是主动调用而执行的;而存储过程则需要主动调用其名字执行
触发器:trigger,是指事先为某张表绑定一段代码,当表中的某些内容发生改变(增、删、改)的时候,系统会自动触发代码并执行。
2.作用:
1.可在写入数据前,强制检验或者转换数据(保证护数据安全);
2.触发器发生错误时,前面用户已经执行成功的操作会被撤销,类似事务的回滚;
3.创建触发器:
1.基本语法:
delimiter 自定义结束符号
create trigger 触发器名字 触发时间 触发事件 on 表 for each row
begin
-- 触发器内容主体,每行用分号结尾
end自定义的结束符合
delimiter ;
on 表 for each:触发对象,触发器绑定的实质是表中的所有行,因此当每一行发生指定改变时,触发器就会发生。
2.触发时间:
当 SQL 指令发生时,会令行中数据发生变化,而每张表中对应的行有两种状态:数据操作前和操作后。
before:表中数据发生改变前的状态。
after:表中数据发生改变后的状态。
PS:如果 before 触发器失败或者语句本身失败,将不执行 after 触发器(如果有的话)。
3.触发事件:
触发器是针对数据发送改变才会被触发,对应的操作只有delete,insert,update语句。
4.在begin和end之间可以执行多个执行语句内容;表示激活触发器后被执行的语句。
4.操作触发器
查看触发器
show triggers;
删除触发器
drop trigger trigger_name;
5.练习:
1.先准备创建两张表:
create table shop(
shopId int primary key auto_increment,
shopName varchar(20) not null,
shopInfo varchar(50),
index shopNameIndex(shopName)
);
create table shop_bak as select * from shop;
2.创建插入触发器:
create trigger tri_diar after insert on shop for each row insert into shop_bak select * from shop;
delimiter $$
create trigger tri_diar2 before insert on shop for each row
begin
insert into shop_bak values(1,'default',now());
insert into shop_bak values(2,'defaulttest',now());
set @a=10;
end$$
delimiter ;
3.模拟数据插入:
insert into shop values(1,'tom','tom test');
4.查询原表数据
select * from shop;
5.查询备份表数据
select * from shop_bak;
6.删除触发器
drop trigger tri_diar;
10.Mysql运算符
1.算术运算符 + - * / %
2.比较运算符 > < = <=> != <> >= <=
列 between XXX and XXX
列 is null , 列 in (v1,v2,...,vn) , 列 like 表达式,列 regexp 正则表达式
模式字符 ^ $ . [字符集合] [^字符集合] str1|str2|str3 * + 字符串{N} 字符串(M,N)
3.逻辑运算符
and &&
or ||
not !
xor 异或
4.位运算符
& 与 | 或 ~ 取反 ^ 异或 << 左移 >> 右移
11.Mysql常用函数
1.字符串函数
1.concat(str1,str2,..strn) 字符串拼接
2.insert(str,x,y,instr) 将字符串str从第x位置开始,y个字符长的字符串替换为字符串instr
3.lower(str) 将字符串str中所有字符变为小写字符
4.upper(str) 将字符串str中所有字符变为大写字符
5.left(str,x) 返回字符串str最左边的x个字符
6.right(str,x) 返回字符串str最右边的x个字符
7.lpad(str,n,pad) 使用字符串pad对字符串str最左边进行填充,直到长度为n
8.rpad(str,n,pad) 使用字符串pad对字符串str最右边进行填充,直到长度为n
9.ltrim(str) 去掉字符串str左边的空格
10.rtrim(str) 去掉字符串str左边的空格
11.repeat(str,x) 返回字符串str重复x次的结果
12.replace(str,a,b) 使用字符串b替换字符串str中所有出现的字符串a
13.strcmp(str1,str2) 比较字符串str1和str2
14.trim(str) 去掉字符串str两边的空格
15.substring(str,x,y) 返回字符串str从x位置起y个字符长度的字符串
2.数值函数
abs(x) 返回x的绝对值
ceil(x) 返回大于x的最小整数
floor(x) 返回小于x的最大整数
mod(x,y) 返回x模y的值
rand() 返回0~1内的随机数
round(x,y) 返回数值x的四舍五入后有y位小数的数值
truncate(x,y) 返回数值x截断y位小数的数值
3.日期函数
curdate() 获取当前日期
curtime() 获取当前时间
now() 获取当前的日期和时间
unix_timestamp(date) 获取日期date的UNIX时间戳
from_unixtime() 获取unix时间戳的日期值
year(date) 返回日期date的年份
month(date) 返回日期date的月份
week(date) 返回日期date为一年中的第几周
day(date)|dayofmonth(date) 返回日期date为一个月中的第几天
hour(time) 返回日期time的小时值
minute(time) 返回日期time的分钟值
second(time) 返回日期time的秒值
monthname(date) 返回日期time的月份值
除此之外:
utc_date() 获取当前utc日期
utc_time() 获取当前utc时间
quarter(date) 获取日期date属于第几个季度
month(time) 获取日期time属于第几个月
获取日期date属于当前月的第几天
weekofyear(date)
weekday(date) 0-6 周一~周日
dayname(date)
dayofweek(date) 1-7 周日~周六
截取日期时间中的部分值函数extract(type from date)
select now(),extract(year from now()),extract(month from now()),extract(day from now()),extract(hour from now()),extract(minute from now()),extract(second from now());
计算日期和时间的函数
1.与默认日期和时间操作
to_days(date) 计算日期时间date和默认日期时间(0000年1月1日)之间相隔的天数。
from_days(number) 计算从默认日期时间开始经历number天之后的日期时间。
datediff(date1,date2) 计算两个日期之间相隔的天数。
2.与指定日期时间操作
adddate(date,n) 计算date+n天之后的日期
subdate(date,n) 计算date-n天之后的日期
addtime(time,n) 计算time+n秒之后的时间
subtime(time,n) 计算time-n秒之后的时间
4.系统信息函数
version()
database()
user()
last_insert_id()
5.mysql特殊功能函数
password(str) 对字符串str加密
format(x,n) 将数字x进行格式化,保留n位小数
inet_aton(ip) 将IP地址转化为数字
inet_ntoa(x) 将数字转化为IP
convert(s using cs) 将字符串s的字符集变成cs
convert(x,type) 将x变成type类型
cast(value as type)
MySQL 的CAST()和CONVERT()函数可用来获取一个类型的值,并产生另一个类型的值。两者具体的语法如下:
convert(x,type)
cast(value as type)
可以转换的类型是有限制的。这个类型可以是以下值其中的一个:
二进制,同带binary前缀的效果 : BINARY
字符型,可带参数 : CHAR()
日期 : DATE
时间: TIME
日期时间型 : DATETIME
浮点数 : DECIMAL
整数 : SIGNED
无符号整数 : UNSIGNED
6.转化函数
1.时间转字符串
date_format(日期,格式字符串)
select date_format(now(), '%Y-%m-%d %H:%i:%s');
2.字符串转时间
str_to_date(字符串,日期格式)
select str_to_date('2019-01-20 16:01:45', '%Y-%m-%d %H:%i:%s');
附日期格式如下:
%M 月名字(January……December)
%W 星期名字(Sunday……Saturday)
%D 有英语前缀的月份的日期(1st, 2nd, 3rd, 等等。)
%Y 年, 数字, 4 位
%y 年, 数字, 2 位
%a 缩写的星期名字(Sun……Sat)
%d 月份中的天数, 数字(00……31)
%e 月份中的天数, 数字(0……31)
%m 月, 数字(01……12)
%c 月, 数字(1……12)
%b 缩写的月份名字(Jan……Dec)
%j 一年中的天数(001……366)
%H 小时(00……23)
%k 小时(0……23)
%h 小时(01……12)
%I 小时(01……12)
%l 小时(1……12)
%i 分钟, 数字(00……59)
%r 时间,12 小时(hh:mm:ss [AP]M)
%T 时间,24 小时(hh:mm:ss)
%S 秒(00……59)
%s 秒(00……59)
%p AM或PM
%w 一个星期中的天数(0=Sunday ……6=Saturday )
%U 星期(0……52), 这里星期天是星期的第一天
%u 星期(0……52), 这里星期一是星期的第一
3.字符数字转化数字类型
select '123'+0; #转化为数字类型
12.Mysql变量
1.MySQL中的变量分类
系统变量:
全局变量
会话变量
自定义变量:
用户变量
局部变量
2.系统变量
说明:变量由系统定义,不是用户定义,属于服务器层面
注意:全局变量需要添加global关键字,会话变量需要添加session关键字,如果不写,默认会话级别
使用步骤:
1、查看所有系统变量
show global | session variables;
2、查看满足条件的部分系统变量
show global | session variables like '%char%';
3、查看指定的系统变量的值
select @@global | session 系统变量名;
4、为某个系统变量赋值
方式一:
set global| session 系统变量名=值;
方式二:
set @@global| session 系统变量名=值;
1.全局变量
作用域:针对于所有会话(连接)有效,但不能跨重启
1.查看所有全局变量
SHOW GLOBAL VARIABLES;
2.查看满足条件的部分系统变量
SHOW GLOBAL VARIABLES LIKE '%char%';
3.查看指定的系统变量的值
SELECT @@global.autocommit;
4.为某个系统变量赋值
SET @@global.autocommit=0;
SET GLOBAL autocommit=0;
2.会话变量
作用域:针对于当前会话(连接)有效
1.查看所有会话变量
SHOW SESSION VARIABLES;
2.查看满足条件的部分会话变量
SHOW SESSION VARIABLES LIKE '%char%';
3.查看指定的会话变量的值
SELECT @@autocommit;
SELECT @@session.tx_isolation;
4.为某个会话变量赋值
SET @@session.tx_isolation='read-uncommitted';
SET SESSION tx_isolation='read-committed';
3.自定义变量
说明:变量由用户自定义,而不是系统提供的
使用步骤:
1、声明
2、赋值
3、使用(查看、比较、运算等)
1.用户变量
作用域:针对于当前会话(连接)有效,作用域同于会话变量
#赋值操作符:=或:=
1.声明并初始化
SET @变量名=值;
SET @变量名:=值;
SELECT @变量名:=值;
2.赋值(更新变量的值)
#方式一:
SET @变量名=值;
SET @变量名:=值;
SELECT @变量名:=值;
#方式二:
SELECT 字段 INTO @变量名
FROM 表;
3.使用(查看变量的值)
SELECT @变量名;
2.局部变量
作用域:仅仅在定义它的begin end块中有效
应用在 begin end中的第一句话
1.声明
DECLARE 变量名 类型;
DECLARE 变量名 类型 【DEFAULT 值】;
2.赋值(更新变量的值)
#方式一:
SET 局部变量名=值;
SET 局部变量名:=值;
SELECT 局部变量名:=值;
#方式二:
SELECT 字段 INTO 局部变量名
FROM 表;
3.使用(查看变量的值)
SELECT 局部变量名;
3.案例
#案例:声明两个变量,求和并打印
#用户变量
SET @m=1;
SET @n=1;
SET @sum=@m+@n;
SELECT @sum;
#局部变量
DECLARE m INT DEFAULT 1;
DECLARE n INT DEFAULT 1;
DECLARE SUM INT;
SET SUM=m+n;
SELECT SUM;
#注意:必须运行在BEGIN END中,否则会报错
4.用户变量和局部变量的对比
作用域 定义位置 语法
用户变量 当前会话 会话的任何地方 加@符号,不用指定类型
局部变量 定义它的BEGIN END中 BEGIN END的第一句话 一般不用加@,需要指定类型
13.存储过程和函数操作
1.概念:
MySQL 5.0 版本开始支持存储过程。
存储过程(Stored Procedure)是一种在数据库中存储复杂程序,以便外部程序调用的一种数据库对象。
存储过程是为了完成特定功能的SQL语句集,经编译创建并保存在数据库中,用户可通过指定存储过程的名字并给定参数(需要时)来调用执行。
存储过程思想上很简单,就是数据库SQL语言层面的代码封装与重用。
优点:
1.存储过程可封装,并隐藏复杂的商业逻辑(提高了代码的重用性)。
2.存储过程可以回传值,并可以接受参数。
3.存储过程无法使用 SELECT 指令来运行,因为它是子程序,与查看表,数据表或用户定义函数不同。
4.存储过程可以用在数据检验,强制实行商业逻辑等。
缺点:
1.存储过程,往往定制化于特定的数据库上,因为支持的编程语言不同。当切换到其他厂商的数据库系统时,需要重写原有的存储过程。
2.存储过程的性能调校与撰写,受限于各种数据库系统。
存储过程/函数含义:一组预先编译好的SQL语句的集合,理解成批处理语句
1、提高代码的重用性
2、简化操作
3、减少了编译次数并且减少了和数据库服务器的连接次数,提高了效率
函数与存储过程区别:
存储过程:可以有0个返回,也可以有多个返回,适合做批量插入、批量更新
函数:有且仅有1个返回,适合做处理数据后返回一个结果
2.存储过程:
创建语法:
create procedure 存储过程名(参数列表)
begin
存储过程体(一组合法有效的SQL语句)
end
参数模式:在mysql中提供了三组参数模式
(in name char,out pw varchar(20),inout a int)
IN 该参数可以用作输入,也就是说该参数需要调用方传入值
OUT 该参数可以作为输出,类似python中return之后的返回值
INOUT 该参数即可以作为参数又可以作为参数输出
其他:存储过程体只有一条语句时, begin和end可以省略;否则就需要使用delimiter来重新设置语句结束符
调用存储过程:
call 存储过程名(实参列表);
举例:
调用in模式的参数:call sp1('值');
调用out模式的参数:set @name; call sp1(@name);select @name;
调用inout模式的参数:set @name=值; call sp1(@name); select @name;
查看:
show create procedure 存储过程名;
删除存储过程:
drop procedure 存储过程名;
实例演示:
1.无参,向指定表插入数据
create table s_bm.admin(id int primary key auto_increment,username varchar(20),password varchar(20));
插入到admin表中五条记录
drop procedure myp1;
delimiter $$
create procedure myp1()
begin
insert into admin(username,password) values('john1','0000'),('lily','0000'),('rose','0000'),('jack','0000'),('tom','0000');
end$$
delimiter ;
create procedure myp1() insert into admin(username,password) values('john1','0000'),('lily','0000'),('rose','0000'),('jack','0000'),('tom','0000');
#调用
call myp1();
2.IN模式
#案例1 :创建存储过程实现,用户是否登录成功
drop procedure myp2;
delimiter $$
create procedure myp2(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$$
delimiter ;
#调用
call myp2('张飞','8888');
call myp2('tom','0000');
3.OUT模式,根据指定Id查询其姓名并返回
#案例1:根据输入的用户名,返回对应的密码
drop procedure myp3;
create procedure myp3(in name varchar(20),out passwd varchar(20)) select password into passwd from admin where username=name;
call myp3('tom',@pw);
select @pw;
4.INOUT模式,参数既能作为返回值,也能作为接收值,在调用该存储过程的时候,就需要传入已经初始化的两个用户变量来完成。
drop procedure myp4;
delimiter $$
create procedure myp4(inout stuId int)
begin
set stuId=10;
end$$
delimiter ;
set @id=1;
call myp4(@id);
3.函数:
1.创建:
1.语法:
create function 函数名(参数名 参数类型) returns 返回类型
begin
函数体
end
2.注意:
1.函数体:肯定会有return语句,如果没有会报错;如果return语句没有放在函数体的最后也不报错,但不建议
2.函数体中仅有一句话,则可以省略begin end
3.使用delimiter语句设置结束标记函数体中肯定需要有return语句
2.调用
select 函数名(实参列表);
1.参数列表 包含两部分:参数名 参数类型
3.查看
show create function 函数名;
4.删除
drop function 函数名;
5.案例:
1.无参有返回
#案例:返回用户的个数
delimiter $
create function myf1() returns int
BEGIN
declare c int default 0;#定义局部变量
select count(*) into c from bm_registration;
return c;
END $
delimiter ;
SELECT myf1()$
delimiter ;
#2.有参有返回
#案例1:根据学生名字,返回它的手机号码
drop function myf2;
delimiter $
create function myf2(name VARCHAR(20)) returns double
BEGIN
set @phone=0;#定义用户变量
select phoneNumber into @phone #赋值
from bm_registration
where stuName = name;
return @phone;
END $
delimiter ;
select myf2('李祺烁');
#案例2:创建函数,实现传入两个float,返回二者之和
delimiter $
create function myf_add(num1 float,num2 float) returns float
BEGIN
declare sum float default 0;
set sum=num1+num2;
return sum;
END $
delimiter ;
select myf_add(1,2);
14.Mysql事物
1.概念
1.MySQL 事务主要用于处理操作量大,复杂度高的数据。比如说,在人员管理系统中,你删除一个人员,你即需要删除人员的基本资料,也要删除和该人员相关的信息,如信箱,文章等等,这样,这些数据库操作语句就构成一个事务!
2.在MySQL中只有使用了Innodb数据库引擎的数据库或表才支持事务。
3.事务处理可以用来维护数据库的完整性,保证成批的SQL语句要么全部执行,要么全部不执行。
4.事务用来管理insert,update,delete语句
5.一般来说,事务是必须满足4个条件(ACID)::原子性(Atomicity,或称不可分割性)、一致性(Consistency)、隔离性(Isolation,又称独立性)、持久性(Durability)。
1.原子性:一个事务(transaction)中的所有操作,要么全部完成,要么全部不完成,不会结束在中间某个环节。事务在执行过程中发生错误,会被回滚(Rollback)到事务开始前的状态,就像这个事务从来没有执行过一样。
2.一致性:在事务开始之前和事务结束以后,数据库的完整性没有被破坏。这表示写入的资料必须完全符合所有的预设规则,这包含资料的精确度、串联性以及后续数据库可以自发性地完成预定的工作。
3.隔离性:数据库允许多个并发事务同时对其数据进行读写和修改的能力,隔离性可以防止多个事务并发执行时由于交叉执行而导致数据的不一致。事务隔离分为不同级别,包括读未提交(Read uncommitted)、读提交(read committed)、可重复读(repeatable read)和串行化(Serializable)。
4.持久性:事务处理结束后,对数据的修改就是永久的,即便系统故障也不会丢失。
6.在 MySQL 命令行的默认设置下,事务都是自动提交的,即执行 SQL 语句后就会马上执行 COMMIT 操作。因此要显式地开启一个事务务须使用命令 BEGIN 或 START TRANSACTION,或者执行命令 SET AUTOCOMMIT=0,用来禁止使用当前会话的自动提交。
2.事务控制语句:
1.begin 或 start transcation 显式地开启一个事务;
2.commit 也可以使用 commit work,commit会提交事务,并使已对数据库进行的所有修改成为永久性的;
3.rollback 也可以使用 rollback work,不过二者是等价的。回滚会结束用户的事务,并撤销正在进行的所有未提交的修改;
4.savepoint identifier,savepoint 允许在事务中创建一个保存点,一个事务中可以有多个savepoint;
5.release savepoint identifier 删除一个事务的保存点,当没有指定的保存点时,执行该语句会抛出一个异常;
6.rollback to identifier 把事务回滚到标记点;
7.set transaction用来设置事务的隔离级别。InnoDB 存储引擎提供事务的隔离级别有read uncommitted、read committed 、repeatable read 和serializable。
3.Mysql事务处理主要有两种方法:
1、用 begin, rollback, commit
begin 开始一个事务
rollback 事务回滚
commit 事务确认
2、直接用 set 来改变 MySQL 的自动提交模式:
SET AUTOCOMMIT=0 禁止自动提交
SET AUTOCOMMIT=1 开启自动提交
4.事务隔离级别
1.事务中产生的问题:
1.脏读 主要针对update操作。 一个事务A读到另一个事务B中修改过但是还没有提交的数据
2.不可重复读 主要针对update操作。 一个事务A在第一次读数据和第二次读数据之间,有另一个事务B把这个数据更改并提交了,所以就出现了事务A里面读一个数据俩次,但是读到的结果是不同的。
3.幻读 主要针对的是insert/delete操作。事务A第一次用where条件筛选出了10条数据,事务A第二次用通样的where条件筛选出的却是11条数据,因为事务B在事务A的第一次和第二次查询直接进行了插入操作,并且插入的这个数据满足事务A的where筛选条件.
2.事务隔离级别:
read-uncommitted 不提交也能读
read-committed 提交之后才能读 解决了脏读
repeatable-read 解决了脏读和不可重复读
serializable 三个问题都解决了
级别越高解决的问题越多但是效率越低。
注意:并不是所有数据库都支持这四种事务隔离级别,比如oracle就只支持第二种和第四种这俩种,比如mysql就四种全支持.
3.默认隔离级别:
在MySQL数据库中,引擎默认使用repeatable read
查看默认的事务隔离级别:
show variables like 'tx_isolation';
修改默认事务隔离级别:
修改my.cnf配置文件,使用 transaction_isolation=repeatable-read
4.修改会话的事务隔离级别:
set session transaction isolation level read uncommitted|read committed|repeatable read|serializable;
set session transaction isolation level read uncommitted;
set session transaction isolation level read committed;
set session transaction isolation level repeatable read;
set session transaction isolation level serializable;
4.Sql优化
1、创建索引(恰当的添加索引)
如果不加索引的话,那么查找任何哪怕只是一条特定的数据都会进行一次全表扫描,如果一张表的数据量很大而符合条件的结果又很少,那么不加索引会引起致命的性能下降。但是也不是什么情况都非得建索引不可,比如性别可能就只有两个值,建索引不仅没什么优势,还会影响到更新速度,这被称为过度索引。
所以要建在合适的地方,合适的对象上。经常操作 / 比较 / 判断的字段应该建索引。
2、适当的用复合索引代替单索引
比如有一条语句是这样的:select * from users where area=’beijing’ and age=22;
如果我们是在area和age上分别创建单个索引的话,由于mysql查询每次只能使用一个索引,所以虽然这样已经相对不做索引时全表扫描提高了很多效率,但是如果在area、age两列上创建复合索引的话将带来更高的效率。如果我们创建了(area, age,salary)的复合索引,那么其实相当于创建了(area,age,salary)、(area,age)、(area)三个索引,这被称为最佳左前缀特性。
因此我们在创建复合索引时应该将最常用作限制条件的列放在最左边,依次递减。
3、索引不会包含有NULL值的列
只要列中包含有NULL值都将不会被包含在索引中,复合索引中只要有一列含有NULL值,那么这一列对于此复合索引就是无效的。所以我们在数据库设计时不要让字段的默认值为NULL。
4、使用短索引
对串列进行索引,如果可能应该指定一个前缀长度。例如,如果有一个CHAR(255)的 列,如果在前10 个或20 个字符内,多数值是惟一的,那么就不要对整个列进行索引。短索引不仅可以提高查询速度而且可以节省磁盘空间和I/O操作。
5、任何地方都不要使用 select * from t ,用具体的字段列表代替“*”,不要返回用不到的任何字段。
6、like语句操作(不鼓励模糊查询,会全表扫描)
一般情况下不鼓励使用like操作,如果非使用不可,如何使用也是一个问题。like “%aaa%” 不会使用索引而like “aaa%”可以使用索引。
7、区分in和exists、not in和not exists
区分in和exists主要是造成了驱动顺序的改变(这是性能变化的关键),如果是exists,那么以外层表为驱动表,先被访问,如果是IN,那么先执行子查询。所以IN适合于外表大而内表小的情况;EXISTS适合于外表小而内表大的情 况。
例子:
select * from 表A where id in (select id from 表B)
上面SQL语句相当于
select * from 表A where exists(select * from 表B where 表B.id=表A.id)
NOT IN和操作都不会使用索引将进行全表扫描。NOT IN可以NOT EXISTS代替。
在许多基于基础表的查询中,为了满足一个条件,往往需要对另一个表进行联接.在这种情况下, 使用EXISTS(或NOT EXISTS)通常将提高查询的效率. 在子查询中,NOT IN子句将执行一个内部的排序和合并. 无论在哪种情况下,NOT IN都是最低效的 (因为它对子查询中的表执行了一个全表遍历). 为了避免使用NOT IN ,我们可以把它改写成外连接(Outer Joins)或NOT EXISTS.
例子:
(高效)SELECT * FROM EMP (基础表) WHERE EMPNO > 0 AND EXISTS (SELECT ‘X’ FROM DEPT WHERE DEPT.DEPTNO = EMP.DEPTNO AND LOC = ‘MELB’)
(低效)SELECT * FROM EMP (基础表) WHERE EMPNO > 0 AND DEPTNO IN(SELECT DEPTNO FROM DEPT WHERE LOC = ‘MELB’)
8、对于连续的数值,能用 between 就不要用 in
如下:SELECT * FROM t_order WHERE id BETWEEN 2 AND 3
9、尽量不要使用or,会造成全表扫描。如下:
SELECT * FROM t_order WHERE id = 1 OR id = 3
优化:可以用union代替or。如下:
SELECT * FROM t_order WHERE id = 1
UNION
SELECT * FROM t_order WHERE id = 3
10、尽量不要在 where 子句中对字段进行表达式操作,这样也会造成全表扫描。如:
select id FROM t_order where num/2=100
应改为:
select id FROM t_order where num=100*2
11、尽量不要在where条件中等号的左侧进行表达式.函数操作,会导致全表扫描。如下:
SELECT * FROM t_order2 WHERE score/10 = 10
SELECT * FROM t_order2 WHERE SUBSTR(customer,1,5) = 'zhang'
优化:
将表达式.函数操作移动到等号右侧。如下:
SELECT * FROM t_order2 WHERE score = 10*10
SELECT * FROM t_order2 WHERE customer LIKE 'zhang%'
12、尽量不要使用where 1=1的条件
有时候,在开发过程中,为了方便拼装查询条件,我们会加上该条件,这样,会造成进行全表扫描。如下:
SELECT * FROM t_order WHERE 1=1
优化:
如果用代码拼装sql,则由代码进行判断,没where加where,有where加and
如果用mybatis,请用mybatis的where语法。
13、应尽量避免在where子句中对字段进行null值判断,否则将导致引擎放弃使用索引而进行全表扫描,如:
select id from t where num is null
可以在num上设置默认值0,确保表中num列没有null值,然后这样查询:
select id from t where num=0
14、开启查询缓存。
避免某些SQL函数直接在 SQL 语句中使用,从而导致 Mysql 缓存失效。
query_cache_type【0(OFF)1(ON)2(DEMAND)】来控制缓存的开关. 数据修改会带来缓存失效。
15、表的设计
垂直分割表,使得固定表与变长表分割,从而降低表的复杂度和字段的数目。
16、读写分离方案
海量数据的存储及访问,通过对数据库进行读写分离,来提升数据的处理能力, 数据库的写操作都集中到一个数据库上,而一些读的操作呢,可以分解到其它数据库上。
优点:得数据库的处理压力分解到多个数据库上,从而大大提升数据处理能力
缺点:付出数据复制的成本。
17、缓存技术
搭建redis或者memcache做为缓存层,提高数据库读取速度。
18、Mysql limit 分页机制和优化实例
300W数据,select XXX from tableA limit 1000000,10; 会导致mysql将1000000之前的所有数据全部扫描一次,大量浪费了时间。
解决办法:(1) 查询字段,加索引,可以建立与主键的复合索引
(2)limit最大的问题在于要扫描前面不必要的数据,所以可以先对主键的条件做设定,然后记录住主键的位置再取行。
select * from p2p_20131230 where main_id > 1000000 order by main_id limit 10;
19、增加中间表
对于需要经常联合查询的表,可以建立中间表以提高查询效率。通过建立中间表,把需要经常联合查询的数据插入到中间表中,然后将原来的联合查询改为对中间表的查询,以此来提高查询效率。
5.管理用户
1.查看现有用户:select host,user,authentication_string from mysql.user;
2.新建用户:create user “username”@“host” identified by “password”;
create user “briup123”@“localhost” identified by “briup123”;
/host=“localhost"为本地登录用户,host=“ip"为ip地址登录,host=”%”,为外网ip登录/
3.删除用户:drop user ‘username’@‘host’;
drop user ‘briup123’@‘localhost’;
4.授权:grant privileges on databasename.tablename to ‘username’@‘host’ IDENTIFIED BY ‘PASSWORD’;
grant all privileges on . to ‘briup123’@‘localhost’ IDENTIFIED BY ‘briup123’;
1. GRANT命令说明:
1.priveleges(权限列表),可以是all priveleges,表示所有权限,也可以是select、update等权限,多个权限的名词,相互之间用逗号分开
2.on用来指定权限针对哪些库和表。
3.. 中前面的号用来指定数据库名,后面的号用来指定表名。
4.to 表示将权限赋予某个用户, 如 jack@‘localhost’ 表示jack用户,@后面接限制的主机,可以是IP、IP段、域名以及%,%表示任何地方。注意:这里%有的版本不包括本地,以前碰到过给某个用户设置了%允许任何地方登录,但是在本地登录不了,这个和版本有关系,遇到这个问题再加一个localhost的用户就可以了。
5.identified by指定用户的登录密码,该项可以省略。
6.WITH GRANT OPTION 这个选项表示该用户可以将自己拥有的权限授权给别人。注意:经常有人在创建操作用户的时候不指定WITH GRANT OPTION选项导致后来该用户不能使用GRANT命令创建用户或者给其它用户授权。
备注:可以使用GRANT重复给用户添加权限,权限叠加,比如你先给用户添加一个select权限,然后又给用户添加一个insert权限,那么该用户就同时拥有了select和insert权限。
2.授权原则说明:
权限控制主要是出于安全因素,因此需要遵循一下几个经验原则:
a、只授予能满足需要的最小权限,防止用户干坏事。比如用户只是需要查询,那就只给select权限就可以了,不要给用户赋予update、insert或者delete权限。
b、创建用户的时候限制用户的登录主机,一般是限制成指定IP或者内网IP段。
c、初始化数据库的时候删除没有密码的用户。安装完数据库的时候会自动创建一些用户,这些用户默认没有密码。
d、为每个用户设置满足密码复杂度的密码。
e、定期清理不需要的用户。回收权限或者删除用户。
eg:
/授予用户通过外网IP对于该数据库的全部权限/
grant all privileges on test
.* to ‘test’@’%’ ;
/授予用户在本地服务器对该数据库的全部权限/
grant all privileges on test
.* to ‘test’@‘localhost’;
grant select on test.* to ‘user1’@‘localhost’; /给予查询权限/
grant insert on test.* to ‘user1’@‘localhost’; /添加插入权限/
grant delete on test.* to ‘user1’@‘localhost’; /添加删除权限/
grant update on test.* to ‘user1’@‘localhost’; /添加权限/
flush privileges; /刷新权限/
5.查看权限
show grants;
查看某个用户的权限:show grants for ‘jack’@’%’;
6.删除权限
revoke privileges on databasename.tablename from ‘username’@‘host’;
revoke delete on test.* from ‘jack’@‘localhost’;
7.更改用户名
rename user ‘jack’@’%’ to ‘jim’@’%’;
8.修改密码
1.用set password命令
set password for ‘briup123’@‘localhost’ = password(‘123456’);
2.用mysqladmin
mysqladmin -u用户名 -p旧密码 password 新密码
mysqladmin --ubriup123 -p123456 password 1234abcd
3.用update直接编辑user表