数据库
本质: 一套C/S socket 软件
分类
关系型数据库:
数据与数据建立关联关系
SQLServe,仅支持Windows
MySQL, 免费 开源 性能不差 先后被sun 和Oracle 收购目前属于Oracle公司
mariaDB mysql创始人自己又自己开发的一款数据库
Oracle, 目前较好的数据库 收费高
DB2, IBM 收费
非关系型数据库: MongoDB,Redis,memcache
相关概念:
数据: 记录事物状态的符号
记录: 事物典型特征的组合 (数据行)
表 : 文件
库 : 文件夹
数据库管理系统(DBMS): 用于管理库的软件 C/S程序
数据库服务器 : 运行着DBMS的计算机称为数据库服务器
MySQL数据库
安装
windows版本
1、下载:MySQL Community Server 5.7.16
http://dev.mysql.com/downloads/mysql/2、解压
如果想要让MySQL安装在指定目录,那么就将解压后的文件夹移动到指定目录,如:C:mysql-5.7.16-winx643、添加环境变量
【右键计算机】--》【属性】--》【高级系统设置】--》【高级】--》【环境变量】--》【在第二个内容框中找到 变量名为Path 的一行,双击】 --> 【将MySQL的bin目录路径追加到变值值中,用 ; 分割】4、初始化
mysqld --initialize-insecure5、启动MySQL服务
mysqld # 启动MySQL服务6、启动MySQL客户端并连接MySQL服务
mysql -u root -p # 连接MySQL服务器
上一步解决了一些问题,但不够彻底,因为在执行【mysqd】启动MySQL服务器时,当前终端会被hang住,那么做一下设置即可解决此问题:
注意:--install前,必须用mysql启动命令的绝对路径
制作MySQL的Windows服务,在终端执行此命令:
"c:mysql-5.7.16-winx64inmysqld" --install
移除MySQL的Windows服务,在终端执行此命令:
"c:mysql-5.7.16-winx64inmysqld" --remove
注册成服务之后,以后再启动和关闭MySQL服务时,仅需执行如下命令:
启动MySQL服务
net start mysql
关闭MySQL服务
net stop mysql
其他操作
设置密码
mysqladmin.exe 用于设置密码
mysqladmin -uroot -p旧密码 password 新密码
破解密码
可以在启动服务器时 告诉他 让他不要读取密码文件
1.mysqld --skip-grant-tables
2.无密码登录服务器
3.使用update 来更新你的密码 在msyql.user表中
在客户端 update mysql.user set password = password("321") where user = "root" and host="localhost";
4.重启服务 验证新密码
安装mysql得到两个程序
1.服务器程序
存取数据时服务器的工作
2.客户端程序
命令服务器来完成存取工作
客户端将命令发送给服务器 服务器解析执行命令 返回客户端要的数据
服务器为了保证数据安全需要进行用户验证
默认有一个root 账户 默认没有密码 不安全
需要修改密码:
在服务器的终端中执行
mysqladmin.exe -u要改的用户名 -p旧密码 password 新密码
在服务器上执行命令时 如果看到Install/Remove of the Service Denied! 说明权限不够
得用管理员身份运行
如果忘记密码 要破解 也需要在服务器终端启动mysql服务 并且需要添加跳过授权表的参数
mysql -uroot -padmin 用mysql自带的客户端登录服务器
-u 用户名 -p 密码 -h 服务器的ip -P端口号 在本机上执行客户端不需要指的 -h -P
基础SQL语句
库相关
创建
create database 数据库名 charset 编码名称
修改
alter database 数据库名 charset gbk
查
show databases; 查看所有数据
show create database 数据库名 查看建库语句
删除
drop database 数据库名
表相关
创建 create table t1(id int,name char); 修改 改结构 alter table 表名 add | drop | modify | change add 后面跟 字段名 数据类型 drop 后面跟 字段名 modify 后面跟 字段名 新类型 change 后面跟 旧字段名 新的字段名 新类型 该属性 编码 alter table t1 charset gbk; 表名 rename table 旧表名 to 新表名 查 show tables; show create table 表名 查看建表语句 desc 表名 查看表结构(字段) 删除 drop table 表名 truncate table 表名,重建表(清空数据)
记录相关
添加
insert into 表名 values(值1...),(值1....)....
插入时注意 值得顺序 和 类型必须与表结构一致
修改
update 表名 set 字段名=新的值 where 条件
可以同时修改多行 用逗号来隔开字段
没有条件就全改
查
select *|字段名 from 表名 *表示所有字段
删除
delete from 表名 where条件
没有条件就全删
创建表的完整语法
create table 表名(
字段名称 数据类型[(长度) 约束条件],
字段名称 数据类型[(长度) 约束条件]
)
数据存储引擎
什么是引擎 ? 一个功能的核心部分
引擎可以被分类
需求场景的不同催生了不同的引擎类别
mysql
核心功能是存储数据 涉及到存储数据的代码 就称之为存储引擎
根据不同的需求 也有着不同的引擎分类
不同的引擎测试
创建表时在最后指定引擎名称 engine = xxx
create table t1(id int)engine=innodb
create table t1(id int not null)engine=CVS
create table t1(id int)engine=memory
create table t1(id int)engine=blackhole
总结: innodb是默认的引擎 因为 它是永久存储 并且 支持事务,行锁,外键
数据类型
存在不同数据类型好处
1.描述事物 更加准确
2.描述起来更方便
3.节省内存空间
mysql支持的数据类型:
整型
tinyint smallint mediumint int bigint
字节数: 1 2 3 4 8
默认情况下整型是有符号的 需要用一个二进制位存储符号
给整型加上 约束 unsigned来表示无符号
如果数据超出范围就尽可能保存最大的 例如 在无符号下 保存256 其实存的255
如果有符号 例如 tinyint 保存-1280 其实存的是 -128 是最小值
浮点型
分类: float double decimal
字节数: 4 8 不确定(手动指定)
给浮点设置宽度限制
float(m,d)
double(m,d)
decimal(m,d)
长度说明
m表示 这个浮点数整体的长度
d表示 小数部分的长度
例如: float(5,3) 最大值: 99.999
异同
相同点: 小数部分最大长度都是30
float和double的最大长度为255
不同点: decimal的整体最大长度65
精度不同
double 比 float 精度高
decimal 是准确的 不会丢失精度
字符型
分类
char 定长字符
varchar 变长字符
char类型的长度是固定 无论你存储的数据有多长 占用的容量都一样
char(3) 存储的数据为 "a" 在硬盘保存的数据还是占3字符长度 实际保存的是"a "
varchar 长度是可变的 存储的数据有多长就占用多长
varchar(3) 存储的数据为 "a" 在硬盘保存的数据还是占1字符长度 实际保存的是"a"
yxx exx lxx zxx cx wxx char(3)
(1bytes+yx)(1bytes+exx)(1bytes+lx)(1bytes+zxx) varchar(3)
如果是可变长度 则有问题 不知道数据从哪里开始到哪里结束 所以需要有一个位置保存数据的长度
vharchar 能支持的最大长度是65535 用于保存数据长度的数据最长两个bytes
如果是char类型 如果你的数据不足指定长度 就在后面用空格补全
验证:
使用一个 char_length的函数 可以查看字符的长度
create table t18(a char(4),b varchar(4));
insert into t18 value("x","x");
select char_length(a),char_length(b) from t18;
两个字段的长度都为1
结论:
这是因为 mysql在存储时 自动加上的空格 对使用者而言是没有意义的 所以mysql自动帮你处理掉空格了
我们可以设置sql模式 来让它现出原形
set global sql_mode = "PAD_CHAR_TO_FULL_LENGTH,STRICT_TRANS_TABLES"
设置完成后重启msyql 再次查询长度
注意:
当你在执行这样的查询语句时 mysql会自动将参数末尾的空格去除
select *from t19 where name = "yh"
当你在使用模糊搜索时 要注意 定长字符 后面可能会有空格 所以最好在后面加上百分号 %
select *from t19 where name like "yh";
% 任意个数的任意字符
_ 1个任意字符
如何选择
char
存取效率高
浪费存储空间
varchar
存取效率低于char
节省存储空间
使用起来感受不到区别 通常用的是char
char和varchar 长度都比较小 最大就是65535
大文本类型:
TEXT系列 TINYTEXT TEXT MEDIUMTEXT LONGTEXT 文本是带有编码
BLOB 系列 TINYBLOB BLOB MEDIUMBLOB LONGBLOB 也是字符数据 但是不带编码二进制类型: 用于存储多媒体数据 比如视频 但是我们一般不会将多媒体数据存到数据 而是存储文件路径地址
BINARY系列 BINARY VARBINARY 存储二进制数据
时间类型
分类
time 时分秒 HH:MM:SS
year 年份
date 日期 年月日
datetime 日期加时间 年月日 时分秒 年份最大是9999
timestamp 时间戳 从1970-1-1开始算 年份最大是2037
共同点: 时间的存取通过字符串类型
都可以使用now()函数来插入当前时间
datetime 和 时间戳都能够表示日期和时间
不同之处是: 年份最大范围不同
时间戳可以为空 代表当前时间
时间戳在你更新记录时 会自动更新为当前时间
枚举
用于描述 一个已知范围的数据 例如性别: 只有男 女 或其他
enum("man","woman","other")
总结: 枚举中只能是字符串类型
添加的数据只能是已经出现在枚举中的值
你的值只能是其中的一个
你也可以使用枚举值的序号来插入值 从1开始
多选1
集合
用于描述一堆数据 比如你的兴趣爱好
set("watch movie","listen music","play game")
总结:集合中的数据 只能是字符串
添加的数据只能是已经出现在集合中的值
你的值可以是其中的任意几个
你也可以使用枚举值的序号来插入值 从1开始 但是只能给一个序号
多选多
约束条件
除了数据类型以外额外添加的约束
为了保证数据的合法性 完整性
not null
非空约束 数据不能为空
create table student (id ind,
name char(10) not null);
default
默认值约束 可以指定字段的默认值
create table user (id ind,name char(10) not null,
sex char(1) default "woman");
unique
唯一性约束 该字段的值不能重复
是一种索引 可以加速查找
单列唯一:
create table t5(idcard char(18) unique);
联合唯一:
create table t6(idcard char(18),
phonenumber char(11),
unique(idcard,phonenumber));
primary key
主键约束
是一种索引 必然存在硬盘上的某个文件中 是物理层面
等价于not null 加unique约束
create table stu (stuid int primary key,name char(3));
多列联合主键
create table t8(idcard char(18),
phonenumber char(11),
primary key(idcard,phonenumber));
有主键 和没有主键的区别?
1.无法区分两个相同记录
2.有主键则意味有这索引 效率更高
3.可以建立关联关系
auto_increment
自动增长
通常搭配主键字段使用 可以自动为你的数据分配逐渐
create table t9(id int primary key auto_increment,
name char(3));
修改自动增长的起始位置
alter table t9 auto_increment = 7;
注意: 自动增长 只能用于整型
如果主键是自动增长 你可以跳过这个字段 也可以为它插入null 都可以
foreign key
表与表之间建立联系
表与表之间的关系
一对一
多对一:
将'多' 一方设为从表 加上外键
多对多:
创建第三张 关联表
语法
create table dept(id int primary key auto_increment,
name char(10),
manager char(10));
create table emp(id int primary key auto_increment,
name char(10),dept_id int,
foreign key(dept_id) references dept(id));
添加外键约束时:
被关联的表需要先被创建
部门数据(主表)应该先插入 员工数据(从表)后插入
在删除部门数据前(主表)前 要保证该部门的员工数据都删除了
在更新部门编号前 要先保证没有员工关联到这个部门
注:外键加上以后 主表中的数据 删除 和更新时 都受到限制
解决的方案是为 外键 添加 级联操作
级联操作
指的是就是同步更新和删除
语法:在创建外键时 在后面添加 on update cascade 同步更新
on delete cascade 同步删除
create table class(id int primary key auto_increment,
name char(10));
create table student(
id int primary key auto_increment,
name char(10),
c_id int,
foreign key(c_id) references class(id)
on update cascade
on delete cascade
);
查询语句
完整查询语句
select [distinct] {* | 字段名 | 聚合函数 | 表达式} from 表名
[where 条件
group by 字段名
having 条件
order by 字段名
limit 显示的条数]
关键字执行顺序
def select()
from() 打开文件
where() 读取每一行并判断是否满足条件
group() 对数据进行分组
having() 再分组之后进行过滤 having不单独出现 仅用于分组之后进行过滤
distinct() 去重
order() 用于对筛选后的数据 进行排序
limit() 限制显示的条数
最后根据select后制定的字段来显示数据
一、where过滤
where字句中可以使用:
-
比较运算符:> < >= <= <> != #不等于用 != 不用 <>
select id,name from db39.emp where id >= 3 and id <= 6
-
between 80 and 100
select * from db39.emp where id between 3 and 6; # >=3 and <=6
-
in(80,90,100) 值是80或90或100
select * from emp where salary in (20000,18000,17000); # select * from emp where salary = 20000 or salary = 18000 or salary = 17000;
-
like 'egon%', pattern可以是%或_, %表示任意多字符, _表示一个字符
select name,salary from db39.emp where name like '%i%' #要求:查询员工姓名中包含i字母的员工姓名与其薪资 select name,salary from db39.emp where name like '____'; #要求:查询员工姓名是由四个字符组成的的员工姓名与其薪资 select name,salary from db39.emp where char_length(name) = 4; #结果与上一条一致
-
逻辑运算符:在多个条件直接可以使用逻辑运算符 and or not
select * from db39.emp where id not between 3 and 6; select * from emp where salary not in (20000,18000,17000);
针对NULL必须用is,不能用=
select name,post from db39.emp where post_comment is NULL;
二、group by分组
如果不设置成only_full_group_by模式,分完组后用*默认取出的是组内的第一个人的数据。但分完组后单独取组内的某个元素是没有意义的,所以,分组前,一般会对模式做如下处理
#设置sql_mode为only_full_group_by,意味着以后但凡分组,只能取到分组的依据
```Python
set global sql_mode="strict_trans_tables,only_full_group_by";
```
聚合函数: max(), min(), avg(), sum(),count()
group_concat:(分组之后用)把想要用的信息取出;字符串拼接操作
as :为字段或表取别名
#聚合函数 group function(一般与分组连用)
select post,max(salary) from emp group by post; #取不出组内的元素name, age..,只能取组名(分组依据)或用聚合函数
select post,min(salary) from emp group by post;
select post,avg(salary) from emp group by post;
select post,sum(salary) from emp group by post;
select post,count(id) from emp group by post;
#group_concat(分组之后用):把想要用的信息取出;字符串拼接操作
select post,group_concat(name) from emp group by post;
select post,group_concat(name,"_SB") from emp group by post;
select post,group_concat(name,": ",salary) from emp group by post;
select post,group_concat(salary) from emp group by post;
# 补充concat(不分组时用):字符串拼接操作
select concat("NAME: ",name) as 姓名,concat("SAL: ",salary) as 薪资 from emp;
# 补充as语法:为字段或表取别名
select name as 姓名,salary as 薪资 from emp; # as可省略
mysql> select emp.id,emp.name from emp as t1; # 报错
mysql> select t1.id,t1.name from emp as t1; # 同 mysql> select id,name from emp as t1;
三、having过滤 (一定要用组名(分组依据)或聚合函数)
having的语法格式与where一模一样,只不过having是在分组之后进行的进一步过滤
即where不能用聚合函数,而having是可以用聚合函数,这也是他们俩最大的区别
#统计各部门年龄在30岁以上的员工平均工资,并且保留平均工资大于10000的部门
select post,avg(salary) from emp where age >= 30 group by post having avg(salary) > 10000;
#强调:having必须在group by后面使用 (不认默认分组)
select * from emp having avg(salary) > 10000; #报错
四、distinct去重 (在having之后执行,和post,name等属于同一执行级别)
select distinct post,avg(salary) from emp where age >= 30 group by post having avg(salary) > 10000;
五、order by 排序 (默认升序)
select * from emp order by salary asc; #默认升序排
select * from emp order by salary desc; #降序排
select * from emp order by age desc,salary asc; #先按照age降序排,再按照薪资升序排
# 统计各部门年龄在10岁以上的员工平均工资,并且保留平均工资大于1000的部门,然后对平均工资进行排序
select post,avg(salary) from emp where age > 10 group by post having avg(salary) > 1000 order by avg(salary);
六、limit 限制显示条数;分页
select * from emp limit 3;
select * from emp order by salary desc limit 1; #显示薪资最高人的信息
select * from emp limit 0,5; #分页, 从0开始,取5条(1-5)
select * from emp limit 5,5; #分页, 从5开始,取5条(6-10)
七、正则表达式
select * from emp where name regexp '^jin.*(n|g)$'; #调正则;正则表达式通用
多表连接查询
关键字 on
在 多表查询时使用 后边条件 = 号两边全是主键
一、笛卡尔积
from emp,dep,dep2,...
二、内连接:把两张表有对应关系的记录连接成一张虚拟表
select * from emp inner join dep on emp.dep_id = dep.id;
#应用:
select * from emp,dep where emp.dep_id = dep.id and dep.name = "技术"; # 不推荐;不要用where做连表的活
select * from emp inner join dep on emp.dep_id = dep.id where dep.name = "技术"; #逻辑与上一条一致
三、左连接:在内连接的基础上,保留左边没有对应关系的记录
select * from emp left join dep on emp.dep_id = dep.id;
四、右连接:在内连接的基础上,保留右边没有对应关系的记录
select * from emp right join dep on emp.dep_id = dep.id;
五、全连接:在内连接的基础上,保留左、右边没有对应关系的记录
select * from emp left join dep on emp.dep_id = dep.id
union #去重
select * from emp right join dep on emp.dep_id = dep.id;
六、多表连接可以是单表不断地与虚拟表连接
#查找各部门最高工资
select t1.* from emp as t1
inner join
(select post,max(salary) as ms from emp group by post) as t2 #把虚拟表提成t2
on t1.post = t2.post
where t1.salary = t2.ms
;
select t1.* from emp as t1
inner join
(select post,max(salary) as ms from emp group by post) as t2
on t1.salary = t2.ms
;
子查询(一个问题一个问题解决)
把一个查询语句用括号括起来,当做另外一条查询语句的条件去用,称为子查询
select name from emp where dep_id = (select id from dep where name="技术"); #子查询
select emp.name from emp inner join dep on emp.dep_id = dep.id where dep.name="技术"; #链表
#查询平均年龄在25岁以上的部门名
select name from dep where id in (select dep_id from emp group by dep_id having avg(age) > 25); #子查询
select dep.name from emp inner join dep on emp.dep_id = dep.id group by dep.name having avg(age) > 25; #链表
#查看不足2人的部门名(子查询得到的是有人的部门id)
select * from emp where exists (select id from dep where id > 3); #exists用法,当()返回True时,外层查询语句将进行查询;当返回值为False时,外层查询语句不进行查询(empty set)
#查询每个部门最新入职的那位员工
select t1.id,t1.name,t1.post,t1.hire_date,t2.post,t2.max_date from emp as t1 inner join (select post,max(hire_date) as max_date from emp group by post) as t2 on t1.post = t2.post where t1.hire_date = t2.max_date;
权限管理
mysql 用户管理
MYSQL 是一个tcp 服务器 用于操作服务器上的文件数据,
接收用户端发送的指令, 接收指令时需要考虑安全问题
在mysql自带的mysql数据库中有4个表用于用户管理的
分别是: 优先级从高到低
user -> db -> tables_priv -> columns_priv
#1.创建用户的语句
create user 用户名@"主机地址" identified by "密码";
create user scote@"127.0.0.1" identified by "123";
此处的主机地址 不是服务器地址 而是表示 这个账户可以在那台电脑上登录
#2. 授权的语句
语法: grant [权限的名称 select insert.... | all ] on 数据库.表名 to 用户名@主机地址;
# 授予 scote 这个用户所有权限 在所有数据库所有表中
grant all on *.* to scote@"localhost"; 可以访问 所有库和表
grant all on day41.* to scote@"localhost"; 可以访问day41库的所有表
grant all on day41.stu to scote@"localhost"; 可以访问day41库的stu表
grant select(id,name),insert(id,name) on day41.stu to scote@"localhost";
# 仅能查看和添加 day41库的stu表中的 id和name字段
# 3.grant [权限的名称 select insert.... | all ] on 数据库.表名 to 用户名@主机地址 with grant option;
with grant option 这个用户可以将他有的权限授予别的账户
特点: 如果授权时 用户不存在 直接自动创建用户
grant all on mydb1.* to testDBA@"%" identified by "123";
# 4.删除权限
revoke 权限的名称 on 数据库.表名 from 用户名@"主机名" ;
revoke all on *.* from scote@"localhost";
update mysql.user set Grant_priv = "N" where user ="scote" and host = "localhost";
# *.刷新权限表
flush privileges;
# 5.删除用户
drop user 用户名@"主机地址";