Structure Query Language(结构化查询语言)简称SQL
MySQL是基于SQL查询的开源跨平台数据库管理系统(DBMS),MYSQL是一个关系数据库管理系统(RDBMS)
MYSQL分为了三个部分:
数据库本质是一个文件夹,数据库表本质是一个文件。
1、DDL(Data Definition Language) 数据定义语言,用来操作数据库、表、列等; 常用语句:CREATE(创建)、 ALTER()、DROP
2、DML(Data Manipulation Language) 数据操作语言,用来操作数据库中表里的数据;常用语句:INSERT(插入)、 UPDATE(修改)、 DELETE(删除)
3、DCL(Data Control Language) 数据控制语言,用来操作访问权限和安全级别; 常用语句:GRANT(授权)、REVOKE(撤回)、DENY(否认)
4、DQL(Data Query Language) 数据查询语言,用来查询数据 常用语句:SELECT(选择)
根据数值取值范围的不同MySQL 中的整数类型可分为5种,分别是TINYINT、SMALUNT、MEDIUMINT、INT和 BIGINT。下图列举了 MySQL不同整数类型所对应的字节大小和取值范围,而最常用的为INT类型的。
如果没有指定 unsinged,则默认为有符号
数据类型 | 字节数 | 无符号数的取值范围 | 有符号数的取值范围 |
---|---|---|---|
TINYINT | 1 | 0~255 | -128~127 |
SMALLINT | 2 | 0~65535 | -32768~32768 |
MEDIUMINT | 3 | 0~16777215 | -8388608~8388608 |
INT | 4 | 0~4294967295 | -2147483648~ 2147483648 |
BIGINT | 8 | 0~18446744073709551615 | -9223372036854775808~9223372036854775808 |
数据类型 | 字节数 |
---|---|
FLOAT | 4 |
DOUBLE | 8 |
DECIMAL(M,D) | M+2 |
DECIMAL(M,D)中的M表示这个数一共又多少位,D表示小数点后有多少位。例如DECIMAL(5,2)就表示三位整数,两位小数的数。如果D为零,即表示一个整数了,应为没有小数位。所以DECIMAL不仅可以表示小数,还可以表示整数。
M的默认值位10,D的默认值位2。M的最大值为65,D的最大值位30。由此可见DECIMAL是可以表示非常大的值的
CHAR(size),表示存放固定长度的字符串,括号中的的参数设置字符串的长度,最大为255个字符
VARCHAR(size),表示存放可变长度字符串,最大为65535个字节。这里明确字符和字节的区别,在不同的编码中一个字符所占的字节是不同的。而亲还要留出3个字节的空间来保存所存放字符串的大小,所以字符的可用字节为65532个字节。
4.0版本以下,varchar(20),指的是20字节,如果存放UTF8汉字时,只能存6个(每个汉字3字节)
5.0版本以上,varchar(20),指的是20字符,无论存放的是数字、字母还是UTF8汉字(每个汉字3字节),都可以存放20个,最大大小是65532字节
一个字母,数字,汉字就是一个字符,而位和字节是两个单位
计算机存储信息的最小单位,称之为位(bit),音译为比特,二进制的一个“0”或一个“1”叫一位。
计算机存储容量基本单位是字节(Byte),音译为拜特,8个二进制位组成1个字节。一般而言:一个标准英文字母占一个字节位置,一个标准汉字占二个字节位置。
UTF-8编码中:一个英文字符等于一个字节,一个中文(含繁体)等于三个字节。
CHAR和VARCHAR的区别
CHAR存放的的是固定长度的字符串,即使你没有添加够字符长度,也会自动填充。VARCHAR存放可变长度的字符串,会根据添加的字符来确定字符串的大小。另外VARCHAR还会预留1~3个字节来存放字符串的长度。
如果我们已经知道要存放数据的大小,我们应该选用CHAR,反之,使用VARCHAR。因为CHAR比VARCHAR的查询速度快。
文本数据类型
也是用来存放字符串,相对比较简单,不需要指定size
数据类型 | 储存范围 |
---|---|
TINYTEXT | 0~255字节 |
TEXT | 0~65535字节 |
NEDIUMTEXT | 0~16777215字节 |
LONGTEXT | 0~4294967295字节 |
数据类型 | 日期格式 |
---|---|
YEAR | YYYY |
DATE | YYYY-MM-DD |
TIME | HH:MM:SS |
DATETIME | YYYY-MM-DD HH:MM:SS |
TIMESTAMP | YYYY-MM-DD HH:MM:SS |
可通过设置
TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
来当前TIMESTAMP 为默认时间戳
创建数据库
CREATE DATABASE mydb3;
创建表
CREATE TABLE t2(
birthday DATE,
job_time DATETIME,
log_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);
查询所有数据库
SHOW DATABASES;
查询数据库的创建信息
SHOW CREATE DATABASE mybd2;
查询当前数据库中的所有表
SHOW TABLES;
查询指定表的创建信息
SHOW CREATE TABLE t2;
查询表结构
DESC t2;
查询表中的数据
SELECT* FROM t2;
INSERT INTO t4(birthday,job_time) VALUES('2021-8-5','2021-8-5 11:10:30');
INSERT INTO t2 VALUE(10);
INSERT INTO t1(id,`name`) VALUES(6,'erha'), (5,'元芳');
注意点:
增加一列
alter table `emp` add image VARCHAR(32) not null default '' after resume;
修改列
alter table `emp` modify jod VARCHAR(32) not null default '';
删除列
alter table `emp` drop sex;
修改字符集
alter table `employee` character set utf8;
修改列名
alter table employee change `name` `user_name` varchar(32) not null default '';
修改表名
rename table `emp` to `employee`;
修改表中数据
update employee set salary=5000;
update employee set salary=2000 where user_name='元芳';
update employee set salary=salary+1000 ,jod='元帅' where user_name='元芳';
删除数据库
drop database myda3;
删除表
drop table t2;
因为执行指令是在一个数据库中执行的,所以可以不用指定是哪个数据库的表名
删除列
alter table `emp` drop sex;
删除一行
delete from employee where user_name='狄仁杰';
删除所有行
delete from employee;
查询所有列
#select 后就是要查询的列,*表示通配
select * from student;
查询指定列
select distinct `name`,`english` from student;
as起别名
select `name` ,(math+english+chinese) as sum_score from student;
where子句的使用
select * from student where `name`='小华';
select * from student where english>90;
select * from student where (math+english+chinese)>250;
select * from student where math >80 and id>3;
select * from student where math>english;
select * from student where (math+english+chinese)>250 and math=80 and math<=90;
#between and 是一个闭区间
select * from student where math between 80 and 90;
select * from student where math in(80,89,81);
order by 子句
select * from student order by math;
#升序
select * from student order by math desc;
#降序
select `name`, (math+english+chinese) as sum_score from student where sum_score>240;
#where中不能使用别名
select *, (math+english+chinese) as sum_score from student WHERE (math+english+chinese)>240 ORDER BY sum_score;
需要注意的是在where中不可以使用别名
#统计满足条件的行数
select count(*) from student;
select count(*) from student where math>80;
#select(*)和select(`id`)的区别#select(*)返回所有的行,select(`id`)返回id不为空的行
select count(`id`) from student;
#sum
select sum(math) from student;
select sum(math),sum(chinese),sum(english) from student;
select sum(math+chinese+english) from student;
select sum(math)/count(*) from student;
select sum(salary)/count(*) from employee;#avgselect avg(math) from student;
#不会统计salary为空的行select avg(salary) from employee;
#分组 group by 是对employee的一个分组 ,having是对分组后内容的一个过滤
select avg(salary) from employee group by id having avg(salary)>6000;
#max min
select max(math),min(math) from student;
#查询字符集
select charset(dname) from dept;
#将多列拼接成一列
select CONCAT(dname,' 在 ',loc) from dept;
#查找子串开始的位置 dual是系统默认的一个表
select instr('zhouzhihao','hao') from dual;
#转大写
select ucase(dname) from dept;
#转小写
select lcase(dname) from dept;
#从左边开始在n个
select left(loc,2) from dept;
# 从右边开始在n个
select right(loc,2) from dept;
#查看字符串长度 按字节放回
select `loc`,length(loc) from dept;
select length('周志浩') from dept;
#替换字符串
select replace(loc,'ShangHai','上海') from dept;
#字符串比较 相同返回0 ,大于返回1 ,小于返回-1
select strcmp(loc,dname) from dept;
#查找子串 从1开始找,包含1,找两个
select substring(loc,1,2) from dept;
#去空格
select ltrim(loc),rtrim(loc),trim(loc) from dept;
#练习
select CONCAT(ucase(substr(dname,1,1)),substr(dname,2)) as new_name from dept;
select CONCAT(ucase(left(dname,1)),substr(dname,2)) as new_name from dept;
#当前日期
select current_date from dual;
#当前时间
select current_time from dual;
#当前时间戳
select current_timestamp from dual;
#只显示日期,不显示时间
select date(log_time) from t4;
#增加时间
select * from t4 where date_add(log_time,interval 3 day)>=now();
#相差多少天
select datediff(now(),log_time) from t4;
#相差多少天
select datediff('2081-12-04',NOW()) from dual;
#相差多少时间
select timediff('10:20:20','10:10:10');
#只返回当前的年 月 日
select year(now()) from dual;
select month(now()) from dual;
select day(now()) from dual;
#返回1970-1-1到现在的秒数
select unix_timestamp() from dual;
#把unix_timestamp的秒数 转换为指定的日期格式(格式是固定的)
#在开发中可以存放一个整数,将其转为一个日期
select from_unixtime(unix_timestamp(),'%Y-%m-%d') from dual;
select from_unixtime(unix_timestamp(),'%Y-%m-%d %H:%i:%s') from dual;
#查看登录到mysql的用户以及用户IP
select USER() from dual;
#查看当前使用的数据库表名
select database();
#MD5(str) 为字符串算出一个32位字符串进行加密
select MD5('xx666666');
select length(MD5('xx66666'));
#PASSWORD(str)加密函数,数据库的用户密码就用的是这个加密
select PASSWORD('xx666666');
select * from mysql.user;
#IF() 相当于一个三元运算符 第一个如果是一个字符串的话就会认为是一个false
select if(false,'hello','get') from dual;
select if(true,'hello','get') from dual;
#IFNULL expr1 不为空,就返回expr1 否则返回expr2
select ifnull(null,'hello');
select ifnull('zzh','hello');
#case 相当于多重判断
select case
when false then 'hello'
when true then 'zzh'
else 'world' end;
#练习
desc t4;
select * from dept;
select if(job_time is null,CURRENT_TIMESTAMP,job_time) from t4;
select ifnull(job_time,CURRENT_TIMESTAMP) from t4;
select dname, (select case when dname='accounting' then '财务部'
when dname='research' then '研发部'
when dname='sales' then '销售部'
when dname='operations' then '监管部'
else dname end
) as job from dept;
#分页查询
#从start+1开始查询,查找三行
#第一页
select * from emp order by empno limit 0,3;
#第二页
select * from emp order by empno limit 3,3;
#第三页
select * from emp order by empno limit 6,3;
#最后一页
select * from emp order by empno limit 12,3;
#下面关键字必须按顺序来 empno不能使用下面的语句
#empno是一个非聚合列,不能使用group by
select empno,avg(sal) as avg_sal from emp group by deptno having avg_sal>1000 order by avg_sal desc limit 0,2;
group by
子句后用having
代替where
使用
select ename,sal,dname,emp.deptno from emp,dept1 where emp.deptno=dept1.deptno;
select ename,sal,dname,emp.deptno
from emp,dept1
where emp.deptno=dept1.deptno and emp.deptno=10;
select ename,sal,grade from emp,salgrade where sal between losal and hisal;
select ename,sal,dname from emp,dept1 where emp.deptno=dept1.deptno;
select * from dept1;
select * from salgrade ;
#自链接 一张表当两张表使用 返回了169条记录 13*13
#worker和boss相当于时emp的别名
select * from emp worker,emp boss;
#添加条件
select worker.ename as '员工',boss.ename as 'leader'
from emp worker ,emp boss
where worker.mgr=boss.empno;
/*
自连接的特点:
一张表当作两张表来使用
需要给表别名 原表名 空格 别名
如果列名不清晰,可起别名
*/
#子查询:select语句嵌套在select语句中
select deptno from emp
where ename='SMITH';
#单行子查询:子查询的查询结果只有一行
select deptno,ename from emp where deptno=(
select deptno from emp where ename='SMITH'
);
#多行子查询:子查询的查询结果多行
select deptno,job from emp where deptno=10;
select ename,job,sal,deptno from emp where job in (
select job from emp where deptno=10
)and deptno!=10;
#多行子查询,还可以当作一张临时表使用
#all操作符
select ename,sal,deptno from emp where sal>all(
select sal from emp where deptno=30
);
select ename,sal,deptno from emp where sal>(
select max(sal) from emp where deptno=30
);
#any操作符
select ename sal,deptno from emp where sal>any(
select sal from emp where deptno=30
);
select ename sal,deptno from emp where sal>(
select min(sal) from emp where deptno=30
);
#多列子查询
select deptno,job from emp where ename='ALLEN';
#where括号中内容与查询的内容一一对应进行比较
select * from emp where(deptno,job)=(
select deptno,job from emp where ename='ALLEN'
)and ename<>'ALLEN';
#复制表结构
create table temp_emp like emp;
desc temp_emp;
#复制表内容
#采用这种方式可以不断地给表中添加数据,当数据够大时,可通过海量数据来测试SQL语句的效率
insert into temp_emp select * from emp;
select * from temp_emp;
#表中删除重复数据的思路
#创建临时表
create table temp_emp1 like temp_emp;
desc temp_emp1;
insert into temp_emp1 select distinct * from temp_emp;
delete from temp_emp;
insert into temp_emp select * from temp_emp1;
drop table temp_emp1;
select count(*) from temp_emp;
#union all 关键字可以合并两条select语句查询结果,不去重
select empno,ename,sal from emp where sal>2000;
union all
select empno,ename,sal from emp where deptno=20;
select count(*) from emp where sal>2000;
select count(*) from emp where deptno=20;
select count(*) from
(select empno,ename,sal from emp where sal>2000
union all
select empno,ename,sal from emp where deptno=20) temp;
#union all 关键字可以合并两条select语句查询结果,去重
select count(*) from
(select empno,ename,sal from emp where sal>2000
union
select empno,ename,sal from emp where deptno=20) temp;
#左外连接 显示左表的所有内容 左表在右表中没有的内容显示为null
select dname,ename, job
from dept1 left join emp
on dept1.deptno=emp.deptno;
#左外连接 显示右表的所有内容 右表在左表中没有的内容显示为null
select dname,ename, job
from emp right join dept1
on dept1.deptno=emp.deptno;
#实际开发中最常用还是内连接,多表查询
#在创建表的时候可以定义主键,表示改内容在表中不能重复出现
# primary key 不能重复且,不能为空。
create table t5(
id int primary key,
`name` varchar(10),
job varchar(10)
)
desc t5;
#主键只有一个,但可以有复合主键:只有两个值都相等时,才算重复
create table t6(
id int,
`name` varchar(10),
job varchar(10),
primary key(id,`name`)
)
desc t6;
#也可以采用创建符合主键的方式,来创建单个主键
create table t7(
id int,
`name` varchar(10),
job varchar(10),
primary key(id)
)
desc t7;
#在实际开发中,往往每个表都会设计一个主键
/*创建外键的条件:
1.创建一个主表,主表中被主键或unique约束的字段,可作为为从表外键的依赖
2.创建一个从表,在从表中可以设置某个字段为外键
外键的特性:
1.主表中主键的字段添加的数据不能重复
2.从表中为外键外键的字段可以重复,但必须是外键依赖中有的字段
*/
create table class(
class_id int primary key,
`name` varchar(10)
);
desc class;
create table stu(
id int primary key,
`name` varchar(10),
class_id int,
foreign key (class_id) references class(class_id)
);
desc stu;
insert into class values(100,'java'),(200,'wab'),(300,'PHP');
insert into stu values(1,'erha',100),(2,'yf',200),(3,'gg',300);
insert into stu values(4,'zzh',400);
select *from stu;
/*
外键的使用细节
1.外键指向的表的字段,要求是primary key或unique
2.表的类型是Innodb,这样才支持外键
3.外键字段的类型要和主键字段的类型相同(长度可以不同)
4.外键字段的值,必须在主键中出现过,或者为null(前提是外键没有设置not null)
5.一个表中可以有多个外键
6.一旦建立外键的关系,数据不能随意删除了,两个表建立了依赖关系
*/
#check约束 对添加数据进行校验
create table t9 (
id int,
sex varchar(10) check(sex in('man','woman')),
sal int check(sal>1000 and sal<2000)
);
insert into t9 values(1,'mid',1); #添加失败 Check constraint 't9_chk_1' is violated.
insert into t9 values(1,'man',1500);
select * from t9;
#自增长
create table t10(
id int primary key auto_increment,
`name` varchar(10)
);
#两种插入方式
insert into t10 values(null,'erha');
insert into t10 (`name`) values('yuanfang');
/*
自增长一般于主键配合使用,或者使用unique约束
自增长一般修饰整型(小数也可以,但用的很少)
自增长默认从一开始
可以修改自增长的起始值
*/
alter table t10 auto_increment=10;
/*
索引的原理:
1.底层是一个二叉树
2.占用内存空间
3.对dml语句的效率有影响,因为要重构二叉树
4.对那个字段建立索引才会,提高那个字段的查询效率
为什么没有索引会很慢?
当要查询一条数据时,都会进行一次全表扫描
索引的分类:
1.主键索引
2.唯一索引(unique)
3.普通索引(index 开发中常用的索引,可以提高查询速度,又可以让数据有重复)
4.全文索引(一般开发中不使用MySql自带的全文索引,会使用全文搜索的框架:Solr和ElasticSearch)
*/
create table t11(
id int,
`name` varchar(10)
);
#查询表中是否有索引
show index from t11;
#添加唯一索引
create unique index id_index on t11(`id`);
#添加普通索引
create index name_index on t11(`name`);
alter table t11 add index name_index (`name`);
#unique索引的优点:查询快
#添加主键索引
#在创建表的时候,添加组件就是一个主键索引
alter table t11 add primary key (id);
#删除普通索引
drop index `name_index` on t11;
#删除主键索引
alter table t11 drop primary key;
#修改索引:先删除,后添加
#查找索引
show index from t11;
show indexes from t11;
show keys from t11;
desc t11;
/*
那些列适合创建索引
1.较频繁的作为查询条件的字段,应当创建索引
2.唯一性太差的索引不适合创建索引
3.更新非常频繁的字段不适合创建索引
4.不会出现在where子句的字段不适合创建索引
*/
create table t12 (
id int,
`name` VARCHAR(6)
);
select * from t12;
#开始一个事务
start transaction;
#设置保存点a
savepoint a;
insert into t12 values(1,'erha');
#设置保存点b
savepoint b;
insert into t12 values(2,'yfang');
#回退到保存点a
rollback to b;
#回退到保存点a
rollback to a;
#回退全部事务:之前的保存点会被删除
rollback
#提交事务:删除所有的保存点,不能再回滚事务
commit;
/*
事务的细节:
1.如果不开启一个事务,默认情况下是自动提交,没有自动回滚的功能
2.在开启事务时,不创建保存点,也会默认有一个保存点,可使用rollback实现回退
3.mysql的事务机制需要Innodb存储引擎才可以使用
4.也可以使用SQL语句:set autocommit=off; 来开启事务(就是关闭自动提交的意思)
*/
概念:多个连接开启各自事务操作数据库中的数据时,数据库系统要负责隔离操作,以保证各个连接的在获取数据时的准确性。
通俗解释:当有多个连接在开启事务时,就会保存当前数据库表的所有数据。当连接要对同一张表进行操作(insert into,delete,alter)时,不应该影响到其他事务保存的数据库表中的数据。就是不同事务之间是隔离开来的,事务之间互不影响
MySql有四种隔离级别:定义事务与事务之间的隔离程度
三种读取状态:
不可重复读和幻读都强调:一个事务读取到另外一个事务已经提交的数据。
四种隔离级别的区别:
隔离级别 | 脏读 | 不可重复读 | 幻读 | 锁 |
---|---|---|---|---|
读未提交 | ✅ | ✅ | ✅ | ❌ |
读已提交 | ❌ | ✅ | ✅ | ❌ |
可重复读 | ❌ | ❌ | ❌ | ❌ |
可串行化 | ❌ | ❌ | ❌ | ✅ |
强调:事务隔离的前提是,开启事务
默认的隔离级别是:可重复读(REPEATABLE READ)。
#查询隔离级别
show variables like '%isolation%';
#修改隔离级别
SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;
事务的四个特性(ACID):
create table t12 (
id int,
`name` VARCHAR(6)
);
select * from t12;
#开始一个事务
start transaction;
#设置保存点a
savepoint a;
insert into t12 values(1,'erha');
#设置保存点b
savepoint b;
insert into t12 values(2,'yfang');
#回退到保存点a
rollback to b;
#回退到保存点a
rollback to a;
#回退全部事务
rollback
#提交事务:删除所有的保存点,不能再回滚事务
commit;
/*
事务的细节:
1.如果不开启一个事务,默认情况下是自动提交,没有自动回滚的功能
2.在开启事务时,不创建保存点,也会默认有一个保存点,可使用rollback实现回退
3.mysql的事务机制需要Innodb存储引擎才可以使用
4.也可以使用SQL语句:set autocommit=off; 来开启事务(就是关闭自动提交的意思)
*/
/*
Innodb:
1.支持事务和外键
2.支持行级锁,所以插入数据的效率会受到影响
MyISAM:
1.不支持事务和外键
2.支持表级锁,插入数据的效率高
MEMORY:
1.不支持事务和外键
2.数据存储在内存中,所以不能存储较大的数据库表,查询速度快
3.适用于临时表
4.默认支持索引(hash表)
*/
#查看所有的存储引擎
show engines;
#创建表时设置存储引擎
create table t14(
id int,
`name` varchar(10)
)engine MyISAM;
#修改表存储引擎
alter table t14 engine=INNODB;
/*
如何选择存储引擎
1.如果你的应用不需要事务,只是简单的CRUD操作,那么可以选择MYISAM
2.如果需要支持事务,选择Innodb
3.如果像用户在线状态这种寻求就可以采用MEMORY
*/
/*
1.视图是根据基表来创建的,视图是虚拟的表(在创建数据库文件中,只有一个结构文件,没有数据文件)
2.视图也有列,数据来自基表
3.通过视图改变可以修改基表
4.基表的改变也会影响数据的数据
5.视图中还可以创建视图,数据仍然来自基表
*/
#创建视图
create view emp_view01
as select empno,ename,job,deptno from emp;
#查看视图结构
desc emp_view01;
#查看表中数据
select * from emp_view01;
#修改视图中列
alter view emp_view01 as select empno,ename,job from emp;
#查看创建视图的指令
show create view emp_view01;
#删除视图
drop view emp_view01;
#修改视图 会影响到基表
update emp_view01 set job='SALESMAN' where empno=7369;
#修改基表 也会影响视图
update emp set job='CLERK' where empno=7369;
#视图中创建视图
create view emp_view02 as select empno,ename from emp_view01;
select * from emp_view02;
#多表为基表创建视图
create view emp_view03 as
select empno,ename,emp.deptno,salgrade.grade
from emp,salgrade,dept1
where emp.deptno=dept1.deptno and
emp.sal>salgrade.losal and emp.sal<salgrade.hisal;
select * from emp_view03;
/*
视图的优点:
1.方便向用户展示想要展示的表内容
2.可以通过视图的方式来结合多张表中的数据,方便操作
*/