1.DQL:数据查询语言(凡是带有select关键字的都是查询语句)
2.DML:数据操作语言(凡是对表当中的数据进行增删改的都是DML)
3.DDL:数据定义语言
4. TCL:是事务控制语言
4. DCL:数据控制语言
老杜p11导入表的链接:https://pan.baidu.com/s/13olV5qKdwzQRzoocl_Utgg
提取码:JIUQ
导入方式:source 文件地址(source D:\course\03-MySQL\document\bjpowernode.sql)
导出方式:mysqldump bjpowernode>D:\bjpowernode.sql -uroot -p201408181p; (要先退出登录)
注意:路径中不要有中文!!!!
1.怎么查看表中的数据呢?
2.不看表中的数据,只看表的结构,有一个命令:desc 表名;
3.select version();查看mysql的版本号
4.select database查看使用的那个数据库
5.mysql不见";"不执行";"表示结束
7.\c终止一条命令的输入
8.mysql不区分大小写
9.select 字段名 from 表名 简单查询,查询两个字段或着多个字段用“,”隔开,如果查询所有字段可以都写上,也可以使用*
10.给查询的列起别名,只是将查询的结果列名显示为你所修改的,原列明不变.
条件查询不是将表中所有数据都查出来,而是查询出符合条件的。
语法格式:
select 字段,字段2,字段3...
from 表名
where 条件
= 等于
where sal = 800;
where ename = 'smith' ;
<>或!=不等于 >大于 >=大于等于 <小于<= 小于等于
between ... and ...两个值之间,等同于>= and <=
where sal between 800 and 5000
is null 为 null (is not null 不为空)
where comm is null;
where comm is not null
and 并且
where sal >= 800 and sal <= 5000
or或者
where sal = 800 or sal = 5000
where sal > 800 and (deptno = 20 or deptno = 30)
in包含,相当于多个or(not in不在这个范围内)
where sal in(800, 3000);
where ename in('smith', 'allen');
where sal not in(800,3000);
not 可以取非,主要用在is或者in中
like like称为模糊查询,支持%或下划线匹配
1.对查询的数据进行排序:select 显示的字段名
from 表名
order by 排序的字段名;
例如:
SELECT ename,sal
FROM emp
ORDER BY sal;
2.默认的排序是升序排序,如果想指定降序:select 显示的字段名
from 表名
order by 排序的字段名 desc;
指定升序: select 显示的字段名
from 表名
order by 排序的字段名 asc;
3.如果给多个字段进行排序:select 显示的字段名
from 表名
order by 排序的字段名1,排序的字段名2;
(先进行字段1的排序,只有字段1的排序遇到相等的时才会进行字段2的排序)
查询工资在1250到3000的人进行倒叙排序:
select ename,sal
from emp
where sal between 1250 and 3000
order by sal desc;
以上语句的执行顺序:
第一步:from
第二步:where
第三步:select
第四步:order(排序总是在最后执行)
数据处理函数被称为单行函数,特点是一个输入对应一个输出
常见的单行处理函数有?
1.lower转换小写 在这里插入代码片
2.upper转换大写
3.substr取子串(substr(被截取的子串,起始下标,截取长度))
获取名字首字母为A的员工名字?
SELECT ename
FROM emp
WHERE SUBSTR(ename, 1, 1) = 'A';
4.length取长度 select length(ename) from emp;
5.concat函数进行字符串拼接 select concat(ename,empon) from emp;6.trim 去空格
SELECT *
FROM emp
WHERE ename = TRIM(' KING');
7.str_to_date 将字串转化为日期
8.date_format 设置千分位
9.round生成随机数
select round(rand()*10,0) from emp;
SELECT ROUND(1234.567) AS result FROM emp;
select round(1234.567,1) as result from emp
select round(1234.567,2) as result from emp
select round(1234.567,-1) as result from emp
10.ifnull可以将null转化为具体值
注意:只要null参与运算,最总结果一定是null,为了避免这个现象,需要ifnull函数
ifnull函数用法:ifnull(数据,被当作哪个值)
select ename ,(sal + ifnull(comm,0)) * 12 as yearsal from emp;
11.case...when..then...when...then...else...end
当员工的工作岗位是MANAGER的时候,发工资上调10%,当工作岗位是SALESMAN的时候,工资上调50%,其他正常(只修改查询结果不修改数据库)
select ename ,job,(case job when 'MANAGER' then sal*1.1 when 'SALESMAN' then sal*1.5 else sal end) as newsal
from emp;
select 后面可以跟某个表的字段名(可以等同看作变量名),也可以跟字面量/字面值(数据)
select 21000 as num from dept;
select round(1234.567,0) as result from emp;
分组函数在使用时注意哪些?
select ...
from ...
group by ...
select ...
from ...
where ...
group by ...
order by ...
1.from
2.where
3.group by
4.select
5.order by
select deptno,max(sal)
from emp
group by deptno
having max(sal) > 3000;
distinct 只能出现在在有字段的最前方,目的是去重,当出现在两个字 段前面时表示两个字段联合去重。
SELECT DISTINCT job,deptno
FROM emp;
笛卡尔现象
1.sql92语法:
select ename,danme
from emp,dept
where emp.deptno = dept.deptno;
最终查询的结果条数是14条,但是匹配次数没有减少,还是匹配了56次只不过进行了4选1
这样写 就会减少匹配次数
select emp.ename,dept.danme
from emp,dept
where emp.deptno = dept.deptno;
为了提高效率我们可以给表起别名
select e.ename,d.dname
from emp e,dept d
where e.deptno = d.deptno;
当然匹配次数越多效率越低,我们应尽量减少匹配次数
2. sql99语法:
select e.ename,d.dname
from emp e
join dept d
on e.deptno = d.deptno;
select e.ename,d.dname
from emp e
join dept d
on e.deptno = d.deptno;
select e.name,e.sal,s.grade
from emp e
join salgrade s
on e.sal between s.losal and s.hisal;
自链接就是把一个数据库表当作两个来看,自己连接自己
1.左外连接:
select e.name,d.name
from dept d
left join emp e
on e.deptno = d.deptno;
2.右外连接
select e.name,d.name
from emp e
right join dept d
on e.deptno = d.deptno;
语法:
select ...
from a
join b
on a和b的连接条件
join c
on a和c的连接条件
join d
on a和d的连接条件
案例:找出每个员工的部门名称以及工资等级,上级领导,要求显示员工名,领导名,部门名,薪资,薪资等级
SELECT e.ename,e.sal,d.dname,s.grade,l.ename
FROM emp e
JOIN dept d
ON e.deptno = d.deptno
JOIN salgrade s
ON e.sal BETWEEN s.losal AND s.hisal
LEFT JOIN emp l
ON e.mgr = l.empno;
1.where子句中的子查询
找出比最低工资高的人员的姓名和工资?
sql
SELECT ename,sal FROM emp WHERE sal > (SELECT MIN(sal) FROM emp)
2.from语句上查询
找出每个岗位的平均工资的薪资等级?
SELECT t.*,s.grade
FROM (SELECT job,AVG(sal) AS avgsal FROM emp GROUP BY job) t
JOIN salgrade s
ON t.avgsal BETWEEN s.losal AND s.hisal;
注意:表上的名字不要带关键字否则在查询表上的名字会查询关键字的作用而不会查询数据导致报错,起别名可以解决。
3.select后的子查询(了解,用其他方法更好)
找出每个员工的部门名,要求显示员工名、部门名?
sql
SELECT e.ename,(SELECT d.dname FROM dept d WHERE d.deptno = e.deptno) AS dname
FROM emp e;
案例:查询工作岗位是MANAGER和SALESMAN的员工?
常规方式:
SELECT ename
FROM emp
WHERE job IN('MANGER','SALESMAN');
使用union:
SELECT ename FROM emp WHERE job = 'manager'
UNION
SELECT ename FROM emp WHERE job = 'SALESMAN';
union的效率会高一些,对于表连接来说每链接一次新表匹配的次数满足笛卡尔积会成倍的翻,但是union可以减少匹配次数
使用union的注意事项:
SELECT ename,job FROM emp WHERE job = 'SALESMAN'
UNION
SELECT ename,sal FROM emp WHERE job = 'MANAGER';
SELECT ename,job FROM emp WHERE job = 'SALESMAN'
UNION
SELECT ename,sal FROM emp WHERE job = 'MANAGER';
limit是将查询结果集的一部分取出来,通常在分页查询上使用
案例:按照薪资降序,取出排名在前五名的员工?
SELECT ename
FROM emp
ORDER BY sal DESC
LIMIT 0,10;
注意:MYSQL上limit是在order by后执行的
案例:取出工资在3~5名的员工?
SELECT ename
FROM emp
ORDER BY sal DESC
LIMIT 2,3;
如果我们每页几个数据而查询哪一页怎么写呢?
例如:
总结:
select ...
from...
where...
group by ...
having...
order by...
limit...
执行顺序:
1. 查询各个部门薪资最高的人
SELECT e.ename,t.*
FROM emp e
JOIN (SELECT deptno,MAX(sal) AS maxsal FROM emp GROUP BY deptno) t
ON t.deptno = e.deptno AND t.maxsal = e.sal
2. 哪些人的薪资在部门平均水平之上
SELECT ename,sal,t.*
FROM emp e
JOIN (SELECT deptno,AVG(sal) AS avgsal FROM emp GROUP BY deptno) t
ON e.sal > t.avgsal AND e.deptno = t.deptno;
3. 取得部门中(所有人的)平均的薪水等级(老师题意应该有问题下面题是老师问题答案)
SELECT s.grade,t.*
FROM salgrade s
JOIN (SELECT AVG(sal) AS avgsal FROM emp GROUP BY deptno) t
ON t.avgsal BETWEEN s.losal AND s.hisal;
取得部门所有人薪水等级的平均值
SELECT e.deptno,AVG(s.grade)
FROM emp e
JOIN salgrade s
ON e.sal BETWEEN s.losal AND s.hisal
GROUP BY e.deptno;
4. 不准用组函数(max),取得最高薪水
SELECT ename,sal
FROM emp
ORDER BY sal DESC
limit 1;
SELECT sal
FROM emp
WHERE sal NOT IN (SELECT DISTINCT a.sal FROM emp a JOIN emp b ON a.sal < b.sal);
5. 取得平均薪水最高部门的部门编号(给出两种方案)
SELECT deptno,AVG(sal) AS avgsal
FROM emp
GROUP BY deptno
ORDER BY avgsal DESC
LIMIT 1;
SELECT deptno,AVG(sal) AS avgsal
FROM emp
GROUP BY deptno
HAVING avgsal = (SELECT MAX(t.avgsal) AS maxsal FROM emp e,(SELECT deptno,AVG(sal) AS avgsal FROM emp GROUP BY deptno) t);
6. 取得平均薪水最高部门的部门名称
SELECT t.avgsal,d.dname
FROM dept d
JOIN (SELECT deptno,AVG(sal) AS avgsal FROM emp GROUP BY deptno ORDER BY avgsal DESC LIMIT 1) t
ON t.deptno = d.deptno;
7.求部门平均薪水等级最低的部门名称
SELECT d.dname,t.*
FROM dept d
JOIN (SELECT b.mingrade,a.deptno FROM (SELECT MIN(t.sgrade) AS mingrade FROM (SELECT s.grade AS sgrade,t.* FROM salgrade s JOIN(SELECT deptno,AVG(sal) AS avgsal FROM emp GROUP BY deptno) t ON t.avgsal BETWEEN s.losal AND s.hisal) t) b JOIN (SELECT s.grade AS sgrade,t.* FROM salgrade s JOIN(SELECT deptno,AVG(sal) AS avgsal FROM emp GROUP BY deptno) t ON t.avgsal BETWEEN s.losal AND s.hisal) a WHERE b.mingrade = a.sgrade) t
ON d.deptno = t.deptno;
8. 取得比普通员工(员工代码没有在mgr字段上出现的)的最高薪水还要高的领导人姓名
SELECT e.sal,e.ename
FROM emp e
JOIN (SELECT MAX(sal) maxsal FROM emp WHERE empno NOT IN(SELECT DISTINCT mgr FROM emp WHERE mgr IS NOT NULL)) t
WHERE e.sal > t.maxsal;
9. 取得薪水最高的前五名
SELECT sal
FROM emp
ORDER BY sal DESC
LIMIT 5;
10.取得薪水最高的第六到第十名
SELECT sal
FROM emp
ORDER BY sal DESC
LIMIT 5,5;
11.取得最后入职的五名员工
SELECT ename,hiredate
FROM emp
ORDER BY hiredate DESC
LIMIT 5;
12.取得每个薪资等级有多少个员工
SELECT s.grade,COUNT(*)
FROM emp e
JOIN salgrade s
ON e.sal BETWEEN s.losal AND s.hisal
GROUP BY s.grade;
13.面试题
有三个表s(学生表),c(课程表),sc(学生选课表)
s(sno,sname)代表(学号和姓名)
c(cno,cname,cteacher) 代表(课号,课名,教师)
sc(sno,cno,scgrade)代表(学号,课号,成绩)
问题:
1.找出没选过''黎明''老师的所有学生姓名
SELECT *
FROM s
WHERE sname NOT IN(SELECT a.sname FROM s a JOIN (SELECT sno FROM sc WHERE cno = (SELECT cno FROM c WHERE cteacher = '黎明')) t ON a.sno = t.sno);
2.列出两门以上(含两门)不及格的学生姓名及成绩
SELECT s.sname,t.cgrade
FROM s s
JOIN (SELECT a.sno,b.countsno,a.cgrade FROM sc a JOIN (SELECT sno,COUNT(sno) AS countsno FROM sc WHERE cgrade < 60 GROUP BY sno) b ON b.countsno = 2 AND a.sno = b.sno) t
ON s.sno = t.sno;
3.即学过1号课程又学过2号课程的所有学生的姓名
SELECT s.sname,s.sno
FROM s s
JOIN (SELECT a.sno FROM (SELECT sno FROM sc WHERE cno = 1) a JOIN (SELECT sno FROM sc WHERE cno = 2) b ON a.sno = b.sno) t
WHERE s.sno = t.sno;
14.列出所有员工及领导名字
SELECT a.ename,b.ename
FROM emp a
LEFT JOIN emp b
ON a.mgr = b.empno;
15.列出受雇日期早于其直接领导员工的编号,姓名,部门名称
SELECT a.ename,a.deptno,a.empno
FROM emp a
JOIN emp b
ON a.mgr = b.empno AND a.hiredate < b.hiredate;
16.列出部门名称和这些部门的员工信息,同时列出那些没有员工的部门
SELECT d.dname,e.*
FROM emp e
RIGHT JOIN dept d
ON d.deptno = e.deptno;
17.列出有五个员工的所有部门
SELECT deptno
FROM emp e
GROUP BY e.deptno
HAVING COUNT(*)> 4;
18.列出薪金比SMITH多的所有员工信息
SELECT *
FROM emp
WHERE sal > (SELECT sal FROM emp WHERE ename = 'SMITH');
19.列出所有"CLERK" (办事员)的姓名及其部门名称,部门的人数
SELECT a.ename,a.dname,b.*
FROM (SELECT e.ename,d.dname,e.deptno FROM emp e JOIN dept d ON e.deptno = d.deptno AND e.job = 'clerk') a
JOIN (SELECT deptno,COUNT(*) FROM emp GROUP BY deptno) b
ON a.deptno = b.deptno;
20.列出最低薪资大于1500的各个工作及从事此工作的全部雇佣人数(注意审题)
SELECT COUNT(*),job FROM emp GROUP BY job HAVING MIN(sal) > 1500;
21.列出在部门''SALES"<销售部>工作的员工的姓名,假定不知道销售部的部门编号
SELECT e.ename
FROM emp e
JOIN (SELECT deptno FROM dept WHERE dname = 'SALES') t
ON e.deptno = t.deptno;
22.列出薪资高于公司平均薪资的所有员工,所在部门,上级领导,雇员的薪资等级
SELECT ename,d.dname,s.grade
FROM (SELECT ename,deptno,sal FROM emp WHERE sal > (SELECT AVG(sal) FROM emp)) t
JOIN dept d
ON t.deptno = d.deptno
JOIN salgrade s
ON t.sal BETWEEN s.losal AND s.hisal;
23.列出与''SCOTT"从事相同工作的所有员工及部门名称
SELECT e.ename,d.dname
FROM emp e
JOIN dept d
ON e.deptno = d.deptno
WHERE job = (SELECT job FROM emp WHERE ename = 'scott') AND e.ename != 'scott';
24.列出薪金等于部门30中员工的薪金的其他员工的姓名和薪金
SELECT ename,sal
FROM emp
WHERE sal IN(SELECT sal FROM emp WHERE deptno = 30) AND deptno != 30;
25.列出薪金高于在部门30工作的所有员工的薪金的员工姓名和薪金、部门名
SELECT e.ename,e.sal,d.dname
FROM emp e
JOIN dept d
ON e.deptno = d.deptno
WHERE sal > (SELECT MAX(sal) FROM emp WHERE deptno = 30);
26.列出在每个部门工作的员工数量,平均薪资和平均服务期限
SELECT a.*,t.times
FROM (SELECT deptno,COUNT(*),AVG(sal) FROM emp GROUP BY deptno) a
JOIN (SELECT deptno,AVG(TIMESTAMPDIFF(YEAR,hiredate,NOW())) AS times FROM emp GROUP BY deptno) t
ON a.deptno = t.deptno;
在MySQL如何计算两个日期的差?
间隔类型:
27.列出所有员工的姓名,部门名和工资
SELECT e.ename,d.dname,e.sal
FROM emp e
JOIN dept d
ON e.deptno = d.deptno;
28.列出所有部门的详细信息和人数
SELECT d.*,t.coun
FROM dept d
LEFT JOIN (SELECT deptno,COUNT(*) coun FROM emp GROUP BY deptno) t
ON d.deptno = t.deptno;
29.列出各种工作的最低工资及从事此工作的雇员姓名
SELECT e.ename,t.minsal
FROM emp e
JOIN (SELECT job,MIN(sal) minsal FROM emp GROUP BY job) t
ON e.job = t.job AND e.sal = t.minsal;
30.列出各个部门的MANAGER(领导)的最低薪资
SELECT deptno,MIN(sal)
FROM emp
WHERE job = 'MANAGER'
GROUP BY deptno;
31.列出所有员工的年工资,按年薪从低到高排列
SELECT ename,(sal+IFNULL(comm,0))*12 AS yearsal
FROM emp
ORDER BY yearsal;
32.求出员工领导的薪水超过3000的员工名称与领导
SELECT t.ename,e.ename
FROM emp e
JOIN (SELECT ename,mgr FROM emp WHERE mgr IS NOT NULL) t
ON e.empno = t.mgr AND e.sal > 3000;
33.求出部门名称中,带's'字符的部门员工的工资合计,部门人数
SELECT SUM(sal),COUNT(e.ename)
FROM emp e
RIGHT JOIN dept t
ON t.deptno = e.deptno AND t.dname LIKE '%s%'
GROUP BY e.deptno;
34.给任职日期超过30年的员工加薪10%
UPDATE emp
SET sal = sal*1.1
WHERE TIMESTAMPDIFF(YEAR,hiredate,NOW()) > 30;
create table 表名(
字段名1 数据类型,
字段名2 数据类型,
字段名3 数据类型,
字段名4 数据类型
);
常见数据类型:
drop table 表名; //当表不存在就会报错
drop table if exists 表名; 这张表存在就删除
语法格式:insert into 表名(字段1,字段2,字段3)value (值1,值2,值3);
insert语句执行成功必然会多一条记录,没写默认值为null
同时插入多条记录也是可以的
语法格式:insert into 表名(字段1,字段2,字段3)value (值1,值2,值3), (值1,值2,值3);
数据库命名规范:所有标识符小写,单词和单词之间下划线进行链接
1.数字格式化:format(数字,'格式')
2.str_to_date('字符串日期','日期格式'): 将字符串varchar类型转化为date类型,通常在insert上
mysql日期格式:
INSERT INTO t_student(birth) VALUES(STR_TO_DATE('01-09-2001','%d-%m-%Y'));
如果格式为(年-月-日)后面可以不写格式
INSERT INTO t_student(birth) VALUES('1990-09-01');
3.date_format(日期类型数据,'日期格式'):将date类型转化为具有一定格式的varchar字符串类型
通常使用查询日期时,将展示的日期为varchar类型
SELECT DATE_FORMAT(birth,'%Y/%m/%d') FROM t_student;
如果不改变格式查询日期:
SELECT birth FROM t_student;
如果想输入当前时间直接 now()
语法格式:update 表名 set 字段名1==值1,字段名2==值2,字段名3==值3 where 条件
注意:没有条件限制就会改变所有数据
语法格式:delectd from 表名 where 条件
注意:没有条件限制就会删除所有数据
删除数据空间不会释放,只是把数据变成空,支持回滚后悔数据可以回复但效率比较低
语法格式:create table 表名 as 查询的结果
语法格式:insert into 表名 查询结果
语法格式:truncate table 表名(DDL)
删除效率比较高,表被一次截断,物理删除,但不支持回滚
删的是数据表结构仍然在
什么是对表结构的修改?
我们在实际开发中一般不会对表结构进行修改,一旦修改表结构对应的Java代码会进行大量修改成本很高,所以我们不需要掌握,如果真的需要直接用工具,我们在Java上不会修改表
在创建表时我们需要给表中的字段增加一些约束,来保证表数据的完整性,有效性
非空约束 not null
唯一性约束 unique
主键约束 primary key(简称pk)
外键约束 foreign key (简称fk)
检查约束 check(MYSQL不支持,Orace支持)
约束的字段不能为空
案例:
CREATE TABLE t_vip(
id INT,
NAME VARCHAR(32) NOT NULL
);
INSERT INTO t_vip(id,NAME) VALUES(1,'black');
INSERT INTO t_vip(id,NAME) VALUES(1);
报错信息:Column count doesn't match value count at row 1
没有表级约束
约束字段不能重复但是可以为null
CREATE TABLE t_vip(
id INT,
NAME VARCHAR(32) NOT NULL,
email VARCHAR(255) UNIQUE
);
INSERT INTO t_vip(id,NAME,email) VALUES(1,'black','[email protected]');
INSERT INTO t_vip(id,NAME,email) VALUES(2,'blank','[email protected]');
INSERT INTO t_vip(id,NAME,email) VALUES(3,'black','[email protected]');
报错信息:Duplicate entry '[email protected]' for key 'email'
CREATE TABLE t_vip(
id INT,
NAME VARCHAR(32),
email VARCHAR(255),
UNIQUE(NAME,email)
);
INSERT INTO t_vip(id,NAME,email) VALUES(1,'black','[email protected]');
INSERT INTO t_vip(id,NAME,email) VALUES(2,'cool','[email protected]');
INSERT INTO t_vip(id,NAME,email) VALUES(3,'cool','cool@');
INSERT INTO t_vip(id,NAME,email) VALUES(4,'yellow','cool');
INSERT INTO t_vip(id,NAME,email) VALUES(5,'cool','cool');
INSERT INTO t_vip(id,NAME,email) VALUES(6,'pink','[email protected]');
INSERT INTO t_vip(id,NAME,email) VALUES(7,'[email protected]','pink');
INSERT INTO t_vip(id,NAME,email) VALUES(8,'green','green');
INSERT INTO t_vip(id,NAME,email) VALUES(9,'green','green');
错误信息:Duplicate entry 'green-green' for key 'NAME'
只有加入id为9时才出现错误,只有加入两组数据的name和email都相同时才报错
这个约束是表级别约束
CREATE TABLE t_vip(
id INT,
NAME VARCHAR(32) NOT NULL UNIQUE
);
DESC t_vip;
INSERT INTO t_vip(id,NAME) VALUES(1,'black');
INSERT INTO t_vip(id,NAME) VALUES(2,'black');
INSERT INTO t_vip(id,NAME) VALUES(3);
在mysql中如果一个字段同时被not null和unique同时约束的话,该字段自动变成主键字段(Oracle不是这样)
什么是主键以及它的作用?
主键值是每一行记录的唯一标识
任何一张表都要有主键,没有主键表无效
一张表的主键约束只能添加一个
主键一般都是数字是定长的不建议varchar来做主键
主键的特征:not null+unique(主键值不能是空也不能重复)
DROP TABLE t_vip;
CREATE TABLE t_vip(
id INT PRIMARY KEY,
NAME VARCHAR(255)
);
INSERT INTO t_vip(id,NAME) VALUES(1,'zhangsan');
INSERT INTO t_vip(id,NAME) VALUES(2,'lisi');
INSERT INTO t_vip(id,NAME) VALUES(2,'baiye');
错误信息:Duplicate entry '2' for key 'PRIMARY'
也可以这样写表示表级约束,前面是列级约束
CREATE TABLE t_vip(
id INT,
NAME VARCHAR(255),
PRIMARY KEY(id)
);
表级约束主要给多个字段起来添加约束
id和name联合起来做主键是复合主键,但在实际开发中主键存在的意义就是这行记录的身份证号只要意义达到即可,单一主键可以做到复合主键比较复杂不建议使用
CREATE TABLE t_vip(
id INT,
NAME VARCHAR(255),
PRIMARY KEY(id,NAME)
);
INSERT INTO t_vip(id,NAME) VALUES(1,'zhangsan');
INSERT INTO t_vip(id,NAME) VALUES(2,'lisi');
INSERT INTO t_vip(id,NAME) VALUES(2,'baiye');
INSERT INTO t_vip(id,NAME) VALUES(2 ,'baiye');
主键除了单一主键和复合主键还可以这样进行分类?
在实际开发中自然主键使用较多,主键不重复就好不需要有意义,主键一但和业务挂钩那么业务变动可能会影响主键值
在mysql中有一种机制可以帮助我们自动维护一个主键值
CREATE TABLE t_vip(
id INT PRIMARY KEY AUTO_INCREMENT,
NAME VARCHAR(255)
);
INSERT INTO t_vip(NAME) VALUES('zhangsan');
INSERT INTO t_vip(NAME) VALUES('lisi');
INSERT INTO t_vip(NAME) VALUES('baiye');
INSERT INTO t_vip(NAME) VALUES('baiye');
AUTO_INCREMENT表示自增,从1开始
当两张表有父子关系时,子表上与父表关联的字段为保证数据有效需要加外键约束,被引用的字段可以不是主键可以为null但是必须具有唯一性
CREATE TABLE t_class(
classno INT PRIMARY KEY,
classname VARCHAR(255)
);
CREATE TABLE t_student(
NO INT PRIMARY KEY AUTO_INCREMENT,
NAME VARCHAR(255),
cno INT,
FOREIGN KEY(cno) REFERENCES t_class(classno)
);
INSERT INTO t_class(classno,classname) VALUES(1001,'商丘一高');
INSERT INTO t_class(classno,classname) VALUES(1002,'商丘二高');
INSERT INTO t_student(NAME,cno) VALUES('liuqi',1001);
INSERT INTO t_student(NAME,cno) VALUES('fangao',1001);
INSERT INTO t_student(NAME,cno) VALUES('feng',1002);
INSERT INTO t_student(NAME,cno) VALUES('bailan',1002);
INSERT INTO t_student(NAME,cno) VALUES('bailan',1003);
错误信息:Cannot add or update a child row: a foreign key constraint fails (`wasd`.`t_student`, CONSTRAINT `t_student_ibfk_1` FOREIGN KEY (`cno`) REFERENCES `t_class` (`classno`))
存储引擎是mysql数据库独有的术语,Oracle数据库有但不叫这个名字
存储引擎是一个表存储或组织数据的方式,不同的存储引擎表存储数据方式不同
ENGINE来指定存储引擎
CHARSET来指定这张表的字符编码方式
mysql默认的存储引擎是InnoDB
mysql默认的字符编方式是utf-8
CREATE TABLE t_vip(
id INT PRIMARY KEY AUTO_INCREMENT,
NAME VARCHAR(255)
))ENGINE=INNODB DEFAULT CHARSET=utf8;
INSERT INTO t_vip(NAME) VALUES('白也');
INSERT INTO t_vip(NAME) VALUES('柳七');
INSERT INTO t_vip(NAME) VALUES('张三');
INSERT INTO t_vip(NAME) VALUES('心悦');
INSERT INTO t_vip(NAME) VALUES('琼落');
INSERT INTO t_vip(NAME) VALUES('十六');
show engines
mysql支持九大存储引擎,5.7.25支持八个,每个版本支持的不同
1.InnoDB
默认的存储引擎,也是一个重量级存储引擎
最主要的特点支持事务保证数据安全,效率较低不能压缩不能转化为只读
主要特征:
2.MyISAM
他管理的表具有以下特征:
使用三个文件表示每个表:
格式文件:存储表结构的定义
数据文件:存储表行的内容
索引文件:存储表上的索引
可以转换为压缩,只读表节省空间
对一张表来说只要是主键,或者加有unique约束的字段会自动创建索引
3.MEMORY
使用memory存储引擎的表其数据存储在内存上,且行的长度固定不能包含text和blob字段,这两个特点使memory存储引擎非常快,但一关机数据消失
一个事务其实就是一个完整的业务逻辑
只有这三个增删改语句才有事务,只要涉及增删改数据安全就是第一位
在事务执行过程中。每一条DML的操作都会记录到“事务性活日志文”中
在事务执行过程中我们可以提交事务也可以回滚事务
提交事务:清空事务性活动的日志文件,将数据全部彻底持久化到数据库表中,标志着事物成功结束
回滚事务:清空事务性活动的日志文件,将所有的DML操作全部撤销,标志着事务失败结束
提交事务:commit
回滚事务:rollback
mysql默认情况下自动提交事务,那怎么自己提交事务呢?
START TRANSACTION;
SELECT * FROM dept;
START TRANSACTION;
INSERT INTO dept VALUE(50,'jjj','yyyy');
SELECT * FROM dept;
ROLLBACK;
SELECT * FROM dept;
事务一旦提交回滚就没有作用
SELECT * FROM dept;
START TRANSACTION;
INSERT INTO dept VALUE(50,'jjj','yyyy');
SELECT * FROM dept;
COMMIT;
ROLLBACK;
SELECT * FROM dept;
A.原子性
C.一致性
I.隔离性
D.持久性
这种隔离级别可能会出现脏读现象(Dirty read)我们称之为读到了脏数据,一般这种隔离级别都是在理论上,大多数的数据库的隔离级别都是二档起步
这种隔离级别解决了脏读现象,但是不可重复读取数据就是每次提交后读取的数据都不一样
Oracle数据库默认的隔离级别就是read committed
解决了不可重复读取的问题,但可能会出现幻影读每次读取的数据都是幻象,MySQL默认的隔离级别就是这个
每次读取的数据都是最真实的,也是效率最低的
查看隔离级别:
SELECT @@tx_isolation;
设置全局的隔离级别:
SET GLOBAL TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
在mysql上索引是B-Tree数据结构,遵循左小右大的原则,采用中序遍历的方式进行遍历取数据
mysql查询方面主要有两种方式:
索引是所有数据库优化的重要手段,优化时优先考虑索引
不要随意添加索引 ,因为索引也是需要维护的,太多会降低系统性能
建议通过unique约束的字段进行查询或主键查询使用索引效率比较高
创建索引:create index 索引的名字 on 添加索引的位置;
CREATE INDEX emp_ename_index ON emp(ename);
删除索引:drop index 索引的名字 on 表名;
DROP INDEX emp_ename_index ON emp;
explain select * from 表名 where 列名 = 条件;
explain select * from emp where ename = 'king';
EXPLAIN SELECT * FROM emp WHERE ename = '%T';
EXPLAIN SELECT * FROM emp WHERE ename = 'king' OR job = 'manager';
CREATE INDEX emp_ename_index ON emp(sal,job);
EXPLAIN SELECT * FROM emp WHERE job = 'manager';
索引失效
EXPLAIN SELECT * FROM emp WHERE sal = 800;
索引生效
EXPLAIN SELECT * FROM emp WHERE sal+100 = 900;
EXPLAIN SELECT * FROM emp WHERE LOWER(ename) = 'smith';
单一索引:一个字段添加索引
复合索引:多个字段联合添加索引
主键索引:主键上添加索引
唯一性索引:具有unique约束的字段上添加索引
注意:唯一性较弱的字段上添加索引意义不大,唯一性越强效率越高
什么是视图?
view:站在不同的角度去看待同一份数据
创建视图:CREATE VIEW 命名 AS DQL语句;
CREATE VIEW dept2_view AS SELECT * FROM dept2;
删除视图:DROP VIEW 名字;
DROP VIEW dept2_view;
用视图做什么?·
我们可以面向视图对象进行增删改查,对视图对象的增删改查会导致原表被操作
CREATE TABLE dept2 AS SELECT * FROM dept;
CREATE TABLE emp2 AS SELECT * FROM emp;
SELECT * FROM emp2;
CREATE VIEW dept2_emp2_view AS SELECT e.ename,e.sal,d.dname FROM emp2 e JOIN dept2 d ON d.deptno = e.deptno;
DROP VIEW dept2_emp2_view;
SELECT * FROM dept2_emp2_view;
UPDATE dept2_emp2_view SET sal = 1000 WHERE ename = 'smith';
emp2上smith的工资也被修改为1000了
第一范式:要求任何一张表必须有主键每一个字段,原子性不可再分
第二范式:建立在第一范式基础之上,要求非主键字段必须完全依赖主键,不要产生部分依赖。
第三范式:建立在第二范式基础之上,要求非主键字段直接依赖主键,不要产生传递依赖
设计数据库的时按照以上范式进行可以避免表中数据冗余造成空间的浪费,但是这是理论上的,我们在实际开发中可能会拿冗余换速度,因为表与表之间连接越多效率越低