一、SQL概述
- 什么是SQL?
SQL(Structured Query Language)是“结构化查询语言”,它是对关系型数据库的操作语言。它可以应用到所有关系型数据库中,例如:MySQL Oracle SQL Server等。SQL标准有:
虽然SQL可以用在所有关系型数据库中,但很多数据库还都有标准之后的一些语法,我们可以称之为“方言”。例如MySQL中的LIMIT语句就是MySQL独有的方言,其它数据库都不支持!当然,Oracle或SQL Server都有自己的方言。 - SQL语法要求
- SQL语句可以单行或多行书写,以分号结尾;
- 可以用空格和缩进来增强语句的可读性;
- 关键字不区别大小写,建议使用大写;
二、分类
- DDL(Data Definition Language):数据定义语言,用于库和表的创建,修改,删除;
- DML(Data Manipulation Language):数据操作语言,用于添加,删除,修改数据库数据,
并检查数据完整性 - DCL(Data Control Language):数据控制语言,用来定义访问权限和安全级别;
- DQL(Data Query Language):数据查询语言,用来查询数据
-
DDL
- 基本操作
- 查看用户名和数据库版本
select user().version();
- 查看数据库名称
show databases; # 查看所有数据库 show databases like 'c%' #查看以c开头的数据库名称
- 切换数据库
use 数据库名称
- 查看数据库中所有的表
show tables # 查看当前数据库所有的表 show tables from 数据库名称 # 查看指定数据库下所有的表
- 查看当前所在的数据库
select database();
- 查看用户名和数据库版本
- 操作数据库
- 创建数据库
create database [if not exists] 数据库名称; # if not exists:当不确定是否存在该数据库时,使用这个参数
例:create database mydb1; - 删除数据库
drop database [IF EXISTS] 数据库名; 例:drop database mydb1;
- 修改数据库的字符集
alter database 数据库 character set 字符编码; 例:alter database students character set 'utf8'; 查看字符集的命令:show variables like 'character_set_database';
- 创建数据库
- 常用数据类型
MySQL与Python一样,也有数据类型。MySQL中数据类型主要应用在列上。int:整型
double/float:浮点型,例如double(5,2)表示最多5位,其中必须有2位小数,即最大值为999.99
decimal:浮点型,在表示钱方面使用该类型,因为不会出现精度缺失问题
char:固定长度字符串类型;char(4) 范围是0-255,即最多255个字符
- varchar:可变长度字符串类型
char和varchar的区别
text:字符串类型;表示存储较长文本
blob:字节类型,//jpg mp3 avi
date:日期类型,格式为:yyyy-MM-dd
time:时间类型,格式为:hh:mm:ss
- timestamp/datetime:时间戳类型,日期+时间 yyyyMMdd hhmmss
datetime和timestamp的比较
-
操作表
- 创建表
例如:create [if not exists] 表名( 字段名 数据类型 【字段约束】 字段名 数据类型 【字段约束】 ... );
create table students( sid int, sname varchar(20), age int, gender char(5), phone char(11), education char(3), place varchar(10), remark char(100), email varchar(50) );
- 查看指定表的创建语句
show create table 表名;
- 查看表结构
desc 表名;
- 删除表
drop table [if exists] 表名;
- 清空表
delete from 表名; # 精细化删除数据,而删除部分数据时只能使用delete truncate table 表名; # 粗暴型清空全部数据
- 修改表
- 添加列
alter table 表名 add 字段名 数据类型; 例:alter table students add hobby varchar(30); alter table 表名 add 字段名 数据类型 after 指定字段名; # 在指定字段名后面添加字段 例:alter table students add hobby varchar(30) after phone; alter table 表名 add 字段名 数据类型 first; # 将该字段添加到第一行 例:alter table students add hobby varchar(30) first;
- 修改列的数据类型
alter table 表名 modify 字段名 数据类型; 例:alter table students modfiy hobby char(30);
- 修改列名
alter table 表名 change 旧字段名 新字段名 数据类型; 例:alter table students change hobby interest varchar(30);
- 删除列
alter table 表名 drop 字段名; 例:alter table students drop interest;
- 修改表名称
alter table 旧表名 rename to/as 新表名; 例:alter table students rename to test_students; alter table students rename as test_students;
- 重命名表
rename table 旧表名 to 新表名; 例:RErename table test_students to students;
- 添加列
- 复制表
- 复制表的结构
create table [if not exists] 表名 like 要复制的表名; 例:create table stu2 like students;
- 复制表的结构和数据
create table 表名 select * from 要复制的表名; 例:create table stu3 select * from students;
- 复制表的结构
- 创建表
-
完整性约束
完整性约束是为了限制表中字段的数据的,从而进一步保证数据表的数据是一致的,准确的,可靠的。-
主键
当某一列添加了主键约束后,那么这一列的数据就不能重复出现。这样每行记录中其主键列的值就是这一行的唯一标识。例如学生的学号可以用来做唯一标识,而学生的姓名是不能做唯一标识的,因为学生有可能同名。注意:
- 主键列的值不能为NULL,也不能重复!
- 指定主键约束使用PRIMARY KEY关键字
- 创建表时创建主键
方式一: CREATE TABLE students( sid int PRIMARY KEY, sname varchar(20), age int, gender char(5), phone char(11), education char(3), place varchar(10), remark char(100), email varchar(50) ); 方式二: CREATE TABLE students( sid int, sname varchar(20), age int, gender char(5), phone char(11), education char(3), place varchar(10), remark char(100), email varchar(50) PRIMARY KEY(sid) ); # 注意,采用方式二可以添加多个字段为主键,但是考虑到实际情况及后续对主键的操作,不建议 设置多个主键
- 修改表时指定主键
alter table 表名 add primary key(字段名); 例: alter table students add primary key(sid);
- 删除主键(只是删除主键约束,而不会删除主键列)
alter table 表名 drop primary key; 例: alter table students drop primary key;
-
主键自增长
MySQL提供了主键自动增长的功能!这样用户就不用再为是否有主键重复而烦恼了。当主键设置为自动增长后,在没有给出主键值时,主键的值会自动生成,而且是最大主键值+1,也就不会出现重复主键的可能了 。- 创建表时设置主键自增长(主键必须是整型才可以自增长)
create table students( sid int primary key auto_increment, sname varchar(20), age int, gender char(5), phone char(11), education char(3), place varchar(10), remark char(100), email varchar(50) );
- 自改表时设置主键自增长
alter table 表名 change 字段名 字段名 数据类型 auto_increment; 例:alter table students change sid sid int auto_increment;
- 修改表时删除主键自增长
alter table 表名 change 字段名 字段名 数据类型; 例:alter table students change sid sid int;
- 创建表时设置主键自增长(主键必须是整型才可以自增长)
-
默认
指定默认值的列,在插入数据时,如果被默认约束的位置没有值,那么这个位置将会被DEFAULT的值填充。- 创建表时设置默认值
插入一条数据CREATE TABLE students( sid int primary key auto_increment, sname varchar(20), age int, gender char(5), phone char(11), education char(3), place varchar(10), remark char(100) default 'TEST', email varchar(50) );
insert into student(sname,age) values('张三',15);
- 修改表时指定默认值
alter table 表名 alter column 字段名 set default 默认值;(若本身不存在则可以直接设定) 例: alter table students alter column remark set default 'testclass';
- 创建表时设置默认值
非空
指定非空约束的列不能没有值,也就是说在插入记录时,对添加了非空约束的列一定要给值;在修改记录时,不能把非空列的值设置为NULL。-
创建表时指定非空约束
create table students( sid int primary key auto_increment, sname varchar(20) not null, age int, gender char(5), phone char(11), education char(3), place varchar(10), remark char(100) default 'TEST', email varchar(50) );
当为sname字段指定为非空后,再向students表中插入记录是,必须给sname字段指定值,否则会报错
insert into students(sid) values(2);
报错:image.png
给非空字段指定值:image.png -
修改表时指定非空约束:
alter table 表名 modify 字段名 数据类型 not null; 例:alter table students modify age not null;
-
-
唯一
还可以为字段指定唯一约束!当为字段指定唯一约束后,那么字段的值必须是唯一的。这一点与主键相似!例如给students表的sname字段指定唯一约束。- 创建表时添加唯一约束
向表中插入数据create table students( sid int primary key auto_increment, sname varchar(20) not null unique, age int, gender char(5), phone char(11), education char(3), place varchar(10), remark char(100) default 'TEST', email varchar(50) );
insert into students(sname) values('LHD'); insert into students(sname) values('LHD'); # 插入同样的数据报错
- 修改表是指定唯一约束
alter table 表名 modify 字段名 字段类型 unique; 例: alter table students modify gender char(11) unique; 或者: alter table 表名 add [constraint] [唯一约束名] unique(字段名); 例: alter table student add constraint g_unique unique(age); alter table students add unique(age);
- 修改表时删除唯一约束
唯一约束与主键约束的对比:# 1. 首先查看表的约束 show keys from 表名; 例: show keys from students; # 2. 删除对应的key_name drop index key_name on 表名; 例: drop index gender on students; 或者: alter table 表名 drop index key_name; alter table students drop index g_unique;
约束 字段是否可以为空 一张表可以有几个 主键 不可以为空 1个 唯一 可以为空 n个
- 创建表时添加唯一约束
-
外键
外键是构成表与表关联的唯一途径!外键是另一张表的主键! 为了更形象的让大家理解,做dage和xiaodi两个表,大哥表是主键表,小弟表是外键表。- 创建表时添加外键
在两张表中插入数据创建大哥表 create table dage( id int primary key auto_increment, name varchar(10) ); 创建小弟表 create table xiaodi( id int primary key auto_increment, dage_id int, name varchar(10), constraint fk_xd_dg foreing key(dage_id) references dage(id) );
删除大哥# dage表 insert into dage(name) values('CHN'); # 思考为什么在命令行窗口输入带有中文的 插入语句时报错 # xiaodi表 insert into xiaodi(dage_id,name) values(1,'A');
插入一个新的小弟delete from dage where id = 1; # 报错 # 不行呀,有约束的,大哥下面还有小弟,可不能扔下我们不管呀;
insert into xiaodi(dage_id,name) values(2,"B"); # 报错 # 小子,想造反呀!你还没大哥呢!
- 修改表时指定外键(必须先删除原有的外键)
alter table xiaodi add constraint fk_xd_dg foreing key(dage_id) references dage(id);
- 删除外键
# 1.先删除外键 alter table 表名 drop foreing key 外键名; 例:alter table xiaodi drop foreing key fk_xd_dg; # 2.再删除索引 alter table 表名 drop index 外键名; 例:alter table xiaodi drop index fk_xd_dg;
- 创建表时添加外键
-
数据表关系
-
一对多/多对一
一对多:从社会组织角度来说一个大哥拥有多个小弟即为一对多;多对一:从小弟角度来说多个小弟属于一个大哥即为多对一
存在最普遍的映射关系,简单来讲就如大哥与小弟的关系:
image.png - 一对一
一对一关系就如大哥与组织之间的关系,一个大哥仅有一个组织,而一个组织也仅有一个大哥;数据表间一对一关系的表现有两种,一种是外键关联,一种是主键关联;# 外键关联,即添加外键列 create table zuzhi( id int primary key auto_increment, dage_id int, name varchar(10), constraint fk_zz_dg foreing key(dage_id) references dage(id) ); # 主键关联,要求两个表的主键必须完全一致,通过两个表的主键建立关联关系 create table zuzhi( id int primary key auto_increment, name varchar(10), constraint fk_zz_dg foreing key(id) references dage(id) );
-
多对多
多对多关系也很常见,例如学生与选修课之间的关系,一个学生可以选择多门选修课,而每个选修课可以被多名学生选择。 数据库中的多对多关联关系一般需采用中间表的方式处理,将多对多转化为两个一对多。
image.png
-
-
- 基本操作
-
DML
-
插入数据
- insert...values
insert [into] 表名(列名1,列名2, …) values(值1, 值2); 例:INSERT INTO students(sname,age,gender,phone,education,place,remark) values('lhd',25,'man','15235206957','DZ','DT','fat'); 或:INSERT INTO students values(1,'lhd',25,'man','15235206957','DZ','DT','fat');
注意:
- 所有字符串数据必须使用单引号
- 如果要插入的值列表包含所有字段并且顺序一致,则可以省略字段列表
- 可同时插入多条数据记录
INSERT INTO 表名(列名1,列名2, …) VALUES(值1, 值2),(值1, 值2)... - 如果字段没有非空约束,那么可以不插入数据,可只插入部分数据
INSERT...SET
- insert...set
insert into 表名 set 字段名=值,字段名=值...; 例: insert into students set sname='张三',age=18;
- 插入查询结果
insert into 表名 (字段名,字段名) select 字段名,字段名 from 表名; 例: create table teachers( id int primary key auto_increment, tname varchar(5) not null unique, gender char(5) not null ); insert into teachers(tname,gender) values('xm','man'); insert into students(sname,gender) select tname,gender from teachers;
- insert...values
-
修改数据
update 表名 set 字段名=值,... 字段名=值 where 字句; 例: update students set phone='666666',education='bk' where id=1;
注意:更新时一定要保证WHERE子句的正确性,一旦WHERE子句出错,将会破坏所有改变的数据。
-
删除数据
-
delete
delete from 表名 where 字句; 例: delete from students where sid=1;
注意:在实际的应用中,执行删除操作时,执行删除的条件一般应该为数据的id,而不是具体某个字段值,这样就可以避免一些错误的发生。
-
truncate table
truncate table 表名; 例: truncate table myname;
-
-
-
DQL
select 要查询的列名称 from 表名 [where 满足的行条件] [group by 分组的依据] [order by 排序的依据] [limit 限定输出结果];
-
基础查询
- 查询所有的结果
select * from 表名; 例: select * from students
- 查询指定列
select 字段名,字段名,... from 表名; 例: select sname,phone from students;
- 查询一个或多个表中的数据
select 表名.字段名,表名.字段名,... from 表1,表2,...; 例: select students.sname,students.age,teacher.tname,teacher.gender from students,teachers;
- 查询所有的结果
-
条件查询
条件查询就是在查询时给出WHERE子句,在WHERE子句中可以使用如下运算符及关键字;运算符 名称 示例 = 等于 id = 5 !=或<> 不等于 id != 5 > 大于 id > 5 >= 大于等于 id >= 5 < 小于 id < 5 <= 小于等于 id <= 5 关键字 名称 示例 and 和 name='张三' and age=25 or 或 name='张三' or name='李四' is null 为空 phone is null is not null 不为空 id is not null between and 在...和...区间 id between 1 and 5 in 在...集合中 id in(3,4,5) not in 不在...范围里 id not in(100,101) like 模式匹配 name like('a%') not like 模式匹配 name not like('a%') regexp 常规表达式 name 正则表达式 - 带关键字in的查询
关键字IN可以判断某个字段的值是否在指定的集合中。如果字段的值在集合中,则满足查询条件,该记录将被查询出来;如果不在集合中,则不满足查询条件。select 字段名 from 表名 where 条件 [not] in (元素1,元素2,元素3,...); 例:select * from students where age in (18,19,20); # 查询年龄在(18,19,20)范围 内的学生信息
- 带关键字between and的范围查询
关键字BETWEEN AND可以判断某个字段的值是否在指定的范围内。如果字段的值在指定范围内,则满足查询条件,该记录将被查询出来。如果不在指定范围内,则不满足查询条件。select 字段名 from 表名 where 条件 [not] between 取值1 and 取值2; 例:select * from students where age between 25 and 30; # 查询年龄在25~30之间的 学生信息
- 带关键字like的字符匹配查询
通过like可以实现模糊查询。它有两种通配符:“%”和下划线“_”- “%”可以匹配一个或多个字符,可以代表任意长度的字符串,,长度可以为0。例如,“L%D”表示以“L”开头,以“D”结尾的任意长度的字符串。
- “ _ ”只匹配一个字符。例如“m_n”表示以m开头,以n结尾的3个字符。中间的“_”可以代表任意一个字符。
select 字段名 from 表名 where 字段名 like 匹配规则; 例:select * from students where sname like '刘%'; # 查询姓名以“刘”开头的学生信息
- 带关键字is null查询空值
关键字and可以用来联合多个条件进行查询。使用关键字and时,只有同时满足所有查询条件的记录会被查询出来。如果不满足这些查询条件的其中一个,这样的记录就会被排除掉。select 字段名 from 表名 where 条件1 and 条件2 [...and 条件n]; 例:select * from students where age>22 and education='大专'; # 查询年龄大于22 且学历为大专的学生信息
- 带关键字or的多条件查询
关键字or也可以用来联合多个条件进行查询,但是与关键字and不同,关键字or只要满足查询条件中的一个,那么此记录就会被查询出来;如果不满足这些查询条件中的任何一个,这样的记录将被排除掉。select 字段名 from 表名 where 条件1 or 条件2 [...or 条件n]; 例:select * from students where age>22 or education='大专'; # 查询年龄大于22 且学历为大专的学生信息
- 带关键字distinct去除结果中的重复行
使用关键字distinct可以去除查询结果中的重复记录select 字段名 from 表名 order by 字段名 [desc]; 例:select * from students order by age; # 查询学生信息并根据年龄排序
- 带关键字group by分组查询
- 单独使用关键字group by查询结果只显示每组的一条记录
select 字段名 from 表名 group by 分组依据的字段名; 例:select id,sname,age,phone from students group by age; # 查询学生id,姓 名,年龄,电话,每个年龄段只显示一条记录
- 使用关键字group by与group_count()函数一起使用,可以将每个组中的记录数量都显示出来
select 字段名,group_count()分组依据的字段名) from 表名 group by 分组依赖的字段 名; 例:select id,sname,age,phone,group_count(age) from students group by age; # 查询学生id,姓名,年龄,电话,根据age分组并显示每一组的记录
- 按多个字段进行分组
使用关键字group by也可以按多个字段进行分组select 字段名 from 表名 group by 分组依据的字段名,分组依据的字段名...; 例:select id,sname,age,phone,place,group_count(age,place) from students group by age,place; #查询学生信息,根据age,place分组并显示每一组的记 录
- 单独使用关键字group by查询结果只显示每组的一条记录
- 用关键字limit限制查询结果的数量
- limit是MySQL中一个特殊的关键字,可以对查询结果的记录条数进行限定,控制它输出的行数。
select 字段名 from 表名 [其他条件] limit int; 例:select * from students order by age limit 10; # 查询学生信息,根据age 排序并只显示10条记录
- 还可以从查询结果的中间部分取值。首先要定义两个参数,参数1是开始读取的第一条记录的编号(在查询结果中,第一个结果的记录编号是0,而不是1);参数2是要查询记录的个数
select 字段名 from 表名 [其他条件] limit int,int; 例:select * from students order by age limit 0,5; # 查询学生信息,根据age 排序从第0位开始显示,只显示5条
- limit是MySQL中一个特殊的关键字,可以对查询结果的记录条数进行限定,控制它输出的行数。
- 用关键字regexp使用正则表达式查询
正则表达式是用某种模式去匹配一类字符串的一个方式。正则表达式的查询能力比通配字符的查询能力更强大,而且更加灵活。
select 字段名 from 表名 where 字段名 regexp '匹配方式';
https://www.runoob.com/mysql/mysql-regexp.html
- 带关键字in的查询
-
聚合函数查询
- count()函数
对于除" * "以外的任何参数,返回所选择集合中非NULL值的行的数目;对于参数“*”,返回选择集合中所有行的数据,包含NULL值的行。select count(字段名) from 表名; 例:select count(*) from students;
- sum()函数
sum()函数可以求出表中某个字段取值的总和select sum(字段名) from 表名; 例:select sum(age) from students;
- avg()函数
avg()函数可以求出表中某个字段取值的平均值select avg(字段名) from 表名; 例:select avg(age) from students;
- max()函数
max()函数可以求出表中某个字段取值的最大值select max(字段名) from 表名; 例:select max(age) from students;
- min()函数
min()函数可以求出表中某个字段取值的最小值select min(字段名) from 表名; 例:select min(age) from students;
- count()函数
-
连接查询
- 内连接查询
列出数据表中与连接条件相匹配的数据行,组合成新记录【只有满足条件的记录才出现在查询结果】
内连接的最常见的例子是相等连接,也就是连接后的表中的某个字段与每个表中的都相同。# 员工表 create table staff( id int primary key auto_increment, name varchar(20) not null, dpid int not null ); # 部门表 create table department( id int primary key auto_increment, dname varchar(10) ); insert into staff(name,dpid) values('张三',1); insert into staff(name,dpid) values('李四',1); insert into staff staff(name,dpid) values('王五',2); insert into staff(name,dpid) values('赵六',2); insert into department(dname) values('开发'); insert into department(dname) values('测试'); select 字段名1,字段名2 from表名1 inner join表名2 where 连接条件; 例:select s.name,d.dname from staff s inner join department d where s.dpid = d.id; # 连接员工表的dpid字段和部门表的id字段,并查询员工姓名和部门名称
- 外连接查询
与内连接不同,外连接是指使用OUTER JOIN关键字将两个表连接起来。外连接生成的结果集不仅包含符合连接条件的行数据 ,而且还包含左表(左外连接时的表) 右表(右外连接时的表)或两边连接表(全外连接时的表)中所有的数据行。
select 字段名称 from 表名1 left|right join 表名2 on 表名1.字段名1 = 表名2.字段名2;
- 左外连接
左外连接是指将左表中的所有数据分别与右表中的每条数据进行连接组合,返回的结果除了内连接的数据外,还包括左表中不符合条件的数据,并在右表的相对应列中添加NULL值insert into staff(name,dpid) values('小明',3); insert into staff(name,dpid) values('小花',3); select s.name,d.dname from staff s left join department d on s.dpid = d.id; #连接员工表的dpid字段和部门表的id字段,并查询员工姓名和部门名称,如果右表中没有对应的 连接数据,会自动添加NULL值
- 右外连接
右外连接是指将右表中的所有数据分别与左表中的每条数据进行连接组合,返回的结果除内连接的数据外,还包括右表中不符合条件的数据,并在左表的相应列中添加NULLinsert into department(dname) values('人事'); insert into department(dname) values('行政'); select s.name,d.dname from staff s right join department d on s.dpid = d.id; # 连接员工表的dpid字段和部门表的id字段,并查询员工姓名和部门名称,如果左表中没有对应 的连接数据,会自动添加NULL值
- 复合条件连接查询
在连接查询时,也可以增加其他的限制条件,通过多个条件的复合查询,可以使查询结果更加准确。select 字段名1,字段名2 from 表名1,表名2 where 连接条件 and 限制条件; 例:select s.name,d.dname from staff s,department d where s.dpid = d.id and s.dpid>1; # 查询员工姓名和部门名称,条件是员工表的dpid字段与部门表中的id字段相等,并且dpid大于1
- 左外连接
- 内连接查询
-
子查询
子查询就是select查询是另一个查询的附属,MySQL4.1开始可以嵌套多个查询,在外面一层的查询中使用里面一层查询产生的结果集。这样就不是执行两个(或多个)独立的查询,而是执行包含一个(或多个)子查询的单独查询。
当遇到这样的多重查询时,MySQL从最内层的查询开始,然后从它开始向外向上移动到外层(主)查询,在这个过程中每个查询产生的结果集都被赋予到包围它的父查询,接着这个父查询被执行,它的结果也被指定给父查询。
除了结果集经常由包含一个或多个值的一列组成外,子查询和常规SELECT查询的执行方式一样。子查询可以用在任何可以使用表达式的地方,它必须由父查询包围,而且,如同常规的select查询,它必须包含一个字段列表(这是一个单列列表) 具有一个或者多个表名字的from子句以及可选的where having和group by子句。- 带关键字in的子查询
只有子查询返回的结果列包含一个值时,比较运算符才适合。例如一个子查询返回的结果集是值的列表,这时比较运算符就必须用关键字in代替。
in运算符可以检测结果集中是否存在某个特定的值,如果检测成功就执行外部的查询select 字段名 from 表名 where 字段名 in(select 字段名 from 表名); 例:select * from staff where dpid in(select id from department); # 首先从部门表中获取id,当员工表的dpid在部门表id的多个值中存在时,查询员工信息
- 带比较运算符的子查询
子查询也可以使用比较运算符,包括= != > >= <和<=等。比较运算符在子查询时使用非常广泛。select 字段名 from 表名 where 字段名 比较运算符(select 字段名 from 表名 where 条件); 例:select * from staff where dpid=(select id from department where dname = '开发'); # 查询员工所属部门id等于部门名称为“开发”的编号id时的员工信息
- 带关键字in的子查询
-