目录
前提知识
数据库三层机构
数据在数据库的存储方式
SQL语句分类
数据库操作
创建数据库
查看数据库
使用数据库
删除数据库
备份数据库
恢复数据库
常用数据类型
字符串细节
细节1:
细节2:
细节3:
细节4:
表操作
创建表
查看表结构
删除表
数据库CRUD语句
insert
updata
delete
select
别名
去重
排序
条件查询
函数
合计函数
count
sum
avg
max/min
配合合计函数的语法——分组:group by
字符串函数
数学相关函数
日期相关函数
加密和系统函数
查询增强
分页查询
数据分组的总结
多表查询
自连接
子查询
表复制
合并查询
外连接
约束
主键primary key
unique
外键
check
自增长
索引
索引类型
添加索引
主键索引
唯一索引
普通索引
全文索引
删除索引
显示索引
修改索引
索引创建规则
事务
细节
隔离级别
脏读
不可重复读
幻读
设置隔离级别
表类型和存储引擎
查看所有存储引擎
主要的存储引擎/表类型特点
细节说明
修改存储引擎
视图
使用
创建视图
细节
视图的最佳实践编辑
MySQL管理
创建用户
修改密码
删除用户
分配权限
回收权限
细节
最后要说的话
使用SQLyog软件操作数据库
1.所谓安装MySQL数据库,就是在主机安装一个数据库管理系统(DBMS),这个管理程序可以管理多个数据库。DBMS(database manage system)
2.一个数据库可以创建多个表,以保存数据。
3.数据库管理系统(DBMS)、数据库和表的关系如图所示:
表的一行成为一条记录(在Java程序中,一行程序往往使用对象表示),一行中的一列称为一个字段。
DDL:数据定义语句[create 表,库..]
DML:数据库操作语句[增加 insert,修改 update,删除delete]
DQL:数据查询语句[select]
DCL:数据控制语句[管理数据库:比如用户权限 grant revoke]
[这里是可选限制条件]
create database 数据库名 [CHARACTER SET 字符集 [COLLATE 校对规则]]
注意:
名字不能和关键字重名,如果想想重名则可使用反引号(英文输入法,tab键上面,!的左边)包裹名字
例如
create database `database`;
举个例子
# 创建一个使用utf8字符集的cs_db02数据库
CREATE DATABASE cs_db02 CHARACTER SET utf8;
# 创建一个使用utf8字符集,并带校对规则的cs_db03数据库
CREATE DATABASE cs_db03 CHARACTER SET utf8 COLLATE utf8_bin;
# 校对规则 utf8_bin 区分大小写 默认utf8_general_ci 不区分大小写
show databases;
use 数据库名
drop database 数据库名
删库是很危险的操作,所以一般操作时要谨慎使用
删除分为逻辑删除和物理删除,
mysqldump -u 用户名 -p -B 数据库1 数据库2 数据库n > 文件名sql(含路径)
例如:
mysqldump -u root -p -B cs_db01 cs_db03 > d:\\bak.sql
Source 文件名.sql(含路径)
注意decimal类型,如果设置第二个参数为0时可以表示整数
char(4) //这个44表示字符数(最大255),不是字节数,不管中文还是字幕都是放四个,按字符计算。
varchar(4) //这个4表示字符数,不管时字母还是中文都是定义好的表的编码存放数据
共同点:不管是 中文还是英文字母,都是最多存放4个,是按照字符来存放的
char(4)是定长(固定的大小),就是说,即使插入'aa',也会占用分配的4个字符的空间
varchar(4)是边长(变化的大小),就是说,如果插入'aa'实际占用空间大小并不是4个字符,而是按照实际占用空间来分配
特别注意:
varchar本身还需要占用1~3个字节来记录存放内容长度 L(实际数据大小) + (1~3)字节
什么时候使用char,什么时候使用varchar
1.如果数据是定长,推荐使用char,比如md5的密码,邮编,手机号,身份证号码等等
2.如果一个字段的长度是不确定,我们使用varchar,比如留言,文章
查询速度:char > varchar
在存放文本时,也可以使用text数据结构,可以将text列视为varchar列,注意text不能有默认值,大小0~2^16字节
如果希望存放更多字符,可以选择
mediumtext 0~2^24 或者longtext 0~2^32
- 根据存储的实现:可以考虑用 varchar 替代 text,因为 varchar 存储更弹性,存储数据少的话性能更高。
- 如果存储的数据大于 64K,就必须使用到 mediumtext,longtext,因为 varchar 已经存不下了。
- 如果 varchar(255+) 之后,和 text 在存储机制是一样的,性能也相差无几。
- 需要特别注意 varchar(255) 不只是 255byte,实质上有可能占用的更多。
对表操作的前提是进入该数据库,所以操作表前使用use 数据库进入数据库
create table 表名 (
字段名1 类型,
字段名2 类型,
字段名3 类型,
...
);
例如:
创建actor表,包含id和name
CREATE TABLE actor ( -- 演员表
id INT,
name VARCHAR(32)
);
desc 表名;
drop table 表名;
insert into 表名 [(参数列表)] values(内容) [,(内容),(内容)...];
例如:
insert into actor (id, name) values(1,‘小明’);
解释第5点
字段是否可以为空时创建表的时候定义的,不为空可以在字段名类型后加not null
例如
create table t1 (
id int not null
);
看下面代码
insert into actor values('2', '小李');
代码不会报错,mysql会把字符串解析,如果是数字,直接替换,但是数字不可以解析为字符串。
update 表名 set 修改内容 where 条件;
例如
修改id为1的名字为小王
update actor set name = '小王' where id = 1;
delete from 表名 where 条件;
例如
删除id为1的记录
delete from actor where id = 1;
select 查询内容 from 表名[,表名,表名...] [限制条件];
例如
查询actor所有信息
select * from actor
查询actor的id,name(分别命名为号,姓名)
select 查询的字段名 [as] 别名 from 表名 [限制条件];
select id as '号', name as '姓名' from actor
as可以省略
查询actor的id(去除重复id)
select distinct 查询的字段名 form 表名 [限制条件];
select distinct id from actor;
查询actor的全部信息(升序排列)
select 查询的字段名 from 表名 order by 排列字段 [asc/desc];
select * from actor order by id asc;
比较运算符
运算符 | 说明 | ||||||||
>,>=,<,<= | 大于,大于等于,小于,小于等于 | ||||||||
= | 等于,NULL不安全,例如NULL = NULL 结果时NULL | ||||||||
<=> | 等于,NULL安全,例如NULL = NULL 结果时TRUE(1) | ||||||||
!=,<> | 不等于 | ||||||||
BETWEEN a0 END a1 | 范围分配,[a0,a1],如果 a0 <= value <= a1,返回TRUE | ||||||||
IN (option, ...) | 如果是option中任意一个,返回TRUE(1) | ||||||||
IS NULL | 是NULL | ||||||||
IS NOT NULL | 不是NULL | ||||||||
LIKE | 模糊查询,%表示任意多个(包括0个)任意字符; _表示任意一个字符 |
逻辑运算符
运算符 | 说明 | ||||||||
AND | 多个条件必须都为TRUE(1),结果才是TRUE(1) | ||||||||
OR | 任意一个条件为TRUE(1),结果为TRUE(1) | ||||||||
NOT | 条件为TRUE(1),结果为FALSE(0) |
注意:
1. WHERE条件可以使用表达式,但不能使用别名。
2. AND的优先级高于OR,在同时使用时,需要使用小括号()包裹优先执行的部分
count(*);//表示算出所有记录
count(列名1);//表示算出所有列名1不为NULL的总数
l例如
查询actor记录个数
select count(*) as '总记录数' from actor;
sum(统计的列名)
例如
查询actor表的id之和
select sum(id) from actor;
avg(统计的列名)
查询actor表的id平均值
select avg(id) from actor;
例如max(统计的列名)
查询actor表的id最大值
select max(id) from actor;
select 查询字段 from 表名 group by 分组字段;
例如
-- (1)显示每种岗位的雇员总数。平均工资
SELECT COUNT(empno),AVG(sal),job FROM emp GROUP BY job;#正确的
select 查询字段 from 表名 限制条件 limit start, rows;
例如
-- 分页查询
-- 按雇员的id号升序取出,每页显示3条记录,请分别显示 第1页,第2页,第2页
-- 第一页
SELECT * FROM emp
ORDER BY empno
LIMIT 0, 3;
-- 第二页
SELECT * FROM emp
ORDER BY empno
LIMIT 3, 3;
如果select语句同时包含有[where]group by,having,limit,order by 那么他们的顺序是:
[where]group by,having,orderby,limit
-- 思考题:显示公司员工名字和它的上级的名字
SELECT * FROM emp;
SELECT * FROM emp worker,emp boss;
SELECT worker.ename AS '员工', boss.ename AS '老板'
FROM emp worker,emp boss
WHERE worker.`mgr` = boss.`empno`;
-- 自连接的特点
-- 1. 把同一张表当作两张表使用
-- 2. 需要给表去别名 表名 表别名
-- 3. 列名不明确,可以指定列的别名 列名 as 列的别名
单列子查询
例如
请思考:如何显示与SMITH同一部门的所有员工?
/*
1. 先查询到 SMITH的部门号得到
2. 把上面的select 语句当做一个子查询来使用
*/
SELECT deptno
FROM emp
WHERE ename = 'SMITH';
SELECT *
FROM emp
WHERE deptno = (SELECT deptno
FROM emp
WHERE ename = 'SMITH');
查询和部门10的工作相同的雇员的
-- 名字、岗位、工资、部门号,但是不含10自己的信息
/*
1. 查询到10号部门有哪些工作
2. 把上面查询的结果当作子查询使用
*/
SELECT DISTINCT job
FROM emp
WHERE deptno = '20';
SELECT ename,job,sal,deptno
FROM emp
WHERE job IN (SELECT DISTINCT job
FROM emp
WHERE deptno = '10') AND deptno != 10;
多行子查询
如何显示工资比部门30的其中一个员工的工资高的员工的姓名、工资和部门号
常规思路
SELECT ename,sal,deptno
FROM emp
WHERE sal > (SELECT MIN(sal)
FROM emp
WHERE deptno = 30);#正确
上述代码其实可以用关键字ANY实现
SELECT ename,sal,deptno
FROM emp
WHERE sal > ANY(SELECT sal
FROM emp
WHERE deptno = 30);#正确
还有用关键字ALL实现
SELECT ename,sal,deptno
FROM emp
WHERE sal > ALL(SELECT sal
FROM emp
WHERE deptno = 30);#正确
多列子查询
例如
查找每个部门工资高于本部门平均工资的人的资料
SELECT AVG(sal) AS sal, deptno
FROM emp
GROUP BY deptno;
SELECT deptno, AVG(sal) AS sal
FROM emp
GROUP BY deptno;
SELECT ename, sal, avg_sal
FROM emp, (SELECT AVG(sal) AS avg_sal, deptno
FROM emp
GROUP BY deptno) temp
WHERE emp.`deptno` = temp.deptno AND emp.`sal` > temp.avg_sal;
-- 查找每个部门工资最高的人的详细资料
SELECT MAX(sal), deptno
FROM emp
GROUP BY deptno;
SELECT *
FROM emp
WHERE (sal, deptno) IN (SELECT MAX(sal) AS sal, deptno
FROM emp
GROUP BY deptno)
ORDER BY sal;#升序
使用临时表
SELECT emp.`sal`, temp.max_sal, emp.`deptno`
FROM emp, (SELECT MAX(sal) AS max_sal, deptno
FROM emp
GROUP BY deptno) temp
WHERE emp.sal = temp.max_sal AND emp.`deptno` = temp.deptno;
-- 显示每个部门的信息(包括:部门名,编号,地址)和人员数量
SELECT dname, dept.deptno, temp.aa AS '人数'
FROM dept, (SELECT COUNT(*) AS aa, deptno
FROM emp
GROUP BY deptno) temp
WHERE dept.`deptno` = temp.deptno;
-- 还有一种写法 表.* 表示将该表所有列都显示出来,可以简化sql语句
-- 在多表查询中,当多个表的列不重复时,才可以直接写列名
SELECT dname, temp.*
FROM dept, (SELECT COUNT(*) AS '人数', deptno
FROM emp
GROUP BY deptno) temp
WHERE dept.`deptno` = temp.deptno;
-- 表的复制
-- 为了对某个ssql语句进行效率测试,我们需要海量数据时,可以使用此法为表创建海量数据
表结构相同时
INSERT INTO my_tab_02
SELECT * FROM emp;
不同时则需要利用select查询子表赋值
INSERT INTO my_tab_01
(id, `name`, sal, job, deptno)
SELECT empno,ename,sal,job,deptno FROM emp;
SELECT ename,sal,job FROM emp WHERE sal > 2500;
SELECT ename,sal,job FROM emp WHERE job='MANAGER';
-- union all 就是将两个查询结果合并,不会去重
SELECT ename,sal,job FROM emp WHERE sal > 2500
UNION ALL
SELECT ename,sal,job FROM emp WHERE job='MANAGER';
-- union 就是将两个查询结果合并,会去重
SELECT ename,sal,job FROM emp WHERE sal > 2500
UNION
SELECT ename,sal,job FROM emp WHERE job='MANAGER';
-- 使用左连接
-- (显示所有人的成绩,如果没有成绩,也要显示该人的姓名和id号,成绩显示为空)
将两个表联合,找到公共数据
SELECT `name`,stu.`id`,grade
FROM stu,exam
WHERE stu.`id` = exam.`id`;
-- 改成左外连接(如果左表有的数据,右表没有要查询的数据,则置为NULL)
SELECT `name`,stu.`id`,grade
FROM stu LEFT JOIN exam
ON stu.`id` = exam.`id`;
-- 改成右外连接(如果右表有的数据,左表没有要查询的数据,则置为NULL)
SELECT `name`,stu.`id`,grade
FROM stu RIGHT JOIN exam
ON stu.`id` = exam.`id`;
1.primary key不能重复而且不能为null
2.一张表最多只能有一个主键,但可以是复合主键
3.主键的指定方式 有两种
直接在字段后指定:字段名 primary key
在表定义最后写 primary key(列名)
4.使用desc 表名,可以看到primary key的情况
5.实际开发中,每个表往往都会设计一个主键
CREATE TABLE t17
(id INT PRIMARY KEY, -- 表示id列是主键
`name` VARCHAR(32),
email VARCHAR(32));
CREATE TABLE t20
(id INT,
`name` VARCHAR(32),
email VARCHAR(32),
PRIMARY KEY (`name`)
);
CREATE TABLE t18
(id INT,
`name` VARCHAR(32),
email VARCHAR(32),
PRIMARY KEY (id, `name`) -- 这里就是复合主键
);
和primary key语法一样,有两种定义方式。
1.如果没有指定 not null,则unique字段可以有多个null
2.一张表可以有多个unique字段
foreign key(本表字段名) references 主表名(主键名或unique字段名)
-- 创建主表 my_class
CREATE TABLE my_class(
id INT PRIMARY KEY, -- 班级编号
`name` VARCHAR(32) NOT NULL DEFAULT '');
-- 创建 从表 my_stu
CREATE TABLE my_stu(
id INT PRIMARY KEY, -- 学生编号
`name` VARCHAR(32) NOT NULL DEFAULT '',
class_id INT, -- 学生所在班级的编号
-- 下面指定外键关系
FOREIGN KEY (class_id) REFERENCES my_class(id) -- 不能使用my_class.id
);
.1.外键指向的表的字段,要求是primary key 或者是 unique
2.表的类型是innodb,这样的表才支持外键
3.外键字段的类型要和主键字段的类型一致(胀肚可以不同)
4.外键字段的值,必须在主键字段中出现过,或者为null[前提是外键字段允许为null]
5.一旦建鲤主外键的关系,数据不能随意删除了
oracle和sql server均支持check,但是mysql5.7还不支持check,知错语法校验,但不会生效(mysql8生效)
在mysql中实现check的功能,一般是在程序中控制,或者通过触发器完成。
CREATE TABLE t23 (
id INT PRIMARY KEY,
`name` VARCHAR(32),
sex VARCHAR(6) CHECK (sex IN ('man', 'woman')),
sal DOUBLE CHECK ( sal > 1000 AND sal < 2000)
);
字段名 整形 primary key auto_increment
CREATE TABLE t25
(id INT PRIMARY KEY AUTO_INCREMENT,
email VARCHAR(32) NOT NULL DEFAULT '',
`name` VARCHAR(32) NOT NULL DEFAULT '');
下面是我练习时遇到的问题,以及找的资料:
sql自增长必须是主键吗?
mysql 只有主键能自动增长么 - 小程大序的猿 - 博客园
MySQL自增长可以设置多个吗?
MySQL如何同时自增自减多个字段_咔咔-的博客-CSDN博客_mysql 多个自增字段
索引的优势:查询速度块
底层实现:B+数
代价:
1.磁盘占用
2.对dml语句的效率影响
1.主键索引,主键自动的为主索引(类型Primary key)
2.唯一索引 (UNIQUE)
3.普通索引(INDEX)
4.全文索引(FULLTEXT)[适用于MyISAM]
1.
CREATE TABLE t26 (
id INT PRIMARY KEY,
`name` VARCHAR(32));
2.
CREATE TABLE t26 (
id INT,
`name` VARCHAR(32)),
PRIMARY KEY (id)
);
3.
CREATE TABLE t26 (
id INT,
`name` VARCHAR(32)),
);
ALTER TABLE t26 ADD PRIMARY KEY (id);
ALTER TABLE t26 ADD PRIMARY KEY id; 错误的
4.
CREATE TABLE t27 (
id INT,
`name` VARCHAR(32));
ALTER TABLE t27 ADD PRIMARY KEY index_id (id);
1.
CREATE TABLE t25 (
id INT UNIQUE,
`name` VARCHAR(32));
2.
CREATE TABLE t27 (
id INT,
`name` VARCHAR(32),
UNIQUE (id)
);
3.
CREATE TABLE t25 (
id INT,
`name` VARCHAR(32));
CREATE UNIQUE INDEX id_index ON t25 (id);
CREATE UNIQUE INDEX id_index ON t25 id; 错误的
注意
一下三种都是不可以的
ALTER TABLE t27 ADD UNIQUE id_index (id);
ALTER TABLE t27 ADD UNIQUE (id);
ALTER TABLE t27 ADD UNIQUE id;
1.
CREATE TABLE t27 (
id INT,
`name` VARCHAR(32)
);
CREATE INDEX id_index ON t27 (id);
2.
ALTER TABLE t27 ADD INDEX id_index (id);
一般情况是很少使用mysql的全文索引,开发中考虑:Solr和ElasticSearch(ES)
1.
删除索引
DROP INDEX id_index ON t27;
2.
删除主键索引
ALTER TABLE t27 DROP PRIMARY KEY;
1.
SHOW INDEX FROM t27;
2.
SHOW INDEXES FROM t27;
3.
SHOW KEYS FROM t27;
4.
不全
DESC t27;
前三种一样的效果
最后一个
先删除索引在添加索引
1.较频繁的作为查询条件字段应该创建索引
2.唯一性太差的字段不适合单独创建索引,即使频繁作为查询条件
3.更新非常频繁的字段不适合创建索引
4.不会出现在where子句中字段不该创建索引
什么是事务?
事务用于保证数据的一致性,它由一组相关的dml语句组成,改组的dml语句要么全部成功,要你全部失败(原子性)。
其实游戏中的回档就是事务的一种体现
经典例子:转账
小明要给小李转账100元
这是两个SQL语句,如果小明的语句执行成功,突然服务器崩了,那么小李的钱是没有的,但是小明失去了100元。
如何解救呢?
答案就是使用事务,在转账前开启事务。即初始保存点,如果发生意外返回保存点
-- 1. 创建一张测试表
CREATE TABLE t27
( id INT,
`name` VARCHAR(32));
-- 2. 开始事务
START TRANSACTION;
-- 3. 设置保存点
SAVEPOINT a;
-- 执行dml 操作
INSERT INTO t27 VALUES(100, 'tom');
DELETE FROM t27 WHERE id = 100;
SELECT * FROM t27;
SAVEPOINT b;
-- 执行dml操作
INSERT INTO t27 VALUES(200, 'jack');
SELECT * FROM t27;
-- 回退到 b
ROLLBACK TO b;
-- 继续回退 a
ROLLBACK TO a;
COMMIT;
1.如果不开启事务,默认情况下,dml操作时自动提交的,不能回滚
2.如果开启一个事务,你没有创建保存点,你可以执行rollback,默认就是回退到你事务开始的状态
3.你可以在这个事务中(还没有提交时),创建多个保存点,比如:savepoint aaa;执行dml,savepoint bbb
4.你可以在事务没有提交前,选择回退到哪个保存点
5.mysql的事务机制需要innodb的存储引擎还可以使用,myisam不好使
6.开始一个事务start transaction,set autocommit = off;
1.多个连接开启各自事务操作数据库中数据时,数据库系统要负责隔离操作,以保证各个连接在获取数据时的准确性。(通俗解释)
2.如果不考虑隔离性,可能引发如下问题:
脏读
不可重复度
幻读
当一个事务读取另一个事务尚未提交的修改时,产生脏读
同一查询在同一事务中多次进行,由于其他提交事务所做的修改或者删除,每次返回不同的结果集,此时发生不可重复读
同一查询在同一事务中多次进行,由于其他提交事务所作的插入操作,每次返回不同的结果集,此时发生幻读
查看当前会话隔离级别
SELECT @@tx_isolation;
查看系统当前隔离级别
SELECT @@global.tx_isolation;
设置当前会话隔离级别
SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE;
设置系统当前隔离级别
SET GLOBAL TRANSACTION ISOLATION LEVEL SERIALIZABLE;
设置默认隔离级别
SHOW ENGINES;
InnoDB
1.MyISAM不支持事务、也不支持外键,但其访问速度块,对事务完整性没有要求
2.InnoDB存储引擎提供具有提交、回滚和崩溃恢复能力的事务安全。但是比起MyISAM存储引擎,InnoDB写的处理效率差一下并且会占用更多的磁盘空间以保留数据和索引
3.MEMORY存储引擎使用存在内存中的内容来创建表。每个MEMORY表只实际对应一个磁盘文件。MEMORY类型的表访问速度非常快,因为它的数据是放在内存中的,并且默认使用HASH索引。但是一旦服务关闭,表中的数据就会丢掉,表的结构还在。
ALTER TABLE '表名' ENGINE = '存储引擎名';
1.视图是一个虚拟表,其内容由查询定义。同真实的表一样,视图包含列,其数据来自对应的真实表(基表)
2.视图和基表的关系
-- 创建一个视图emp_vview01,只能查询emp表的(empno,ename,job和deptno)信息
CREATE VIEW emp_view01
AS
SELECT empno,ename,job,deptno FROM emp;
视图其实还是一张表,表的操作同样适用于视图操作。
创建视图后,到数据库去看,对应视图只有一个视图结构文件(形式:视图名.frm)
视图没有.ibd文件,没有内容
-- 解读 (1) 'aaa'@'local' 表示用户的完成信息 'cuishuai' 用户名 'localhost' 登录的IP
-- (2) 123456 密码,但是注意 存放到 mysql.user表时,是password('123456') 加密后的密码
CREATE USER 'aaa'@'localhost' IDENTIFIED BY '123456';
SET PASSWORD = PASSWORD('abcdef');
-- 修改其他人的密码,需要权限
SET PASSWORD FOR 'aaa'@'localhost' = PASSWORD('123456');
DROP USER 'cuishuai'@'localhost';
-- 给 Powering 分配 查看 news 表和 添加news的权限
GRANT SELECT,INSERT
ON testdb.news
TO 'Powering'@'localhost';
GRANT UPDATE
ON testdb.news
TO 'Powering'@'localhost';
- 回收 Powering用户在 testdb.news 表的所有权限
REVOKE SELECT,UPDATE,INSERT ON testdb.news FROM 'Powering'@'localhost';
REVOKE ALL ON testdb.news FROM 'Powering'@'localhost';
-- 在创建用户的时候,如果不指定Host,则为%,%表示所有IP都有连接权限
-- create user xxx;
CREATE USER jack; -- 等价 CREATE USER ‘jack’@‘%’;
SELECT `host`,`user` FROM mysql.user;
-- 你也可以这样指定
-- create user 'xxx'@'192.168.1.%' 表示 xxx用户在 192.168.1.*的ip可以登录mysql
CREATE USER 'tom'@'192.168.%';
-- 在删除用户的时候,如果 host 不是 %,需要明确指定 '用户'@'host值'
DROP USER jack; -- 默认就是 DROP USER 'jack'@'%'
DROP USER 'tom'@'192.168.%';
最近JDBC也学完了,JDBC绝对是纯干货,我会把学习总结做出来的,我先缓缓,2+4个小时写完文章太肝了.。