SQL基本操作
基本操作:CRUD
将SQL的基本操作根据操作对象进行分类,分为库操作,表(字段)操作,数据操作
库操作
对数据库的增删改查
创建数据库
基本语法 Creat database 数据库名字 [库选项];
库选项:用来约束数据库,分为两项
字符集设定:charset/character set 具体字符集(数据存储的编码方式)GBK UTF8
校对集设定:collate 具体校对集(数据比较的规则)
-- 双中华线+空格:注释(单行),也可以使用#号
-- 创建数据库
create database mydatabase charset utf8;
数据库名字不可以使用关键字,或者保留字,如果非要使用,必须用``反引号括起来
创建中文数据库是可以的,但是数据库服务器必须得识别中文
-- 解决方案,告诉服务器当前中文字符集是什么
set names gbk;
create database 中国 charsetutf8;
当创建数据库的SQL语句执行之后,发生了什么
1,在数据库系统中,增加量对应的数据库信息
2,会在保存数据的文件夹下;Data目录,创建一个对应数据库名字的文件夹
查看数据库
1,查看所有数据库
show databases;
2,指定查看部分数据库:模糊查询
show databases like 'pattern';--pattern是匹配模式
%:匹配多个字符
_:匹配单个字符
show databases like 'info\_%';--
show databases like 'info_%';--相当于不加_
3,查看数据库的创建语句
show create database mydatabase;
更新数据库
数据库名字不可以修改,数据库的修改仅限:字符集和校对集(校对集以来字符集)
Alter database 数据库名字 【库选项】;
Charset/character set [=] 字符集
Cllate 校对集
-- 修改数据库infotest 的字符集
Alter database infotest charset GBK;
删除数据库
Drop database 数据库名;
drop database 中国;
表操作
表与字段是密不可分的,
新增数据表:
create table [if not exists] 表名(
字段名字数据类型,
字段名字数据类型,
最后一行不需要逗号
)[表选项];
if not exists:如果表名不存在,那么就创建;
表选项:控制表的表现:
字符集:charset/character set 具体字符集;-- 保证表中的数据存储的字符集
校对集collate 具体校对集
存储引擎:engine 具体的存储引擎(innodb和 myisam)
-- 创建表
create table if not exists student(
name varchar(10),
gender varchar(10),
number varchar(10),
age int
)charset utf8;
-- 创建失败,因为没有指定数据库
任何一个表的设计都必须指定数据库
方案一:显示的指定表所属的数据库
create table [if not exists] 数据库名.表名(
字段名字数据类型,
字段名字数据类型,
最后一行不需要逗号
)[表选项];
create table if not existsmydatabase.student(
name varchar(10),
gender varchar(10),
number varchar(10),
age int
)charset utf8;
方案二:隐士的指定表所属的数据库:先进入摸个数据库环境,然后这样创建的表自动归属到某个表
-- 进入数据库环境:use 数据库名字;
use mydatabase;
-- 创建表
create table class(
name varchar(10),
room varchar(10)
)charset utf8;
当创建数据表的SQL指令执行之后到底发生了什么
1,指定数据库下已经存在对应的表
2,在数据库对应的文件夹下,会残生对应表的结构文件(跟存储引擎有关系)
查看数据表
数据库能查看的方式表也能用
查看所有表
show tables;
查看部分表:模糊匹配
show tables like '%s';
查看表的创建语句
show create table 表名;
show create table student \g--\g等价于分号\G将查到的结构旋转就是都
查看表结构:查看表中的字段信息
Desc/describe/show columns from 表名
desc class;
describe class;
show columns from class;
修改数据表
表本身存在,还包含字段:表的修改包含两个部分,修改表本身,修改字段
修改表本身
表本身可以修改:表名和表选项
修改表名啊:rename 老表名 to 新表名
rename table student to my_student;
修改表选项:字符集,校对集,存储引擎
Alter table 表明 表选项 [=] 值;
alter table my_student charset = GBK;
修改字段
字段包含操作很多:新增,修改,重命名,删除
新增字段
alter table 表明 add[column] 字段名 数据类型 [列属性] 【位置】
位置:字段名可以存放的位置
first:第一个位置
after:在那个字段之后,默认最后一个位置
alter table my_student
add id int
first;
修改字段: 修改通常是修改属性或者数据类型
alter table 表名 modify 字段名 数据类型 【属性】【位置】
alter table my_student modify numberchar(10) after id;
重命名字段
alter table 表名 change 旧字段 新字段名 数据类型 【属性】 【位置】
alter table my_student change gender sexvarchar(10);
删除字段
alter table 表名 drop 字段名;
alter table my_student drop age;
删除虽简单,有风险;
删除数据表
drop table 表名1,表名2...,可以一次性删除多张表;
drop table class;
数据操作
新增数据
有两种方案:
方案一:给全表字段插入数据,不需要指定字段列表,要求数据的值出现的循序必须与表中设计的字段出现的循序一致,凡是非数值的数据,都得用引号(建议是单引号)包裹
insert into 表名 values(值列表)(值列表)...;
insert into my_studentvalues(1,'ithm0001','jim,'male'),(2,'ithm0002','hanmei','female');
方案2:给部分字段插入数据,需要选定字段:字段列表出现的循序和字段的顺序无关;但是值列表的顺序与选定的字段的顺序一致
insert into 表名 (字段列表) values(值列表)【(值列表)】;
insert into my_student (number,sex,name,id)values ('ithn0003','male','tom',3),('ithn0004','female','suxi',4);
查看数据
select*/字段列表 from 表名 【where 条件】;
查看所有数据
select * from my_student;
查看指定字段,指定条件数据
select id,number,sex,name from my_studentwhere id = 1;
更新数据
update 表名 set 字段 = 值 【where条件】;--建议都有where,要不就是更新全部
update my_student set sex = female where i= 1;
更新不一定会成功;如没有真正要更新的数据
删除数据:删除不可逆
delete from 表名 【where条件】
delete from my_student where sex = 'male';
中文数据问题
中文数据问题是字符集问题,计算机只是别二进制;
二进制与符号的对应关系就是字符集
查看服务器到底识别那些字符集
show character set;
-- 既然服务器识别那么多,总有一种是服务器默认的跟客户端打交道的字符集
查看服务器默认的对外处理的字符集
show variables like 'character_set%';
问题根源:客户端数据只能是GBK,而服务器认为是UTF8;
解决方案:改变服务器,默认的接收字符集为GBK
set character_set_client = gbk;
修改服务器给客户端的数据字符集为GBK
set character_set_results = GBK;
Set 变量 = 值;这种修改只是会话级别(当前客户端有效;关闭客户端失效)
设置服务器对客户端的字符集的认识,可以使用快捷方式:set names 字符集
set names GBK:====>character_set_client;character_set_results,charcter_set_connection;
connection 连接层,改了效率更高,不改也没关系;
校对集问题
校对集:数据比较的方式
校对集有三种表格式
_bin:binary,二进制比较,取出二进制位,取出二进制位,一位一位的比较,区分大小写
_cs :case sensitivi,大小写敏感,区分大小写
_ci:case insensitive,大小写不敏感,
查看数据库所支持的校对集:show collation;
校对集应用:只有数据需要比较的时候才需要校对集
必须在数据生成前修改,否则修改无效;
web 乱码问题
--增加主键
create table my_pri1(name varchar(20) notnull comment '姓名',number char(10) primary key comment '学号')charsetutf8;
-- 复合主键
create table my_pri2(number char(10)comment '学号:ithm+0000',course char(10) comment '课程代码:3901+0000',scoretinyint unsigned default 60 comment '成绩',primary key(number,course))charset utf8;
所谓的数据类型:就是对数据的统一的分类,从系统的角度出发为了能够使用统一的方式进行管理:更好的利用空间。
SQL中将数据类型分为了三大类:数值类型,字符串类型和时间日期类型
数值型
数值型数据:都是数值
系统将数值型分为整数型和 小数型
整数型
在SQL中因为更多要考虑如何节省磁盘空间,所以系统将整形划分为5类
Tinyint:迷你整型:使用字节存储,标识的状态最多为256种(常用)
Smallint 小整型,使用2个字节存储,表示的状态
Mediumint 中整型,使用3个字节存放数据
Int 标准整型;使用4个字节存储(常用)
BigInt:大整型,使用8个字节存放数据
有时候需要使用无符号数据:需要给数据类型限定:int unsigned;--表示无符号(从0开始)
浮点型
浮点型数据是一种精度型数据,因为超出指定范围后会丢失精度,理论分为两种精度
float和Double
float:单精度,占用四个字节存储数据,精度范围大概为7位左右
Double:双精度,占用8个字节存储数据,精度方位大概为15位左右
创建浮点数表:浮点的使用方式:直接float表示没有小数部分;float(M,D)M代表总长度,D带代表小数部分长度,整数部分长度为M-D;
插入数据时可以是直接小数,也可以是科学记数法
因系统进位导致整数部分超出系统规定的整数部分的长度,是被允许的,但是,管理员不能这样干
定点型
定点型:绝对的保证整数部分不会被四舍五入(不会丢失精度)小数部分有可能:理论小数部分也不会丢失精度
查看警告:show warnnings;
时间日期类型
Datatime:时间日期,格式是YYYY-mm-ddHH:ii:ss,表示的范围是从1000到9999年,有0值
0000-00-00 00:00:00
Data:日期,就是datatime中的data部分
Time:时间(段),指定的某个区间之间,-时间到-时间
timestamp:时间戳,并不只是时间戳,知识从1970年开始的YYYY-mm-ddHH:ii:ss格式与datatime完全一致
Year:年份,两种形式,year(2)和year(4):1901-2156
Time:时间段
网站是以PHP为实现的主要操作对象,PHP中有非常强大的时间日期函数 data 只需要一个时间戳就可以赚莞城任意类型的时间:以PHP为主的时候,都是数据库使用时间戳(整型)来存储时间
字符串类型
在SQL中怎么处理字符串类型:分成了6类:char varchar text,blob,enum,set
char类型,
定长字符串:磁盘(二维表)在定义结构的时候就已经确定了最终数据的存储长度
char(L):L代表length,可以存储的长度,单位为字符,最大的长度值可以为255
char(4):在UTF8环境下需要4*3=12个字节
变长字符串 :varchar:在分配空间的时候,按照最大的空间分配:但实际上最终用了多少是根据具体的数据来确定
Varchar(L):L表示字符长度 理论长度是65536个字符,但是会多出1到2个字节的实际长度,但是实际上如果长度超过了255,既不用定长,也不用变长,使用文本字符串text来存储数据
如何选择定长和变长字符串呢?
定长的磁盘空间比较浪费,但是效率高:如果数据基本上长度都一样
如:身份证,电话号码,手机号码等
变长的磁盘空间比较节省,但是效率高,如果数据长度不一,就使用变长
文本字符串
如果数据量非常大,通常说唱过255个字符就会使用文本字符串
文本字符串根据存储的数据的格式进行分类:text和blob
text:存储文字(二进制数据都是存储路径)
blob:存储二进制(通常不用)
枚举字符串
枚举:enum:事先将所有可能出现的结果都设计好,实际上存储的数据必须是规定好的数据中的一个
枚举的使用方式
定义:enum(可能出现的元素列表);//如(’男‘,’女‘,’不男不女‘,’保密‘);
作用一:规范数据存储格式,数据只能是规定数据中的一个
z作用二:节省空间
枚举原理:枚举在进行数据规范的时候(定义的时候),系统会自动建立一个数字与枚举元素的对应关系(关系放在日志文件中);然后再进行数据插入的时候,系统自动将字符转换成对应的数字存储,然后在提取的时候,系统自动将数值转换成对应的字符串显示
查询枚举表
select 字段名 + 0 ,字段名 from 表名
集合字符串
集合跟枚举很类似:实际存储的数值,而不是字符串(集合是多选)
集合使用方式:
定义:set(元素列表)
使用:可以使用元素列表中的元素(多个),使用逗号分隔
创建集合表
create table my_set(
hobby set('篮球','足球','乒乓球','羽毛球','排球','台球','网球','棒球')
)charset utf8;
插入数据:可以使用多个元素字符串组合,也可以直接插入数值
insert into my_set values('足球,台球,网球');
insert into my_set values(3);:
主键,唯一键,自增长,
主键:primary key 主要键,一张表只能有一个字段可以使用对应的键,用来唯一的约束该字段里面的数据,不能重复,这种称之为主键
一张表只能有一个主键
SQL操作中有多种方式给表增加主键:
方法一:在创建表的时候,直接在字段之后跟 primary key关键字
优点:非常直接;缺点:只能使用一个字段作为主键
方案二:在创建表的时候,在所有的字段之后,使用primary key(主键字段列表)来创建主键(如果有多个字段作为主键,可以是复合主键)
方案三:当表已经创建好之后,额外追加主键:可以通过修改表字段属性,也可以直接追加Alter table 表名 add primary key(字段列表);
前提:表中字段对应的数据本身是独立的(不重复)
主键对应的字段中的数据不允许重复:一旦重复,数据操作失败(增和改);
没有办法更新主键,主键必须先删除才能再增加
Alter table 表名 drop primary key;
在实际创建表的过程中,很少使用真实业务数据作为主键字段(业务主键,如:学号,课程号);大部分的死后是使用逻辑性的字段(字段没有业务含义,值是什么都没有关系),将这种字段称之为逻辑主键;
Create table my_student(
Id int primary key auto_increment comment’学号 逻辑主键 自增长,’
Name varchar(10) nut null commet ‘姓名’)charsetutf8;
自增长:当对应的字段,不给值,或者说给默认值,或者给null时,会自动的被系统触发
系统会自动的从当前字段记录的最大值自动+1操作,得到一个新的在不同的字段
自增长通常和主键搭配
自增长特点:auto_increment
1, 任何一个字段要做自增长 必须前提是本身是一个索引(key一栏有值)
2,
3, 自增长字段必须是数字(整形)
4, 一张表最多只能有一个自增长
当自增长被给定的值为null或者默认值的时候会触发
自增长如果对应的字段输入了值,那么自增长失效,但是下一次还是能够正确的自增长(从最大值+1);
如何确定下一次是什么自增长,可以通过查看建表语句;
自增长如果涉及到字段改变:必须先删除自增长,后增加(一张表只能由一个自增长)
修改当前自增长已经存在的:修改只能比当前已有的自增长的最大值大,不能小(小不生效)值
Alter table 表名 auto_increment = 值;
思考:为什么自增长是从1开始的,为什么每次都是自增一呢?
所有系统的变现(如字符集,校对集)都是由系统内部的变量控制的
查看自增长对应的变量:show variables like ‘auto_increment%’;
可以修改变量实现不同的效果:修改是对整个数据修改,而不是单张表(修改是会话级);
Alter table my_auto motifyid int primarykey -- 主键理论是单独存在的
Alter table my_auto modify id int;
一张表汪汪有很多字段需要具有唯一性,数据不能重复,但是一张表中只能有一个主键:唯一键(unique key)就可以解决表中有多个字段需要唯一性约束的问题
唯一键本质上与主键差不多:唯一键默认的允许为空,而且可以多个为空(空字段不参与唯一性比较)
基本上与增加主键差不多:有三种方法
方案一:在创建表的时候,字段后面直接跟unique 或者 unique key
方案2:在所有的字段之后增加unique key(字段列表) -- 复合唯一键
为什么也是PRI呢?这是错觉:因为唯一键这时不能为空:而主键也是不能为空,也是自增长,所以系统以为这就是主键
方案三:追加唯一键
唯一键与主键本质不同唯一键允许默认允许为空,而且是多个为空
更新唯一键:先删除后新增(唯一键可以有多个:可以不删除)
Alter table 表名 drop index 索引名 – 默认的索引名就是字段名
几乎所有的索引都是建立在字段之上的
索引:系统根据某种算法,将已有的数据(未来可能新增的数据)单独建立一个文件:文件能够实现快速的匹配数据,并且能够快速的找到对应表中的记录
索引的意义:
1,提升查询数据的效率
2,约束数据的有效性(唯一性等)
增加索引的前提:索引本身会产生索引文件,有时候可能比数据文件大,会非常耗费磁盘空间,
如果某个字段徐娅作为查询的条件经常使用,那么可以使用索引(一定会想办法增加);
如果某个字段需要进行数据的有效性约束,也可能使用索引(主键,唯一键)
MySQL 中提供了多种索引
1,住建座因:primary key
2,唯一索引:unique key
3,全文索引:fulltext index
4,普通索引:index
全文索引:针对文章内部的关键字进行索引
最大的问题:在于如何确定关键字
将实体与实体的关系,反应到最终数据库表的设计上来:将关系分为三种:一对一,一对多
多对多
所有的关系都是指表与表之间的关系
一对一:一张表的一条记录一定只能与另外一张表的一条记录进行对应;反之亦然
多对一:可以在另外一张表里加上这张表的主键
多对多:添加一张中间表,中间表分别和两个表形成一对多的关系
范式:normal format 是一种离散数学中的知识,是为了解决一种数据的存储与优化的问题
保证数据的存储之后,凡是能够通过关系寻找出来的数据,坚决不再重复存储,终极目标是为了减少数据的冗余。
范式:是一种分层结构的规范,分为六层:每一层都比上一层更加严格:若要满足下一层凡是,前提是满足上一层范式
六层范式:1NF.2NF,3NF,4NF,5NF,6NF
Mysql属于关系型数据库:有空间浪费,也是致力于解决存储空间问题,
第一范式:在设计表存储数据的时候,如果表中设计的字段存储的数据,在取出来使用之前
还需要额外的处理(拆分)那么说表的设计不满足第一范式:第一范式要求字段的数据具有原子性:不可再分
解决方案:将可在分的字段拆分
第二范式:在数据表设计的过程中,如果有复合主键(多字段主键),切表中有字段并不是由整个主键来确定,而是依赖主键中的某个字段(主键的部分);存在字段依赖主键部分的问题称之为部分依赖;第二凡是就是为了解决表设计不允许出现部分依赖
解决方案一:可以将有部分依赖的字段单独成表,
解决方案二:取消复合主键使用逻辑主键
要满足第三范式,必须满足第二范式
第三范式:理论上讲,应该一张表中的所有字段都应该直接依赖主键(逻辑主键,代表业务主键),如果表设计中存在一个字段,并不直接依赖主键,而是通过某个非主键字段依赖,最终实现依赖主键:把这种不是直接依赖主键,而是依赖非主键字段的依赖关系称之为传递依赖,第三范式就是解决传递依赖的问题
解决方案:将存在传递依赖的字段,以及依赖的字段本身单独取出,形成一个单独的表,然后在需要对应的信息的时候,使用对应的实体表的主键加进来
有时候,在设计表的时候,如果一张表中有几个字段是需要从另外的表中去获取信息,但是效率低:会刻意的在某些表中,不去保存另外表的主键(逻辑主键)而是直接保存想要的数据信息,这样一来就可以提升查询效率但是会导致数据冗余
逆规范化:磁盘的利用率和效率的对抗,
数据操作:增删改查
基本语法
Insert into 表名 【(字段列表)】values (值列表)
在数据插入的时候,假设主键对应的值已经存在,插入一定会失败!
当主键存在冲突的时候(duplicate key)可以选择选择性的进行处理,:更新和替换
主键冲突:更新操作
Insert into 表名【(字段列表:包含主键)】 values (值列表) on duplicate keyupdata
主键冲突:替换
Replace into 表名 【(字段列表:包含主键)】 values(值列表);
蠕虫复制:从已有的数据中去获取数据,然后将数据有进行新增操作,数据成倍的增加
表创建高级操作:下哦那个已有表创建新表(复制表结构)
Create table表名 like数据库.表名;-- 如果在一个数据库就不需要(数据库.)了
蠕虫复制:先查出数据,然后将查出的数据新增一遍
Insert into表名【(字段列表)】 select */字段列表 from 数据表名;
蠕虫复制的意义:
1, 从已有表拷贝数据到新表中
2, 可以迅速的让表中的数据膨胀到一定的数量级:测试表的压力以及效率
基本语法
Update 表名 set 字段 = 值 【where条件】;
高级
Update 表名 set 字段 = 值【where条件】【limit限制更新数量】;
与更新类似:可以通过limit限制数量
Delete from 表名 【where条件】【limit数量】;
删除:如果表中存在自增长,那么当删除之后,自增长不会还原
思路:数据的删除是不会改变表结构,只能删除后重建
Truncate 表名;-- 先删除改变,在重建表;
基本语法
Select 字段列表/* from 表名 【where条件】;
完整语法
Select【select选项】 字段列表【字段别名】/*from 数据源【where条件子句】【groupby子句】【having 子句】【order by 子句】【limit 子句】
select选项:select对查出来的结果的处理方式
all:默认的,保留所有的结果
distinct:去重,查出来的结果,将重复的结果去除
字段别名:当数据进行查询出来的时候,有时候名字并不一定就能满足需(多表查询的时候会有同名字段),需要对字段名进行重命名:别名
语法
字段名【as】别名
数据源:数据的来源,关系型数据库的来源都是数据表,本质上只要保证数据类似二维表最终都可以作为数据源
数据源分为多种:但表数据源,多表数据源,查询语句
单表数据源:select * from 表名
多表数据源:select * from 表名1,表名2,…;
多表数据源
从一张表中取出一条记录,去另外一张表中匹配所有记录,而且全部保留(记录数和字段数)
将这种结果称为:笛卡儿积(交叉连接)笛卡儿积没什么乱用,尽量避免
子查询,数据的来源是一条查询语句(查询语句的结果是二维表)
Select * from (select 语句)as 表名;
Where子句:用来判断数据,筛选数据
Where子句返回结果:0或1,0代表false,1代表true
比较判断条件:运算符:>,<,>=,<=,!=,<>,=,like,beturnand,in/not in
逻辑运算符:&&(and),||(or),!(not)
Where是直接一个从磁盘获取数据的时候就开始判断数据,从磁盘取出一条记录,开始进行where判断,判断的结果如果成立保存到内存,如果不成立直接放弃
增加值:rand取得一个0~1之间的随机数 floor向下取整
Update my_studnet setage=floor(rand()*20+20);
条件查询1:要求找出学生id为1或者3 或者5的学生
第一种查询方式是条件查询,第二种方式为落在集合中
Between 本身是闭区间;between左边的值必须小于等于右边的值;
Select * from 表名 where 1;1 代表true,where返回true或false
Group by分组的意思,根据某个字段进行分组(相同的放一组,不同的分到不同的组)
基本语法:group by 字段名;、
分组的意义:是为了统计数据(按组统计:按分组字段进行统计)
SQL提供了一系列的统计函数
Count() 统计分组后的记录数:每一组有多少记录
Max():统计最大值
Min()统计最小值
Avg():统计平均值
Sum():统计和
Count函数:里面可以使用两种参数;*代表统计记录,字段名代表统计对应的字段(null不统计)
分组会自动排序:根据分组字段默认升序
Group by 字段 [asc/desc];-- 对分组的结果然后合并然后合并之后的整个结果进行排序
Select 字段名1,字段名2,count(*)from 表名 group by 字段名1,字段名2;
与一个函数:可以对分组的结果中的某个字段进行字符串连接(保留改组所有的某个字段)
Group_concat(字段);
回溯统计:with rollup:任何一个分组后的结果,都会有一个小组,最后都需要向上级分组进行回报统计:根据当前分组的字段,这就是回溯统计:回溯统计的时候会将分组字段置空
Having子句与where子句一样,做条件判断
Where是针对磁盘数据进行判断,但是磁盘进入内存之后,会进行分组操作,分组结果需要having来处理
Having能做where几乎能做的所有事情,但是where不能做having能做的很多事情
1, 分组统计的结果或者说统计函数都只有having能够使用
2, having能够使用字段别名:where是从磁盘取数据,而名字只能是字段名,字段别名是在字段进入到内存后才会产生,
Order by,排序,根据某个字段进行升序或者降序,依赖校对集,
基本语法
Order by 字段名 [asc/desc];-- asc 是升序(默认)
排序可以进行多字段排序:先根据某个字段进行排序,然后排序好的内部,再按照某个数据进行排序;
Limit 子句是一种限制结构的语句
Limit有两种使用方式
方案1:只用来限制数量
方案2 :限制起始位置,限制数量:limit起始位置,长度;从指定的数据开始往后面找几个数据
方案2 :主要用来实现数据的分页:为用户节省时间,提交服务器的相应效率,减少资源的浪费
对于用户来讲:可以点击的分页按钮1,2,3,4如淘宝的分页
对于服务器来讲:根据用户选择的页码来获取不同的数据:limit offset,length;
Length:每页显示的数据量,基本不变
Offset:offest = (页码-1)*每页显示量
需求:查询出所有学生,而且要显示出学生所在班级的信息
链接查询:将多张表,进行记录的连接,按照某个指定的条件进行数据的拼接
最终结果:记录数有可能变化,有可能不变化,字段数一定会增加(两张表拼接)
意义:在用户查看数据的时候,需要现实的数据来自多张表
链接查询关键字:join 使用方式:左表 join 右表
左表:关键字左边的表
右表:关键字右边的表
SQL中奖连接查询分为四类:内连接,外连接,自然连接和交叉连接
交叉连接:cross join 从一张表中循环去除每一条记录,每条记录都去另外一张表进行匹配;匹配一定成功(没有条件匹配)而链接本身字段就会增加(保留),最终形成的结果叫做:笛卡儿积
基本语法:左表 cross join 右表 : ======from 左表,右表
笛卡儿积没有意义:应该尽量避免(交叉连接没有用)
交叉连接存在价值:保证连接这种结构的完整性
内链接:[inner] join ,从左表中取出每一条记录,去右表中去匹配:盘匹配中必须是某个条件在左表中与右表中相同最终才会保留结果,否则不保留
基本语法
坐标[inner] join 右表 on 左表.字段=右表.字段 on表示链接条件:条件字段就是代表相同的业务含义(如my_student.c_id和my_class.id)
select * from my_student inner joinmy_class on my_student.c_id=my_class.id;
相当于select * from my_student inner join my_class on c_id=my_class.id;
字段别名及表别名的使用:在查询数据的时候,不同表有同名字段,这个时候需要加上表名
内链接可以没有条件,没有条件又编程笛卡儿积
可以用where代替on:通常不用where,on效率更高
外连接:outer join,以某张表为主,去除里面所有记录,然后每条与另外一张表进行连接
不管能不能匹配上条件,最终都会保留有,能匹配,正确保留,不能匹配,其他表的字段置空
Null
外连接分为两种:是以某张表为主,有主表
Left join:左外连接(左连接),以左表为主
Right join:右外连接(有链接),以右表为主
基本语法:左表 left/right join 右表 on 坐标.字段 = 右表.字段
左表为主表:最终记录数至少不少于左表已有的记录数
右连接
以右表为主表
虽然左连接和右连接有主表擦哈哟,但是现实的结果:左表的数据在左边,右表的数据在右边
左表和右表可以互转
自然连接:natural join,自然连接就是自动匹配连接条件:系统以字段名字作为匹配模式
(同名字段就作为条件,多个同名字段都作为条件)
自然连接:可以分为自然内连接,和自然外连接
自然内连接:坐标 natural join右表;
自然连接自动使用同名字段作为链接条件:连接之后会合并同名字段
自然外连接
左表 natural left/right join 右表
其实:内连接和外连接都可以模拟自然连接:使用同名字段,合并字段
左表:left/right/inner join 右表 using(字段名);-- 使用同名字段作为链接条件:自动合并条件
外键 : foreign key 外面的键(键不在自己表中):如果一张表中有一个字段(非主键)指向另外的一张表的主键,那么称该字段为外键
一张表可以有多个外键
外键可以在创建表的时候或者创建表之后增加(但是要考虑数据问题)
创建表的时候增加外键,再所有的表的字段之后,增加foreign key(外键字段)reference 外部表(主键字段)
在新增表之后增加外键,修改表结构
Alter table 表名 add [constraint 外键名字]foreignkey(外键字段) references 父表(主键字段);
外键不可修改,先删除后新增
删除外键语法
Alter table 表名 drop foreign key 外键名;
一张表中可以有多个外键,但是名字不能相同;
外键作用有两点:一个对父表,一个对字表(外键字表所在的表
对字表约束:字表数据进行写操作的时候,如果对应的外键字段在父表找不到对应的字段,操作失败
)
对父表约束:父表数据进行写操作(删和改:都涉及到主键本身)如果对应的主键在子表中已经被数据所引用,那么就不允许操作
1, 外间要存在:首先必须保证表的存储引擎是innodb(默认的存储引擎),如果不是innodb存储引擎,外键可以创建成功,但是没有约束效果
2, 外间字段的字段类型(列类型)必须与父表的主键类型完全一致,
3, 一张表中的外键名字不能重复,
4, 增加外键的字段(数据已经存在),必须保证数据与父表之间要求对应
所谓外键约束:就是指外键的作用
之前所讲的外键作用:是默认的作用;其实可以通过对外键的需求,进行定制操作
外键约束有三种约束模式:都是针对父表的约束
District:严格模式(默认的),父表不能删除或者更新一个已经被字表数据引用的记录
Cascade:级联模式:父表的操作,对应字表关联的数据也跟着被删除
Set null:置空模式:父表的操作之后,子表对应的数据(外键字段)被置空
通常一个合理的做法(约束模式)删除的时候子表置空,更新的时候子表级联操作
指定模式的语法
Foreign key(外键子段) references 父表(主键字段) ondelete 模式 update 模式
级联操作
删除模式
删除置空的前提条件,外间字段允许为空,(如果不满足条件外间无法创建)
外键虽然很强大,能够进行各种约束:外键降低了对数据的可控性:通常在实际开发中,很少使用外间来处理
联合查询:将多次查询(多条select语句)在记录上进行拼接(字段不会增加)
多条select 语句构成:每一条select语句获取的字段数必须严格一致(但是字段类型无关)
Select 语句 1
Union[union选项]
Select 语句 2….
Union 与select选项一样有两个
All:保留所有(不敢重复)
Distinct:去重(整个重复):默认的
联合查询的意义分为两种:
1, 查询同一张表,但是需求不同:查询学生信息,但是需求不同
2, 多表查询:多张表的结构一样,保存的数据(结构)相同
在联合查询中,必须将order by子句用括号括起来
若要order by生效,必须搭配limit;limit使用限定的最大数
子查询:sub query,查询是在某个子查询结果之上进行的(一条select语句内部包含了另外一条select语句)
子查询有两种分类:按位置分类,按结果查询
From子查询:子查询跟在from之后
Where子查询:子查询出现在where条件中
Exists子查询:子查询出现在exists里面
按结果分类:根据子查询得到的数据进行分类(理论上讲任何一个查询得到的结果都可以理解为二维表)
标量子查询:子查询得到的结果是一行一列
列子查询:子查询得到的结果是一列多行
行子查询:子查询得到的结果是多列一行(多行多列)
上面几个出现的位置都是在where之后
表子查询:子查询得到的结果是多行多列(出现的位置是在from之后)
需求:知道班级名字为PHP0710,想获取该班的所有学生信息
1, 确定数据源,获取所有学生
Select * from my_student where c_id=?
2, 获取班级ID:可以通过班级名字确定
Select id from MY-class where c_name = ‘PHP0710’;
需求:查询所有在读班级的学生(班级表中存在的班级)
1, 确定数据源:学生
Select * from my_student where c_id in(?);
2, 确定有效班级的ID
Select id from my_class;
列子查询返回的结果会比较多:一列多行,需要使用in作为条件匹配:其实mysql中还有几个类似的条件:all ,some,any
=Any =====in—其中一个即可
Any=====some;他们两个一样,
=All=======为全部
否定结果
行子查询:返回的结果可以使多行多列(一行多列)
需求:要求查出所有学生中年龄最大,学生最高
1, 确定数据源:
Select * from my _student where age=?and height=?;
2, 确定最大的年龄和最高的身高
Select max(age) from my_student
表子查询:子查询返回的结果是多行多列的二维表:子查询返回的结果当作二维表来使用
需求:找出每个班中最高的学生
Exists:是否存在,exists子查询就是用来判断某些条件是否满足(跨表),exists是接在where之后:exists返回0或1
需求:查询所有学生:前提是班级存在
1, 确定数据源
Select * from my_student where ?;
2,
视图 view 是一种有结构(有行有列)但是没结果(结构中不真实存放数据)的虚拟表,虚拟表的结构来源不是自己定义,而是从对应的基表中产生(视图的数据来源)
基本语法
Create view 试图名字 as select语句;-- select语句可以是普通查询,链接查询,联合查询,子查询
创建单表视图:基表只有一个
创建多表视图:基表至少有两个
查看视图:查看视图的结构
视图是一张虚拟表:表,表的所有查看方式适用于查看视图
使用试图主要是为了查询
视图的执行:其实本质就是执行封装的select语句
视图本身不可修改,但是视图的来源是可以修改的,试图修改其实就是修改视图的来源语句(select 语句)
Alter view 视图名字 as 新的select语句;
1, 视图可以节省SQL语句:将一条复杂的查询语句使用视图进行保存:以后可以直接对视图进行操作
2, 数据安全:视图操作是主要针对查询的,如果对视图结构进行处理(删除),不会影响基表(相对安全)
3, 视图往往是在大项目中使用,而且是多系统使用:可以对外提供有用的数据,但是隐藏关键(无用)的数据:数据安全
4, 视图可以对外提供友好型 ,不同的视图提供不同的数据,对外好像专门设计
5, 视图可以更好(容易)地权限控制
视图是的确可以进行数据操作的:但是有很多限制
将数据直接在视图上进行操作
数据新增:直接对视图进行数据新增
1, 多表视图不能新增数据
2, 可以向单表视图插入数据:但是属兔中包含的字段必须有基表中所有不能为空(或者没有默认值)字段
3, 可以向基表中插入数据
多表视图不能删除数
单表视图可以删除数据
理论上不管单表视图,还是多表视图,都可以修改
更新限制:with check option 如果对视图在新增的时候,先顶了某个字段有限制:那么在对视图进行数据更新操作是,系统会进行验证:要保证更新之后,数据还是能被视图查出来
视图算法:系统对视图以及外部查询视图的select语句的一种解析方式
视图算法分为三种
Undefined:未定义(默认的):这不是一种实际的使用算法,是一种推卸责任的算法:告诉系统:视图没有定义算法,系统自己看着办
Temptable临时表算法:系统应该先执行视图的select语句,后执行外部查询语句
Merge:合并算法:系统应该先将视图对应的select语句与外部查询视图的select语句进行合并,然后执行(效率高);
算法指定:在创建视图时
Create algorithm=指定算法 view 视图名字 as select 语句
视图算法比较:如果视图的select语句中会包含一个查询子句(五子句);而且很有可能循序比外部的查询语句靠后,一定是用算法temptable,其他情况下不要指定(默认即可)
备份:将当前已有的数据或记录保留
还原:将已经保留的数据恢复到对应的表中
为什么要做备份与还原:
1, 防止数据丢失:误操作,被盗
2, 保护数据记录
数据还原的方式:直接备份数据表,单表数据备份,SQL备份,增量备份
不需要通过SQL来备份:直接进入数据库文件夹复制对应的表结构以及数据文件,以后还原的时候,直接将备份的内容放回原处
数据表备份有前提条件:根据不同的存储殷勤有不同的区别
存储殷勤:mysql进行数据存储的方式:主要有两种:innodb和myisam(免费)
对比myisam和innodb:数据存储方式
Innodb:只有表结构,数据全部存储到ibdata1中
Myisam :表,数据和索引全部单独分开存储
这种文件备份通过常用于myisam存储引擎:直接复制三个文件即可
然后放到对应的数据库下即可以使用
每次只能备份一张表:只能备份数据,表结构不能备份
通常的使用:将表中的数据进行导出到文件
备份:从表中选出一部分数据保存到外部的文件中(outfile)
Select*/字段列表 into outfile 文件所在路径from 数据源—前提外部文件不存在
高级备份:自己指定字段和行的处理方式
Select*/字段列表 intooutfile 文件所在路径fields 字段处理lines 行处理from 数据源
Fileds:字段处理
Enclosedby:字段是用什么内容包裹:默认是‘’,空字符串
Terminated by :字段以什么结束,默认是”\t“tab键
Escaped by :特殊符号用什么方式处理,默认是‘\\’,使用反斜杠转义
Lines:行处理
Starting by:每行以什么开始,默认是““空字符串
terminated by:每行以什么结束,默认是“\r\n“换行符
数据还原:将一个在外部保存的数据重新恢复到表中(如果表结构不存在,那么sorry)
load data infile 文件所在路径 into 表名[(字段列表)] field 字段处理 lines 行处理;---
怎么备份的怎么还原
备份的是SQL语句:系统会对表以及表结构以及数据进行处理变成对应的SQL语句进行备份:还原的时候只要进行SQL指令集客(主要针对表结构)
备份:mysql没有提供备份指令;需要利用mysql提供的软件:mysqldump.exe
mysqldump.exe也是一种客户端,需要操作服务器:必须连接认证
mysqldump/mysqldump.exe –hPup 数据库名字[数据表名字1 [数据库名字2…]]>外部文件目录(建议使用.sql结尾)
单表备份
整库备份
SQL还原数据:两种方式
方案1:使用mysql.exe客户端
mysql.exe/mysql –hPhp 数据库名字 < 备份文件目录
方案2:使用SQL指令还原
souse 备份文件所在路径
SQL备份优缺点
1, 优点:可以备份结构
2, 缺点:会浪费空间(额外的增加SQL指令)
不是针对数据或者SQL指令进行备份:针对mysql服务器的日志文件进行备份
增量备份:指定时间段开始进行备份,备份数据不会备份,而且所有的操作都会备份(大项目都用增量备份)
前提:存储引擎为:innodb引擎。
事务:transaction一系列要发生的连续的操作
事务安全:一种保护连续操作同时满足(实现)的一种机制
事务安全的意义:保证数据操作的完整性
事务操作分为两种:自动事务(默认),手动事务;
手动操作:操作流程
1, 开启事务:告诉系统一下所有的操作(写)不要直接写入到数据表,先放到事务日志
start transaction:开启事务
2, 进行事务操作:一系列操作
a) 李四账户减少
以另外的视角来看,钱并没有减少(再开一个命令行)
b) 张三账户增加
c)关闭事务:选择性的将日志文件中操作的结果保存到数据表(同步)或者说直接清空事务日志(原来操作直接清空)
a)提交事务:同步数据表(操作成功):commit
b)回滚事务:直接清空日志表(操作失败)rollback
事务开启之后,所有的操作都会临时保存到事务日志,事务日志只有在得到commit命令之后才会同步到数据表中,其他任何时候都会rollback;
回滚点:在某个成功的操作完成之后,后续的操作有可能成功,有可能失败,但是不管成功还是失败,前面操作都已经成功:可以在当前成功的位置,设置一个点:可以供后续失败操作返回到该位置,而不是返回所有操作,这个点称之为回滚点
设置回滚点:savepoint 回滚点名字
回到回滚点:rollback to 回滚点名字
事务只是针对数据的操作;
在mysql中:默认的都是自动事务处理,用户操作完会立即同步到数据表中
自动事务:系统通过autocommit变量控制
show variables like ‘autocommit’;
关闭自动提交:set autocommit = 0;
再次直接写操作
自动关闭之后,需要手动提交回滚
通常都会使用自动提交
事务四大特性:ASID
A:atomic原子性:事务的整个操作是一个整体,不可分割,妖魔全部成功,要么全部失败
C:consistency:一致性:事务操作的前后,数据表中的数据没有变化
I:isolation,隔离性,事务操作前后的两个事务操作互不影响
D:durability:持久性:数据一旦提交,不可改变,永久的改变数据表数据
锁机制:innodb默认是行锁,但是如果在事务操作的过程中,没有使用索引,那么系统会自动全表检索数据,自动升级为表锁
行锁:只有当前行被锁住,别的用户不能操作
表锁:整张表被锁住,别的用户都不能操作
变量分为两种:系统变量,自定义变量
系统定义好的变量:大部分时候用户根本不需要使用那个系统变量:系统变量是用来控制服务器的表现的:
show variables
查看具体变量值:任何一个有数据返回的内容都用select 查看
select @@变量名
修改系统变量:两种方式:会话级和全局级
会话级:临时修改,当前修改,当前客户端,当前有效
set @@变量名 = 值
set 变量名 = 值
全局级:一次修改,永久有效(对所有客户端都生效)
set global 变量名 = 值
如果对方(其他)客户端当前已连接上服务器,那么当次修改无效,要推出重新登陆才会生效
系统为了区分系统变量,会顶用户必须使用一个@符号
set @自定义变量名 = 值
自定义变量类似系统变量查看
select @变量名
在mysql中,‘=’会默认当作比较符号处理(很多地方),为了区分比较和赋值的概念;
重新定义了一个赋值符号;“:=”
mysql允许从数据表中获取数据,然后赋值给变量:两种方式
方案1:边赋值,变查看结果
select@变量名 := 字段名 from 数据源 从字段中取值赋值给变量名 = 必须用 := 否则=变成比较符号
通常不用这一种方案
方案2:只有赋值,不看结果,要求很严格:数据记录最多允许获取一条:mysql不支持数组
select 字段列表 from 表名 into 变量列表;
所有自定义的变量都是会话级别
所有自定义变量不区分数据库(用户级别)
需求:有两张表,一张订单表,一张商品表,没生成一个订单,意味着商品的库存要减少
触发器:trigger,事先为某张表绑定好一段代码,当表中的某些内容发生改变的时候(增删改)系统会自动触发代码执行,
触发器:事件类型,触发时间,触发对象,
事件类型:增删改,三种类型insert delete update
触发时间:前,后before 和 after
触发对象:表中的每一条记录(行)
一张表中只能拥有一种触发时间的一种类型的触发器:最多一张表能有6个触发器
在mysql高级结构中没有大中括号,用对应的字符符号代替
触发器基本语法
--- 临时修改语句结束符
delimiter 自定义符号后续代码中只有碰到自定义符号才算结束
create trigger 触发器名字 触发时间 事件类型 on 表名 for eachrow
begin 代表左大括号 开始
--- 里面就是触发器内容:每行内容都必须使用语句结束符:分号
end 代表右大括号:结束
---- 语句结束符
自定义符号
--- 将临时修改修正回来
delimiter
查看所有触发器或者模糊匹配
show trigger [like pattern]
show create trigger 触发器名字
所有的触发器都会保存到一张表中:information_schema。triggers表中
触发器:不需要手动调用,而是当某种情况发生时会自动触发
触发器不能修改,只能先删除后新增
drop trigger 触发器名字
触发器记录:不管触发器是否触发了,只要当某种操作准备执行,系统就会将当前要操作的记录的当前状态和即将执行之后新的状态给分别保留下来,供触发器使用:其中:要操作当前状态保存到old中,操作之后的可能形态保存到new中
old 代表就记录,new代表新纪录
删除的时候是没有new的,插入的时候没有old
old和new都是代表记录本身:任何记录都有字段和名字
使用方式:old.字段名/new.字段名(代表假设发生之后的结果)
查看触发器效果
如果触发器内部只有一条要执行的SQL指令,可以省略大括号(begin和end)
create trigger 触发器名字 触发时间 事件类型 on 表名 for eachrow
一条SQL 指令
触发器:可以很好的协调表内部的数据处理顺序和关系,但是从PHP角度出发触发器会增加数据库维护的难度,所以较少使用触发器
代码执行结构:顺序结构,分支结构和循环结构
分支结构 :实现准备多个代码块,按照条件选择性执行代码
在mysql中只有if分支
基本语法
if 条件判断 then
--- 满足条件要执行的代码
else
--- 不满足条件要执行的代码
end if;
触发器结合if分支:判断商品库存是否足够;
循环结构:某段代码在指定条件执行重复执行
while 循环(没有for循环)
语法结构:
while 条件判断 do
--- 满足条件要执行的代码
--- 变更循环条件
end while
循环控制:在循环内部进行循环判断和控制
mysql中没有对应的关键字 continue等 但是有替代品
iterate 迭代:类似continue 后面的代码不执行,玄幻重新来过
leave:离开,类似break整个循环条件
使用方式:iterate / leave 循环名字
--- 定义循环名字
循环名字:while 条件判断 do
--- 循环体
-- 循环控制
leave / iterate 循环名字
end while
函数:讲一段代码块封装到一个结构中,在需要执行代码块的时候调用即可(提高代码复用性)
函数分为两类:系统函数和自定义函数
系统定义好的函数,直接调用
任何函数都有返回值,因此函数调用通过select调用
mysql中,字符串的基本操作单位(字符)
substring 截取字符串
char_length:字符长度
length:字节长度
instr:判断字符串是否在某个字符串中存在,存在返回位置,失败返回0;
lpad:左填充,将字符串按照某个指定的填充方式,填充到指定长度,字符单位
insert:替换找到目标位置 ,指定长度的字符串,替换成目标字符串
strcmp:compare 字符串比较 大 等 小
函数要素:函数名,参数列表(形参和实参)返回值函数体(作用域)
创建于法
create function 函数名([形参列表]) returns 数据类型(规定要返回的数据类型)
begin (只有一条语句可以省略)
--- 函数体
--- 返回值 return 类型(指定数据类型)
end(只有一条语句可以省略)
自定义函数与系统函数的调用方式是一样的:select 函数名([实参列表])
查看所有函数:show function status [like‘ppattern’];
查看函数的创建语句:show create function 函数名
只能先删除后新增,不能修改
drop function 函数名
参数分为两种:定义的时候是形参,调用时是实参(食餐可以是数值也可以是变量)
形参:要求必须指定数据类型
function 函数 (形参名字 字段类型) returns 数据类型
在函数内部使用@定义的变量,在外部也可以使用
mysql中的作用域与js中的作用域完全一样在那个
全局变量可以在任何地方使用;局部变量只能在函数内部使用
全局变量:使用set关键字定义,使用@符号标志
局部变量:使用declare关键字声明,没有@符号:所有局部变量的声明,必须在函数体开始之前
存储过程简称过程procedure,是一种用来处理数据的方式
存储过程是一种没有返回值的函数。
create procedure 过程名字([参数列表])
begin
--- 过程体
end
函数的查看方式完全适用于过程:关键字换成procedure
查看所有过程:show procedure status [like “pattern”];
查看创建语句
show create procedure 过程名
过程没有返回值:select是不能访问的
过程有一个专门的调用关键字:call
drop procedure 过程名
函数参数需要数据类型指定:过程比函数更严格
过程还有自己的类型限定:三种类型
In:数据只能是从外部传入内部使用(值传递:也可以是数值可以使变量)
out:只允许过程内部使用(不用外部数据),给外部使用的(引用传递:外部的数据会被先清空才会进入内部);只能是变量
inout:外部可以在内部使用,内部修改也可以给外部使用:典型的引用传递:只能穿变量
基本使用:
create procedure 过程名(in 形参名字 数据类型,out 形参名字 数据类型,inout 形参类型 数据类型)
调用:out和inout类型的必须传入变量不能是数值
正确调用:传入变量
-- 设置变量
set @int_1 = 1;
set @int_2 = 2;
set @int_3 = 3;
select @int_1,@int_2,@int_3;
call pro1(@int_1,@int_2,@int_3);
select @int_1,@int_2,@int_3;
存储过程对于变量的操作(返回)是滞后的:是在存储过程调用结束的时候,才会重新将内部修改的值赋值给外部传入的全局变量
测试数据:局部变量与全局变量无关
最后:在存储过程调用结束之后,系统会将局部变量重复返回给全局变量(out和inout)