一、数据库简介
文本形式存储数据存在很多弊端:执行效率低;占用内存。
DB:
DateBase数据库,本质就是文件集(多个文件)会按照特定存储规范进行数据增删改查;
DBMS:
DateBaseManagementSystem数据库管理系统,本质就是管理数据库文件的软件,Oracle Mysql
SQL:
Strctured Query Language:结构化查询语言,通过sql语言和DBMS进行交互
二、数据库分类
关系型数据库:
是经过数学理论验证过,可以保存现实生活中任何关系的数据库 ,存放数据是以表为单位
Oracle Mysql DB2 Sqlite Sqlserver都是关系型数据库。
非关系型数据库:
Redis数据库(非关系型数据库)
Key-Value
三、数据库相关SQL
创建数据库指定字符集 |
create database db1 character set utf8; |
查看所有数据库 |
show databases; |
查看某个数据库 |
show create database db1; |
使用某个数据库 |
use 数据库名; |
删除某个数据库 |
drop database db2; |
四、表相关SQL
表的定义:表是数据库中存放数据的单元,任何数据都是存放到表中,类似于java中的Class,表中的字段对应Class的属性。
创建表 |
create table 表名(字段1名 类型,字段2名 类型,字段3名 类型); |
|
查询所有表 |
show tables; |
|
查看单个表属性(引擎和字符集) |
show create table 表名; |
|
查看表字段详情 |
desc 表名; |
|
创建表时指定引擎和字符集 |
create table t1(id int,name varchar(10)) engine=myisam charset=utf8; |
|
删除表 |
drop table t_stu; |
|
修改表名称 |
rename table 原名 to 新名; |
|
修改表的属性(引擎和字符集) |
alter table 表名 engine=innodb charset=utf8; |
|
添加表字段 |
在最后添加 |
alter table 表名 add fatherAge int; |
在最前添加 |
alter table 表名 add fatherAge int first; |
|
在某个字段后面添加 |
add fatherAge int after id; |
|
修改字段名和类型 |
alter table 表名 change 原字段名 新字段名 |
|
修改字段类型和位置 |
alter table 表名 modify 字段名 类型 位置(first/after ***); |
|
删除字段 |
alter table 表名 drop 字段名; |
|
给表添加字段的时候可以给表的字段添加注释 |
create table t5(id int comment '用户的id',age int comment '用户的年龄'); |
执行原理:当在终端中输入完建表语句敲回车 终端会把写好的sql 发送给DBMS(mysql),然后解析到 create table 时 识别出要创建一个表, 在表名后面的括号内部的内容是决定此表有哪些字段;
innoDB:默认,支持数据库的高级操作,包括事务 主外键等;
myisam: 只具备基本的数据存储功能创建表时指定引擎和字符集;
五、数据相关SQL
插入语句: |
全表插入格式 |
insert into 表名 values(值1,值2,值3); |
指定字段插入格式 |
insert into 表名 (字段1名,字段2名) values(值1,值2); |
|
批量插入 |
insert into hero values(11,'美国队长',34),(12,'钢铁侠',43),(13,'蜘蛛侠',23),(14,'雷神',55); |
|
指定字段的批量插入 |
insert into hero (name) values('张三'),('李四'),('王五'); |
|
查询语句 |
select * from hero; |
|
更新语句(修改) |
update 表名 set age=25 where id=1; 不加where条件则对整表数据操作 |
|
删除语句 |
delete from 表名 where 条件; |
|
TRUNCATE语句 |
truncate table hero; |
六、乱码问题
1. 数据库字符集 要设置utf8
2. 表的字符集 设置为utf8
3. windows系统的命令行里 有些版本是gbk的编码格式
可以通过set names gbk;的方式把mysql接收到数据时的解码格式设置为gbk,这个位置的gbk 和数据库还有表的utf8没有关系
4.在windows系统中修改mysql默认的数据库编码:
1). 找到安装文件中的my.ini的配置文件 在里面添加如下代码:
character-set-server=utf8
2). 添加完之后 尽量重启下电脑
七、eclipse里面写sql
1.先下载mysql驱动包
mysql-connector-java-5.1.6.jar
2.window->show view ->other->Data Management->Data Source Exploer 和 SQL Results Open
3.在Data Source Exploer选项卡里面的 DataBaseConnections上右键 new
4.选择MYSQL
5.点击下拉箭头右侧的加号
6.选择 5.1 点击JarList clear All
7.点击 add jar在弹出窗口中 找到下载的 jar文件 然后OK
8.修改URL /后面的内容 改成自己电脑上数据库的名字
9.输入密码 没有密码则空着
10.点击test Connection 如果显示 Ping Successed则点击finish
11.在大桶上面右键 Open SQL...
12.type 中选择 mysql5.1 Name中选择 New Mysql
Database中选择 database 在最右侧如果显示Connected则可以开始写sql语句
八、关键词
关键词 |
特点 |
语法/解决办法 |
主键约束 |
非空并唯一 |
create table t1(id int primary key,age int); |
自增约束 |
从最大值基础上+1,每张表只能有一个字段为自增字段 |
create table t2(id int primary key auto_increment,age int); |
非空 |
不为空 |
create table t3(id int primary key auto_increment, age int not null); |
注释 |
给表添加字段的时候可以给表的字段添加注释 |
create table t5(id int comment '用户的id',age int comment '用户的年龄'); |
数据的冗余 |
表内的数据出现大量重复 |
拆分表的形式避免或降低冗余的可能性 |
事务 |
数据库中sql语句执行的最小单元 |
见表九 |
九、事务:原子性,一致性,永久性,隔离性
查看自动提交状态 |
show variables like '%autocommit%'; |
修改状态 |
set autocommit=0/1; |
起始点 |
savepoint begin; |
设置回滚点 |
savepoint s1; |
提交 |
commit; |
回滚 |
rollback to begin/s1; |
十、SQL分类
DDL |
Data Definition Language:数据定义语言 |
常见命令 create alter drop truncate |
DML |
Data Manipulation Language:数据操作语言 |
常见命令:insert update delete (select) |
DQL(属于DML) |
Data Query Language:数据查询语言 |
常见命令:select |
TCL |
Transaction Control Language:事务控制语言 |
常见命令:begin commit rollback savepoint |
DCL |
Data Control Language:数据控制语言 |
给用户分配权限相关的sql语言 |
十一、数据库数据类型
关键字 |
类型 |
字节数/长度 |
语法 |
Int(m) |
整数 |
4 |
create table t_int (num int(10) zerofill);(m代表现实长度,当现实的数据长度小于m值时会补0 **一定要结合zerofill使用) |
bigint |
8 |
create table t_int (num bigint); |
|
double(m,d) |
浮点数 |
56.234 5,3 |
m代表数据的总长度,d代表小数点后面的位数 涉及高精度运算时使用decimal 通常涉及钱的地方使用decimal |
decimal(m,d) |
|||
char(20) |
字符串 |
固定长度(20长度) |
执行效率高 最大255 |
varchar(20) |
可变长度 |
节省空间 最大65535,但是超过255建议使用text |
|
text |
可变长度 |
最大65535 |
|
date |
日期 |
月日 |
create table t(d1 date,d2 time,d3 datetime,d4 timestamp); insert into t values('2008-8-8','12:06:35','2008-08-12 14:30:22',null); |
time |
分秒 |
||
datetime |
年月日时分秒 |
默认值null 最大值9999-12-31 |
|
timestamp |
年月日时分秒 |
默认值是当前时间 最大时间2038-01-19 |
十二、没有条件简单的查询语句
查询语句 |
语法 |
||
查询表中所有的数据 |
select * from 表名; |
||
查询表中所有数据,只查看某些列 |
列值为null : is null |
select empno,ename,job,comm from emp where comm is not null and comm>0; |
|
列值不为null: is not null |
|||
别名 |
select ename as '姓名' from emp; |
||
去重复 |
select distinct job from emp; |
||
= > < >= <= !=(<>) |
select title from t_item where price!=8443; |
||
between and |
select price from t_item where price between 10 and 100; |
||
in(a,b,c) |
select category_id from t_item where category_id in (238,917,163); |
||
AND |
select empno,ename,deptno from emp where deptno!=10 and sal<3000; |
||
OR |
select ename,job,deptno from emp where deptno=30 or mgr=7698; |
||
LIKE _ : 代表单个未知字符 % : 代表多个未知字符
以a开头的字符 a% 以a结尾 %a 包含a %a% 第二个字母是a _a%
|
1.案例:查询标题包含记事本的商品 select title from t_item where title like '%记事本%'; 2.案例:查询单价低于500的联想产品 select title,price from t_item where price<5000 and title like '%联想%'; |
||
ORDER BY 子句 默认升序 升序 asc,降序 desc |
需求:按照分类id升序 价格降序 select category_id,price from t_item order by category_id,price desc; |
||
Limit a,b【a:跳过的条数,b:每页的条数】 |
select name from user where id=1 order by id limit 0,1; |
||
CONCAT() 实现多个字符串的拼接 |
select concat(id,name,money) as '呵呵' from user; |
||
数值计算:+ - * / 7%2等效 mod(7,2) |
select price,num,price*num 总价 from t_item; |
||
日期相关函数 |
now() 获取当前日期+时间 |
select now(),curdate(),curtime(); |
|
curdate() 获取当前日期 |
|||
curtime() 获取当前时间 |
|||
date(now()) 从日期和时间中获取日期 |
select date(now()), time(now()); |
||
time(now()) 从日期和时间中 获取时间 |
|||
extract() 提取年月日时分秒 |
select extract(year from now()); select extract(month from now()); select extract(day from now()); select extract(hour from now()); select extract(minute from now()); select extract(second from now()); |
DATE_FORMAT() 函数 |
- %Y 4位年 2018 - %y 2位年 18 - %m 月 05 - %c 月 5 - %d 日 - %H 24小时 - %h 12小时 - %i 分 - %s 秒
|
select date_format(now(),'%Y年%m月%d日 %H时%i分%s秒');
案例:查询商品,并显示商品上传日期(x年x月x日) select title,date_format(created_time,'%Y年%m月%d日') from t_item; |
str_to_date()函数 |
把字符串转成日期格式 |
举例:2018年10月22日 select str_to_date('2018年10月22日','%Y年%m月%d日'); -案例:14.08.2018 08:12:54 转成日期格式 select str_to_date('14.08.2018 08:12:54','%d.%m.%Y %H:%i:%s');
|
IFNULL(a,b) |
age=ifnull(a,b) 如果a是null age=b 如果不是null age=a; |
update EMP set comm=ifnull(comm,0); |
聚合函数 |
sum(): 求和 |
select sum(num) from t_item; |
avg(): 求平均值 |
select avg(price) from t_item; |
|
count(): 计算数量 |
select count(*) from t_item; |
|
max(): 最大值 |
select max(price) from t_item; |
|
min(): 最小值 |
select min(price) from t_item; |
|
字符串的函数 |
char_length(str) 获取字符串长度 |
select char_length('abc'); |
instr(str,substr) 获取subStr在str中的位置从1开始 |
select instr('abcdefg','d'); |
|
locate(substr,str)获取subStr在str中的位置从1开始 |
select locate('e','abcdefg'); |
|
insert(str,start,length,newStr) 在str中从start位置替换newStr |
select insert('abcdefghijk',3,5,'mm'); 结果:abmmhijk |
|
lower(str) 转小写 |
select lower('NBa'); |
|
upper(str) 转大写 |
select upper('NBa'); |
|
left(str,count)从左边截取count个字符串 |
select left('abcdefg',3); |
|
right(str,count)从右边截取count个字符串 |
select right('abcdefg',3); |
|
trim(str)去字符串两端的空格 |
select trim(' abc '); |
|
substring(str,index) 从index位置开始截取到最后 |
select substring('abcdefg',2); |
|
substring(str,index,length);从index位置开始截取 length个长度 |
select substring('abcdefg',2,2); |
|
repeat(str,count) 重复 |
select repeat('ab',2);
|
|
replace(str,old,new) 替换 |
select replace('mysql','my','your'); |
|
reverse() 反转 |
select reverse('nba'); |
|
数学相关函数 |
floor(num) 向下取整 |
select floor(3.13); 3 |
round(num) 四舍五入 |
select round(3.54); 4 |
|
round(num,m) m代表小数点位数 |
select round(2.34245,2); 2.34 select round(1234.1234,-2); 1200 |
|
truncate(num,m) 和上面一样但是非四舍五入 |
select truncate(2.34545,2); 2.34 |
|
rand() 随机数 |
案例: 获取0-5的随机数 select floor(rand()*6); 案例: 获取5-10的随机数 select floor(rand()*6) + 5; 案例: 获取3到5的随机数 0-2 select floor(rand()*3)+3; 案例: 获取4到7的随机数 0-3 +4 select floor(rand()*4)+4;
|
根据以下员工表,部门表,商品表,商品分类表的字段回答问题
Emp表:字段:empno,ename,job,mgr,Hiredate,sal,comm,deptno;
Dept表:字段:deptno,dname,loc;
t_item:Id,category_id,item_type,title,sell_point,price,num,barcode,image,status,priority,created_time, modified_time ,datetime,created_user, modified_user;
t_item_category:Id,bigint(20),parent_id,name,status,sort_order,is_parent,created_time,modified_time , created_user,modified_user;
Day03 练习
1. 案例:查询没有上级领导的员工的编号,姓名,工资
select empno,ename,sal from emp where mgr is null;
2. 案例:查询emp表中没有奖金的员工的姓名,职位,工资,以及奖金
select ename,job,sal,comm from emp where comm is null;
3. 案例:查询emp表中含有奖金的员工的编号,姓名,职位,以及奖金
select empno,ename,job,sal from emp where comm !=0;
4. 案例:查询含有上级领导的员工的姓名,工资以及上级领导的编号
select ename,job,mgr from emp where mgr is not null;
5. 案例:查询emp表中名字以‘S’开头的所有员工的姓名
Select ename from emp where ename like “S%”;
6. 案例:查询emp表中名字的最后一个字符是'S'的员工的姓名
Select ename from emp where ename like “%S”;
7. 案例:查询倒数的第2个字符是‘E’的员工的姓名
Select ename from emp where ename like “%E_”;
8. 案例:查询emp表中员工的倒数第3个字符是‘N’的员工姓名
Select ename from emp where ename like “%N__”;
9. 案例:查询emp表中员工的名字中包含‘A’的员工的姓名
Select ename from emp where ename like “%A%”;
10. 案例:查询emp表中名字不是以'K'开头的员工的所有信息
Select ename from emp where ename not like “K%”;
11. 案例:查询emp表中名字中不包含‘A’的所有员工的信息
Select ename from emp where ename not like “%A%”;
12. 案例:做文员的员工人数(job_id 中 含有 CLERK 的)
Select count(clerk) from job_id;
13. 案例:销售人员 job: SALESMAN 的最高薪水
Select max(sal) from emp where job='SALESMAN';
14. 案例:最早和最晚入职时间
Select max(Hiredate),min(Hiredate) from emp;
15. 案例:查询类别 163的商品总库存量
Select num from t_item where category_id=163;
16. 案例:查询 类别 163 的商品
Select * from t_item where category_id=163;
17. 案例:查询商品价格不大于100的商品名称列表
Select title from t_item where price<=100;
18. 案例:查询品牌是联想,且价格在40000以上的商品名称和价格
Select title,price from t_item where price>40000 and title like “%联想%”;
19. 案例:查询品牌是三木,或价格在50以下的商品名称和价格
Select title,price from t_item where title like “%三木%”or price<50;
20. 案例:查询品牌是三木、广博、齐心的商品名称和价格
Select title,price from t_item where title like “%三木%”or title like“%广博%”or title like“%齐心%”;
21. 案例:查询品牌不是联想、戴尔的商品名称和价格
Select title ,price from t_item where title not like “%联想%”and title not like “%戴尔%”;
22. 案例:查找品牌是联想且价格大于10000的电脑名称
Select title from t_item where price>10000 and title like “%联想%”and category_id=163;
23. 案例:查询联想或戴尔的电脑名称列表
Select title from t_item where title like “%联想%”or title like “%戴尔%”and category_id=163;
24. 案例:查询联想、戴尔、三木的商品名称列表
Select title from t_item where title like “%联想%”or title like “%戴尔%”or title like “%三木%” ;
25. 案例:查询不是戴尔的电脑名称列表
Select title from t_item where title not like “%戴尔%”and category_id=163;
26. 案例:查询所有是记事本的商品品牌、名称和价格
Select left(title,2),title,price from t_item where category_id=163;
27. 案例:查询品牌是末尾字符是'力'的商品的品牌、名称和价格
Select left(title,2),title,price from t_item where left(title,2) like “_力”;
28. 案例:名称中有联想字样的商品名称
Select title from t_item where title like “%联想%”;
29. 案例:查询卖点含有'赠'产品名称
Select title from t_item where sell_point like “%赠%”;
30. 案例:查询emp表中员工的编号,姓名,职位,工资,并且工资在1000~2000之间。
Select empno,ename,job,sal from emp where sal between 1000 and 2000;
31. 案例:查询emp表中员工在10号部门,并且含有上级领导的员工的姓名,职位,上级领导编号以及所属部门的编号
Select ename,job,mgr, deptno from emp where deptno=10 and mgr is not null;
32. 案例:查询emp表中名字中包含'E',并且职位不是MANAGER的员工的编号,姓名,职位,以及工资。
Select empno,ename,job,sal from emp where ename like “%E%”;
33. 案例:查询emp表中10号部门或者20号部门中员工的编号,姓名,所属部门的编号
Select empno,ename,deptno from emp where deptno=10 or deptno=20;
34. 案例:查询emp表中没有奖金或者名字的倒数第2个字母不是T的员工的编号,姓名,职位以及奖金
Select empno,ename,job,sal from emp where comm is null or ename not like “%T_”;
35. 案例:查询工资高于3000或者部门编号是30的员工的姓名,职位,工资,入职时间以及所属部门的编号
Select ename,job,sal,hiredate,deptno from emp where sal>3000 or deptno=30;
36. 案例:查询不是30号部门的员工的所有信息
Select * from emp where deptno !=30;
37. 案例:查询奖金不为空的员工的所有信息
Select * from emp where sal is not null;
38. 案例:查询emp表中所有员工的编号,姓名,职位,根据员工的编号进行降序排列
Select empno,ename,job from emp order by empno desc;
39. 案例:查询emp表中部门编号是10号或者30号中,所有员工姓名,职务,工资,根据工资进行升序排列
Select ename,job,sal from emp where deptno in(10,30) order by sal;
40. 案例:查询emp表中所有的数据,然后根据部门的编号进行升序排列,如果部门编号一致,根据员工的编号进行降序排列
Select * from emp order by deptno,empno desc;
41. 案例:查询emp表中工资高于1000或者没有上级领导的员工的编号,姓名,工资,所属部门的编号,以及上级领导的编号,根据部门编号进行降序排列,如果部门编号一致根据工资进行升序排列。
Select empno,ename,sal,deptno,mgr from emp where sal>1000 or mgr is null order by deptno desc,sal;
42. 案例:查询emp表中名字中不包含S的员工的编号,姓名,工资,奖金,根据工资进行升序排列,如果工资一致,根据编号进行降序排列
Select empno,ename,sal,comm from emp where ename not like “%S%”order by sal,empno desc;
43. 案例:统计emp表中员工的总数量
Select count(empno) from emp;
44. 案例:统计emp表中获得奖金的员工的数量
Select count(empno) from emp where comm is not null;
45. 案例:求出emp表中所有的工资累加之和
Select sum(sal) from emp;
46. 案例:求出emp表中所有的奖金累加之和
Select sum(comm) from emp;
47. 案例:求出emp表中员工的平均工资
Select avg(sal) from emp;
48. 案例:求出emp表中员工的平均奖金
Select avg(comm) from emp;
49. 案例:求出emp表中员工的最高工资
Select max(sal) from emp;
50. 案例:求出emp表中员工编号的最大值
Select max(empno) from emp;
51. 案例:查询emp表中员工的最低工资。
Select min(sal) from emp;
52. 案例:查询emp表中员工的人数,工资的总和,平均工资,奖金的最大值,奖金的最小值,并且对返回的列起别名。
Select count(empno) as '员工的人数',sum(sal) as '工资的总和',avg(sal) as '平均工资',max(comm) as '奖金的最大值',min(comm) as '奖 金的最小值'from emp;
53. 案例:查询emp表中每个部门的编号,人数,工资总和,最后根据人数进行升序排列,如果人数一致,根据工资总和降序排列。
Select deptno,count(empno),sum(sal) from emp group by deptno order by count(empno),sum(sal) desc;
54. 案例:查询工资在1000~3000之间的员工信息,每个部门的编号,平均工资,最低工资,最高工资,根据平均工资进行升序排列。
Select deptno,avg(sal),min(sal),max(sal) from emp where sal between 1000 and 3000 order by avg(sal);
55. 案例:查询含有上级领导的员工,每个职业的人数,工资的总和,平均工资,最低工资,最后根据人数进行降序排列,如果人数一致,根据平均工资进行升序排列
Select count(empno),sum(sal),avg(sal),min(sal) from emp where mgr is not null group by job order by count(empno) desc,avg(sal);
56. 案例:查询工资在1000~3000之间每一个员工的编号,姓名,职位,工资
Select empno,ename,job,sal from emp where sal between 1000 and 3000;
57. 案例:查询emp表中奖金在500~2000之间所有员工的编号,姓名,工资以及奖金
Select empno,ename,sal,comm from emp where comm between 500 and 2000;
58. 案例:查询员工的编号是7369,7521,
Select * from emp where empno in(7369,7521);
59. 案例:查询emp表中,职位是ANALYST,
select * from emp where job='ANALYST';
60. 案例:查询emp表中职位不是ANALYST,
select * from emp where job not like “ANALYST”;
十三、GROUP BY、HAVING语句
概念 |
理解 |
语法 |
GROUP BY 语句 |
通常查询每个部门(性别/分类) 就以部门(性别/分类)为分组条件 |
每年的入职人数: Select count(*), extract(year from hiredate) year from emp group by year; |
HAVING 语句 |
Where后的条件过滤不能使用聚合函数,这时使用Having代替Where |
查询每个部门的平均工资,只显示平均工资大于2000的: select deptno,avg(sal) a from emp group by deptno having a>2000; |
语法格式:select from where group by having order by limit; |
练习:
1.案例:查询emp表中,每个部门的平均工资高于2000的部门的编号,部门的人数,平均工资,最后根据平均工资进行升序排列。
Select deptno,count(empno),avg(sal) s from emp group by deptno having s>2000 order by s;
2.案例:查询emp表中名字中不是以'K'开头的信息,每个部门的最低工资高于1000的部门的编号,工资总和,平均工资以及最低工资,最后根据平均工资进行升序排列。
Select deptno,count(sal),avg(sal) a,min(sal) s from emp where ename not like “K%”group by deptno having s>1000 order by a;
3.案例:查询emp表中部门编号是10,30号部门的员工,每个职业的最高工资低于5000的职业的名称,人数,平均工资,最高工资,最后根据人数进行升序排列,如果人数一致,根据最高工资进行降序排列。
Select job,count(empno) e,avg(sal),max(sal) s from emp where deptno in(10,30) group by job having s<5000 order by e,s desc;
4.案例:查询emp表中,每个部门的编号,人数,工资总和,最高工资以及最低工资,过滤掉最高工资是5000的部门,根据部门的人数进行升序排列,如果人数一致,则根据最高工资进行降序排列。
Select deptno,count(empno) e,sum(sal),max(sal) m,min(sal) from emp group by deptno having m!=5000 order by e,m desc;
5. 案例:查询emp表中工资在1000~3000之间的员工信息,每个部门的编号,工资总和,平均工资,过滤掉平均工资低于2000的部门,按照平均工资进行升序排列
Select deptno,sum(sal),avg(sal) s from emp where sal between 1000 and 3000 group by deptno having s>=2000 order by s;
6. 案例:查询emp表中名字不是以‘S’开头,每个职位的名字,人数,工资总和,最高工资,过滤掉工资是3000的职位,根据人数进行升序排列,如果人数一致,根据工资总和进行降序排列。
Select job,count(empno) c,sum(sal) s,max(sal) from emp where ename not like “S%”and sal !=3000 group by job order by c,s desc;
7. 案例:查询emp表的信息,每个职位的名称,人数,平均工资,最低工资,过滤掉平均工资是3000的职位信息,根据人数进行降序排列,如果人数一致,根据平均工资进行升序排列
Select job,count(empno) c,avg(sal) a,min(sal) from emp group by job having a<>3000 order by c desc,a;
十四、MySQL子查询、关联查询数据、笛卡尔积、等值连接、内连接左/右外连接
概念 |
定义/理解 |
使用原因 |
语法 |
MySQL子查询 |
在一条sql语句中嵌入另外一条sql查询语句。 |
使用子查询可以把多条sql语句整合成一条执行,提供效率。 |
拿最低工资的员工信息 select * from emp where sal=(select min(sal) from emp); |
关联查询数据 |
同时查询多个表中的数据的查询方式 |
普通单表查询没有办法同时获取多个表里面的数据 |
使用 等值连接 内连接 和 左/右 外连接的方式进行关联查询 |
笛卡尔积 |
如果不写关联关系,查询出的两张表的乘积称为笛卡尔积 |
|
|
等值连接 |
将关联关系写在where 后面的两张表的查询方式 |
|
select * from A,B where A.x=B.x and age>18; |
内连接 |
将关联关系写在on 后面 |
将关联关系和筛选条件分离,更清晰 |
select * from A join B on A.x=B.x where age>18; |
左/右外连接 |
以某一张表为主表显示全部数据,另外一张表只显示关联数据的查询方式 |
内连接只能查询出有关系的数据,如果需要显示某一张表所有数据,则只能使用外连接,左外是以左边表为主表,右外是以右边表为主表 |
查询出所有员工名字和所对应部门的名字 select e.ename,d.dname from emp e left join dept d on e.deptno=d.deptno; |
练习
1. 每个部门的人数,根据人数排序
Select deptno,count(deptno) c from emp group by deptno order by c;
2. 每个部门中,每个主管的手下人数
select deptno,mgr,count(*) from emp group by deptno,mgr;
3. 每种工作的平均工资
Select job,avg(sal) from emp from emp group by job;
4. 每年的入职人数
select extract(year from hiredate) year,count(empno) from emp group by year;
5. 少于等于3个人的部门
Select deptno from emp group by deptno having count(empno) <=3;
6. 拿最低工资的员工信息
Select * from emp where sal=(select min(sal) from emp);
7. 只有一个下属的主管信息
select * from emp where empno in(select mgr from emp group by mgr having count(empno)=1);
8. 平均工资最高的部门编号
select deptno,count(empno),avg(sal) a from emp group by deptno order by a desc limit 0,1;
9. 下属人数最多的人,查询其个人信息
select * from emp where empno=(select mgr from emp group by mgr order by count(empno) desc limit 0,1);
10. 拿最低工资的人的信息
Select * from emp where sal=(select min(sal) from emp);
11. 最后入职的员工信息
Select * from emp where hiredate=(select max(hiredate) from emp);
12. 工资多于平均工资的员工信息
Select * from emp where sal>(select avg(sal) from emp);
13. 查询员工信息,部门名称
Select e.*,d.dname from emp e left join dept d on e.deptno=d.deptno;
14. 员工信息,部门名称,所在城市
Select e.*,d.dname,d.loc from emp e left join dept d on e.deptno=d.deptno;
15. DALLAS 市所有的员工信息
Select e.* from emp e left join dept d on e.deptno=d.deptno where d.loc=’DALLAS’;
16. 按城市分组,计算每个城市的员工数量
Select d.loc,count(e.empno) from dept d,emp e where e.deptno=d.deptno group by d.loc;
17. 查询员工信息和他的主管姓名
Select e.*,m.ename from emp e left join emp m on e.mgr=m.empno;
18. 员工信息,员工主管名字,部门名
第一种在第17上直接join的方式
select e.*,m.ename,d.dname from emp e left join emp m on e.mgr=m.empno left join dept d on m.deptno=d.deptno;
第二种把17查询结果当成新表
select n.*,d.dname
from (select e.*,m.ename 主管名
from emp e join emp m
on e.mgr=m.empno)n join dept d
on n.deptno=d.deptno;
注意:如果多表查询时出现重复字段名称 需要通过别名的方式进行区分
20. 员工和他所在部门名
Select e.*,d.dname from emp e left 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.ename,d.dname from emp e,dept d where e.deptno=d.deptno;
22. 案例:查询emp表中所有员工信息以及该员工上级领导的信息
Select * from emp e join emp m on e.mgr=m.empno;
23. 案例:查询emp表中名字中没有字母'K'的所有员工的编号,姓名,职位以及所在部门的信息
Select e.empno,e.ename,e.job,d.* from emp e right join dept d on e.deptno=d.deptno where e.ename not like “%K%”;
24. 案例:查询dept表中所有的部门的所有的信息,以及与之关联的emp表中员工的编号,姓名,职位,工资
Select d.*,e.empno,e.ename,e.job,e.sal from dept d left join emp e on d.deptno=e.deptno;
十五、表设计关联关系
表设计关联关系 |
定义 |
实例 |
自关联 |
当前表的数据和当前表里面的数据有关联关系 |
员工和上级领导 |
一对一关联 |
A表和B表,A表中的任何一条数据会对应B表中的一条数据 |
用户表和用户信息扩展表 |
一对多关联 |
A表和B表,A表中的任何一条数据会对应B表中一条或多条数据 |
部门和员工,分类和商品 |
多对多关联 |
A表和B表,A表中的任何一条数据会对应B表中一条或多条数据并且B表中的任意一条数据对应A表中的一条或多条 |
老师和学生,用户和角色 |
十六、如何让两张表建立关系
关联关系 |
关联条件 |
自关联 |
需要有一个字段记录当前表主键的值 |
一对一 |
需要在从表中有个字段表示主表的主键值 |
一对多 |
部门和员工为例,需要在多一端表中通过一个字段记录另外一张表的主键 |
多对多 |
需要准备一张关系表,表中保存两张表的主键值 |
1)创建1对1的表并练习
create table user(id int primary key auto_increment,username varchar(10),password varchar(10));
create table userinfo(id int,nick varchar(10));
insert into user values(1,'libai','admin'),(2,'zhaosi','admin');
insert into userinfo values(1,'李白'),(2,'赵四');
练习:查询每一个用户的所有信息
select u.*,ui.nick
from user u join userinfo ui
on u.id=ui.id;
2)创建多对多的表并练习
创建老师表(id,name)和学生表(id,name)每张表插入三条数据 思考:如何实现数据多对多的关系
create table teacher(id int primary key auto_increment,name varchar(10));
insert into teacher values(1,'唐僧'),(2,'刘备');
create table student(id int primary key auto_increment,name varchar(10));
insert into student values(1,'小明'),(2,'小红');
create table t_s(tid int,sid int);
insert into t_s values(1,1),(1,2),(2,1),(2,2);
-练习:查询小明的所有老师
1.得到小明的id
select id from student where name='小明'
2.通过学生id去关系表中查询对应的老师id
select tid from t_s where sid=(select id from student where name='小明');
3.去老师表中查询id等于第二步结果的老师
select * from teacher where id in(select tid from t_s where sid=(select id from student where name='小明'));
-练习2:查询所有老师对应的所有学生
select t.id tid,t.name tname,s.id sid,s.name sname
from teacher t join t_s ts
on t.id=ts.tid
join student s
on ts.sid=s.id;
-练习3:查询唐僧的所有学生
select t.id tid,t.name tname,s.id sid,s.name sname
from teacher t join t_s ts
on t.id=ts.tid
join student s
on ts.sid=s.id where t.name='唐僧';
十七、连接方式和关联关系的区别
连接方式:包括 内连接 外连接(左外,右外),是指查询两张表时使用的查询方式
关联关系: 一对一,一对多,多对多, 是指两张表之间存在的逻辑关系
十八、数据库设计之权限管理
概念 |
定义 |
实现方式 |
权限管理 |
不同的用户登录网站后可能会有不同的权限,实现此功能的过程称为权限管理 |
总共需要5张表 用户表 角色表 模块表 用户和角色关系表 角色和模块的关系表 |
具体实现:
-创建5张表
create table user(id int,name varchar(10));
create table role(id int,name varchar(10));
create table module(id int, name varchar(10));
create table u_r(uid int, rid int);
create table r_m(rid int, mid int);
-插入主表数据
insert into user values(1,'小明'),(2,'小红');
insert into role values(1,'游客'),(2,'管理员');
insert into module values(1,'增'),(2,'删'),(3,'改'),(4,'查');
-插入关系数据
insert into u_r values(1,1),(2,1),(2,2);
insert into r_m values(1,4),(2,1),(2,2),(2,3),(2,4);
-查询小红对应的所有权限(子查询)
1. 得到小红的id
select id from user where name='小红'
2. 通过小红id找到对应的角色id
select rid from u_r where uid=(select id from user where name='小红')
3. 通过角色id 找到对应的权限id
select mid from r_m where rid in(select rid from u_r where uid=(select id from user where name='小红'))
4. 通过权限id 找到权限的名字
select name from module where id in(select mid from r_m where rid in(select rid from u_r where uid=(select id from user where name='小明')));
-查询小红对应的所有权限(内连接)
select distinct m.name
from user u join u_r ur
on u.id=ur.uid
join r_m rm
on ur.rid=rm.rid
join module m
on rm.mid=m.id
where u.name='小明';
十九、视图:工作中使用视图时只是为了DQL(数据查询)
|
理解 |
使用原因/语法 |
|
视图 |
1、在数据库中存在多种对象,表和视图都是数据库中的对象,创建视图时视图名称不能和表名相同; 2、视图实际上就代表了一段sql查询语句,也可以理解成是一张虚拟的表,虚拟表中的数据会随着原表数据改变而改变。
|
1、有些数据的查询需要书写大量的sql语句,每次书写比较麻烦; 2、使用视图可起到重用sql语句的作用,可以通过视图隐藏敏感信息
|
|
创建视图的格式 |
create view 视图名 as 子查询 |
创建员工视图 隐藏工资字段 create view view_emp_nosalas (select empno,ename,job,mgr,hiredate,comm from emp); |
|
视图分类 |
简单视图 |
创建视图的子查询中 不包含去重,函数,聚合,关联查询的视图 |
create view v_emp_20 as (select * from emp where deptno=20 and sal<3000); |
复杂视图 |
和简单视图相反 |
create view v_emp as (select deptno,sum(sal),avg(sal),max(sal),min(sal) from emp group by deptno); |
|
查看视图 |
查看方式和表一样 |
select * from 视图名; |
|
视图数据污染 |
往视图中插入一条视图中不显示但是在原表中显示的数据(在视图中只有进行insert操作时才会造成数据污染 因为update和delete只能操作视图中存在的数据) |
insert into v_emp_20 (empno,ename,deptno) values (43234,'孙悟空',30);
|
|
避免视图污染 |
使用 with check option 关键字 |
create view v_emp_30 as (select * from emp where deptno=30) with check option; |
|
修改视图 |
|
create or replace view v_emp_20 as (select * from emp where deptno=20 and sal<1000); |
|
删除视图 |
|
drop view if exists view_emp_10; |
案例1:创建视图显示每一个部门名所对应的员工名
create or replace view v_emp as (select d.dname,e.ename
from emp e join dept d
on e.deptno=d.deptno);
案例2:修改上面的视图在上面题的前提下只显示工资在3000以内的
create or replace view v_emp as (select d.dname,e.ename
from emp e join dept d
on e.deptno=d.deptno where e.sal<3000);
案例3:删除上面创建的视图;
drop view if exists v_emp;
二十、 索引
|
理解 |
使用原因/语法 |
||
索引 |
索引是用来提高查询速度的技术,它类似于一个目录,查询数据时会先从目录中对数据进行定位,然后直接找到数据的所在位置 |
不使用索引的话,查询数据会按照磁盘块一块一块的去查,如果数据量很大,效率很低.
|
||
索引分类 |
聚簇索引 |
数据是有序保存在磁盘中的,在树的叶子里面保存地址主键和数据 |
在mysql中数据库会为主键创建聚集索引 |
|
非聚集索引 |
在树的叶子里面保存的是数据存在的磁盘块的地址 |
|||
索引内部实现原理:B+tree |
数据库中创建索引的过程是数据库内部自己控制,然后使用索引的过程也是数据库自己操作的不需要程序员干涉
|
|||
索引是越多越好? |
1、索引会占用磁盘空间所以创建索引需谨慎,只创建有查询需求的索引; 2、索引要建立在大量数据的表中,如果数据量不够大,使用索引可能会降低查询效率
|
|||
创建索引格式 |
create index 索引名 on 表名(字段名(长度)); |
-创建索引之前先查询看时间 select * from item2 where title='100'; -创建title索引 create index index_title on item2(title); -再次查询看时间 select * from item2 where title='100';
|
||
查看索引 |
|
show index from item2; |
||
删除索引 |
|
drop index index_title on item2; |
||
复合索引 |
复合索引即创建索引的时候指定多个字段,此时如果查询数据正好过滤条件为这两个字段的话,可以降低磁盘块的访问量从而提高查询效率
|
select * from item2 where title='100' and price<100; create index index_title_price on item2(title,price); |
||
创建表的时候直接添加索引 |
|
create table t_index(id int,age int,index index_age(age)); |
二十一、MySQL 约束
|
理解 |
语法 |
约束 |
约束就是对表字段的数据进行限制的规则 |
|
唯一约束 unique |
添加唯一约束的字段 不能插入重复数据否则报错 |
create table t_uni(id int,age int unique); |
主键约束(PRIMARY KEY) |
|
-创建表时添加主键 create table t(id int primary key auto_increment); -创建表后添加主键 alter table t1 add primary key(id); -删除主键约束 alter table t1 drop primary key;
|
自增约束 auto_increment |
1. 当字段赋的值为null时 ,字段会自动增长; 2. 如果删除了某条数据,自增数值不会减; 3. 如果指定了一个比较大的值,下次插入数据会从最大的值基础上+1;4. 如果使用delete删除数据,自增的值不会从头开始; 5. 如果使用truncate table t_auto的方式删除 则从1开始自增。
|
|
外键约束(FOREIGN KEY) |
外键约束是保证一个表(自关联)或两个表之间数据一致性和完整性的约束 |
外键总结: 保证一个表或两个表之间数据的一致性和完整性,工作不怎么用,外键的值是关联表的主键,值可以是null可以重复,不能是不存在的数据,使用外键必须两张表使用innodb引擎 |
非空约束(NOT NULL) |
让该字段的数据不能为null 否则报错 |
|
默认约束(DEFAULT) |
给字段设置默认值 |
create table t_def(id int,age int DEFAULT 0); |
|
|
|