sql字段与多表查询

mysql的数据类型

数值类型

MySQL中支持多种整型,其实很大程度上是相同的,只是存储值的大小范围不同而已。

tinyint:占用1个字节,相对于java中的byte

smallint:占用2个字节,相对于java中的short

int:占用4个字节,相对于java中的int

bigint:占用8个字节,相对于java中的long

其次是浮点类型即:float和double类型

float:4字节单精度浮点类型,相对于java中的float

double:8字节双精度浮点类型,相对于java中的double

字符串类型

1、char(n) 定长字符串,最长255个字符。n表示字符数,例如:

– 创建user表,指定用户名为char类型,字符长度不超过10

create table user(
    username char(10),
    ...
);

所谓的定长,是当插入的数据的长度小于指定的长度时,剩余的空间会用空格填充。(这样会浪费空间)

char类型往往用于存储长度固定的数据。

2、varchar(n) 变长字符串,最长不超过65535个字节,n表示字符数,一般超过255个字符,会使用text类型,例如:

iso8859-1码表:一个字符占用1个字节,1*n < 65535, n最多等于 65535
utf8码表:一个中文汉字占用3个字节,3*n < 65535,n最多等于 65535/3
GBK码表:一个中文汉字占用2个字节,2*n < 65535,n最多等于 65535/2

– 创建user表,指定用户名为varchar类型,长度不超过10个字符

create table user(
	username varchar(10)
);

所谓的不定长,是当插入的数据的长度小于指定的长度时,剩余的空间可以留给别的数据使用。(节省空间)

总结:长度固定的数据,用char类型,这样既不会浪费空间,效率也比较高

如果长度不固定,使用varchar类型,这样不会浪费空间。

3、大文本(长文本)类型

最长65535个字节,一般超过255个字符列的会使用text。

– 创建user表:

create table user(
	resume text
);

另,text也分多种,其中bigtext存储数据的长度约为4GB。

扩展内容3:(面试题)char(n)、varchar(n)、text都可以表示字符串类型,其区别在于:

(1)char(n)在保存数据时,如果存入的字符串长度小于指定的长度n,后面会用空格补全,因此可能会造成空间浪费,但是char类型的存储速度较varchar和text快。

因此char类型适合存储长度固定的数据,这样就不会有空间浪费,存储效率比后两者还快!

(2)varchar(n)保存数据时,按数据的真实长度存储,剩余的空间可以留给别的数据用,因此varchar不会浪费空间。

因此varchar适合存储长度不固定的数据,这样不会有空间的浪费。

(3)text是大文本类型,一般文本长度超过255个字符,就会使用text类型存储。

日期类型

日期类型

date:年月日

time:时分秒

datetime:年月日 时分秒

timestamp:时间戳(实际存储的是一个时间毫秒值),与datetime存储日期格式相同。两者的区别是:

  • timestamp最大表示2038年,而datetime范围是1000~9999

  • timestamp在插入数据、修改数据时,可以自动更新成系统当前时间(后面用到时再做讲解)

mysql的字段约束

字段约束/列约束 --> 约束: 限制

主键约束

主键约束:如果为一个列添加了主键约束,那么这个列就是主键,主键的特点是唯一且不能为空。

主键的作用: 作为一个唯一标识,唯一的表示一条表记录(作用类似于人的身份证号,可以唯一的表示一个人一样。)

添加主键约束,例如将id设置为主键:

create table stu(
	id int primary key,
	...
);

如果主键是数值类型,为了方便插入主键(并且保证插入数据时,主键不会因为重复而报错),可以设置一个主键自增策略。

create table stu(
	id int primary key auto_increment,
	...
);

主键自增策略是指:设置了自增策略的主键,可以在插入记录时,不给id赋值,只需要设置一个null值,数据库会自动为id分配一个值(AUTO_INCREMENT变量,默认从1开始,后面依次+1),这样既可以保证id是唯一的,也省去了设置id的麻烦。

将id主键设置为自增:

create table stu(
	id int primary key auto_increment,
	...
);

非空约束

非空约束:如果为一个列添加了非空约束,那么这个列的值就不能为空,但可以重复。

添加非空约束,例如为password添加非空约束:

create table user(
	password varchar(50) not null,
	...
);

唯一约束

唯一约束:如果为一个列添加了唯一约束,那么这个列的值就必须是唯一的(即不能重复),但可以为空。

添加唯一约束,例如为username添加唯一约束及非空约束:

create table user(
	username varchar(50) unique not null,
	...
);

外键约束

外键其实就是用于通知数据库两张表数据之间对应关系的这样一个列。

这样数据库就会帮我们维护两张表中数据之间的关系。

(1) 创建表的同时添加外键

create table emp(
	id int,
	name varchar(50),
	dept_id int,
	foreign key(dept_id) references dept(id)
);

在这里插入图片描述
(1)如果是要表示两张表的数据之间存在对应关系,只需要在其中的一张表中添加一个列,保存另外一张表的主键,就可以保存两张表数据之间的关系。

但是添加的这个列(dept_id)对于数据库来说就是一个普通列,数据库不会知道两张表存在任何关系,因此数据库也不会帮我们维护这层关系。

在这里插入图片描述
(2)如果将dept_id列设置为外键,等同于通知数据库,部门表和员工表之间存在对应关系,dept_id列中的数据要参考部门的主键,数据库一旦知道部门和员工表之间存在关系,就会帮我们维护这层关系。

思考:如果在创建表时没有指定外键,那么后期该如何指定外键?以及如何删除外键?

表关系

常见的表关系分为以下三种:

一对多(多对一)·、一对一、多对多
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
多表查询

– 准备数据: 以下练习将使用db30库中的表及表记录,请先进入db30数据库!!!

连接查询

– 42.查询部门和部门对应的员工信息

select * from dept,emp;

上面的查询中存在大量错误的数据,一般我们不会直接使用这种查询。

笛卡尔积查询:所谓笛卡尔积查询就是指,查询两张表,其中一张表有m条记录,另一张表有n条记录,查询的结果是m*n条。

虽然笛卡尔积查询中包含大量错误数据,但我们可以通过where子句将错误数据剔除,保留下来的就是正确数据。

-- 员工所属的部门编号(emp.dept_id),等于部门的编号(dept.id)
select * from dept,emp
where emp.dept_id=dept.id;

通过where子句将笛卡尔积查询中的错误数据剔除,保留正确的数据,这就是连接查询!

上面的查询可以换成下面的查询:

select * from dept inner join emp
on emp.dept_id=dept.id;
-- 内连接查询,和上面的查询结果一样。

左外连接查询

– 43.查询【所有部门】及部门对应的员工,如果某个部门下没有员工,员工显示为null

select * from dept left join emp
on emp.dept_id=dept.id;

在这里插入图片描述
左外连接查询:可以将左边表中的所有记录都查询出来,右边表只显示和左边相对应的数据,如果左边表中某些记录在右边没有对应的数据,右边显示为null即可。

右外连接查询

– 44.查询【所有员工】及员工所属的部门,如果某个员工没有所属部门,部门显示为null即可

select * from dept right join emp
on emp.dept_id=dept.id;

在这里插入图片描述

右外连接查询:可以将右边表中的所有记录都查询出来,左边表只显示和右边相对应的数据,如果右边表中某些记录在左边没有对应的数据,可以显示为null。

扩展:如果想将两张表中的所有数据都查询出来(左外+右外并去除重复记录),可以使用全外连接查询,但是mysql又不支持全外连接查询。

select * from dept left join emp on emp.dept_id=dept.id
union
select * from dept right join emp on emp.dept_id=dept.id;

可以使用union将左外连接查询的结果和右外连接查询的结果合并在一起,并去除重复的记录。例如:

在这里插入图片描述
需要注意的是:union可以将两条SQL语句执行的结果合并,但是有前提:

(1)两条SQL语句查询的结果列数必须一致

(2)两条SQL语句查询的结果列名、顺序也必须一致

并且union默认就会将两个查询中重复的记录去除(如果不希望去除重复记录,可以使用union all)

子查询练习

– 准备数据:以下练习将使用db40库中的表及表记录,请先进入db40数据库!!!

– 45.列出薪资比’王海涛’的薪资高的所有员工,显示姓名、薪资

-- 求出'王海涛'的薪资
select sal from emp where name='王海涛'; -- 2450
-- 求出薪资比 '王海涛'的薪资 还高的所有员工
select name, sal from emp 
where sal > (select sal from emp where name='王海涛');

– 46.列出与’刘沛霞’从事相同职位的所有员工,显示姓名、职位。

-- 查询'刘沛霞'从事的职位
select job from emp where name='刘沛霞'; -- 推销员
-- 求从事'推销员'职位的所有员工
select name, job from emp 
where job = (select job from emp where name='刘沛霞');

– 47.列出薪资比’大数据部’部门(已知部门编号为30)所有员工薪资都高的员工信息,显示员工姓名、薪资和部门名称。

如果不考虑没有部门的员工

-- 连接查询部门表和员工表, 显示员工姓名、薪资和部门名称
select emp.name,sal,dept.name from dept,emp
where emp.dept_id=dept.id;
-- 求大数据部门的最高薪资是多少
select max(sal) from emp where dept_id=30; -- 3000
-- 在连接查询的基础上, 求出 薪资 比大数据部门最高薪资 还高的员工信息
select emp.name,sal,dept.name from dept,emp
where emp.dept_id=dept.id
	and sal > (select max(sal) from emp where dept_id=30);

如果加上没有部门的员工

-- 用外连接查询部门和所有员工, 显示员工姓名、薪资和部门名称
select emp.name,sal,dept.name from dept right join emp
on emp.dept_id=dept.id;
-- 求大数据部门的最高薪资是多少
select max(sal) from emp where dept_id=30; -- 3000
-- 在外连接查询的基础上, 求出 薪资 比大数据部门最高薪资 还高的员工信息
select emp.name,sal,dept.name from dept right join emp
on emp.dept_id=dept.id 
where sal > (select max(sal) from emp where dept_id=30);

多表查询练习

– 48.列出在’培优部’任职的员工,假定不知道’培优部’的部门编号,显示部门名称,员工名称。

-- 连接查询部门表和员工表(可以给表名指定别名,指定后就需要使用别名,不能再使用表名)
select d.name, e.name from dept d,emp e
where e.dept_id=d.id;
-- 在上面查询的基础上, 求出培优部的员工
select d.name, e.name from dept d,emp e
where e.dept_id=d.id
	and d.name='培优部';

– 49.(自查询)列出所有员工及其直接上级,显示员工姓名、上级编号,上级姓名

/*
将 emp 表看做两张表, 分别是员工表(emp e1) 和 上级表(emp e2)
显示的列: e1.name, e2.id, e2.name
查询的表: emp e1, emp e2
连接条件: e1.topid=e2.id
 */
select e1.name, e2.id, e2.name
from emp e1, emp e2
where e1.topid=e2.id;

– 50.列出最低薪资大于1500的各种职位,显示职位和该职位的最低薪资

-- 根据职位进行分组, 求出每个职位对应的最低薪资
select job,min(sal) from emp 
group by job;
-- 求出最低薪资大于1500的职位有哪些
select job,min(sal) from emp 
group by job 
having min(sal)>1500;

补充内容:where和having子句的区别:

相同点: 都是对查询的结果进行筛选过滤
不同点:
(1)where是在分组之前对数据进行筛选过滤; 而having是在分组之后对数据进行筛选过滤
(2)where子句中不能使用多行数据, 也不能使用列别名, 但可以使用表别名; 而having中可以使用多行函数, 也可以使用列别名和表别名;

– 51.列出在每个部门就职的员工数量、平均工资。显示部门编号、员工数量,平均薪资。

-- 根据部门进行分组,每个部门的员工为一组,统计每个部门的员工人数和平均薪资
select dept_id,count(*),avg(sal) 
from emp 
group by dept_id;

– 52.查出至少有一个员工的部门,显示部门编号、部门名称、部门位置、部门人数。

-- 连接查询部门表和员工表,显示部门编号、名称和位置, 员工名称
select d.id, d.name, d.loc, e.name 
from emp e,dept d
where e.dept_id=d.id;
-- 在上面查询的基础上, 根据部门分组, 统计每个部门的人数
select d.id, d.name, d.loc, count(*) 
from emp e,dept d
where e.dept_id=d.id
group by d.name;

-- 在上面查询的基础上,按照部门人数降序排序
select d.id, d.name, d.loc, count(*) 
from emp e,dept d
where e.dept_id=d.id
group by d.name
order by count(*) desc;

– 53.列出受雇日期早于直接上级的所有员工,显示员工编号、员工姓名、部门名称。

/* 将emp表分别看做员工表(emp e1)和上级表(emp e2)
显示的列: e1.id, e1.name, d.name
查询的表: emp e1, emp e2, dept d
连接条件,员工表和上级表关联: e1.topid=e2.id
连接条件,员工表和部门表关联: e1.dept_id=d.id
筛选条件,员工的入职日期小于上级的入职日期: e1.hdate < e2.hdate */
select e1.id, e1.name, d.name
from emp e1, emp e2, dept d
where e1.topid=e2.id
	and e1.dept_id=d.id
	and e1.hdate < e2.hdate;

– 补充:查询员工表中薪资最高的员工信息

-- 求emp表中的最高薪资
select max(sal) from emp;
-- 求出emp表中的哪个员工的薪资等于最高薪资
select * from emp where sal = (select max(sal) from emp);

-- 或者 让员工信息按照薪资降序排序,再分页,只取第一条!
select * from emp order by sal desc limit 0,1;

数据库备份与恢复

备份数据库

在cmd窗口中(未登录的状态下),可以通过如下命令对指定的数据库进行备份:

mysqldump -u用户名 -p 数据库的名字 > 备份文件的位置

示例1: 对db40库中的数据(表,表记录)进行备份,备份到 d:/db40.sql文件中

mysqldump -uroot -p db40 > d:/db40.sql

键入密码,如果没有提示,即表示备份成功!

也可以一次性备份所有库,例如:

对mysql服务器中所有的数据库进行备份,备份到 d:/all.sql文件中

mysqldump -uroot -p --all-database > d:/all.sql

键入密码,如果没有提示错误(警告信息不是错误,可以忽略),即表示备份成功!

恢复数据库

1、恢复数据库方式一:

在cmd窗口中(未登录的状态下),可以通过如下命令对指定的数据库进行恢复:

mysql -u用户名 -p 数据库的名字 < 备份文件的位置

示例:将d:/db40.sql文件中的数据恢复到db60库中

– 在cmd窗口中(已登录的状态下),先创建db60库:

create database db60 charset utf8;

– 在cmd窗口中(未登录的状态下)

mysql -uroot -p db60 < d:/db40.sql

2、恢复数据库方式二:

在cmd窗口中(已登录的状态下),可以通过source执行指定位置的SQL文件:

source sql文件的位置

示例:将d:/db40.sql文件中的数据恢复到db80库中

– 在cmd窗口中(已登录的状态下),先创建db80库,进入db80库:

create database db80 charset utf8;
use db80;

– 再通过source执行指定位置下的sql文件:

source d:/db40.sql

Navicat软件的使用

Navicat Premium是一套带图形用户界面的数据库管理工具,让你从单一应用程序中同时连接MySQL、MariaDB、MongoDB、SQL Server、Oracle、PostgreSQL 和 SQLite数据库。使用Navicat可以快速、轻松地创建、管理和维护数据库。

1、使用navicat连接mysql服务器(使用cmd连接mysql服务器)
2、查看所有库、进入数据库、创建数据库、删除数据库、修改数据库
3、创建表、查看表、修改表、删除表
4、新增表记录、查询表记录、修改表记录、删除表记录
5、使用navicat书写SQL语句操作数据库、表和表记录
...

哔哩哔哩视频链接:https://www.bilibili.com/video/BV1yA41147Vi/

扩展内容

现创建学生表:

use test; -- 进入test库
drop table if exists stu; -- 删除学生表(如果存在)
create table stu( -- 创建学生表
    id int, -- 学生id
    name varchar(20), -- 学生姓名
    gender char(1), -- 学生性别
    birthday date -- 出生年月
);

修改表—新增列

语法:ALTER TABLE tabname ADD col_name datatype [DEFAULT expr][,ADD col_name datatype…];

1、往stu表中添加score列,double类型

alter table stu add score double;

修改表—修改列

语法:ALTER TABLE tabname MODIFY (col_name datatype [DEFAULT expr][,MODIFY col_name datatype]…);

1、修改id列,将id设置为主键

alter table stu modify id int primary key;

2、修改id列,将id主键设置为自动增长

alter table stu modify id int auto_increment;

修改表—删除列

语法:ALTER TABLE tabname DROP [COLUMN] col_name;

1、删除stu表中的score列

alter table stu drop score;

添加或删除主键及自增

思考:a) 在建表时,如何为id指定主键约束和自增?

b) 建好的表,如何通过修改添加主键约束和自增?

c) 如何删除表中的主键约束和自增?

1、创建stu学生表,不添加主键自增, 查看表结果

use mydb1; -- 切换到mydb1库
drop table if exists stu; -- 删除stu学生表(如果存在)
create table stu( -- 重建stu学生表,没有主键自增
    id int,
    name varchar(20),
    gender char(1),
    birthday date
);
desc stu; -- 查看表结构

表结构如下: 没有主键约束和自增。
在这里插入图片描述
2、如果表没有创建,或者要删除重建,在创建时可以指定主键或主键自增

drop table if exists stu; -- 删除stu表
create table stu( -- 重新创建stu表时,指定主键自增
    id int primary key auto_increment,
    name varchar(20),
    gender char(1),
    birthday date
);
desc stu; -- 查看表结构

表结构如下: 已经添加了主键约束和自增。

在这里插入图片描述
3、如果不想删除重建表,也可以通过修改表添加主键或主键自增

再次执行第1步,创建stu学生表,不添加主键自增,查看表结果

– 例如: 将stu学生表中的id设置为主键和自动增长

alter table stu modify id int primary key auto_increment;
desc stu; -- 查看表结构

在这里插入图片描述
如果只添加主键约束,不设置自增

alter table stu modify id int **primary key**;

如果已经添加主键约束,仅仅设置自增,但需注意:

(1)如果没有设置主键,不可添加自增

(2)只有当主键是数值时,才可以添加自增

alter table stu modify id int **auto_increment**;

4、如果想删除主键自增

– 删除主键自增时,要先删除自增

alter table stu modify id int;

– 再删除主键约束

alter table stu drop primary key;
desc stu; -- 查看表结构

在这里插入图片描述

添加外键约束

1、添加外键方式一:建表时添加外键

现有部门表如下:

– 创建部门表

create table dept(
	id int primary key auto_increment, -- 部门编号
	name varchar(20) -- 部门名称
);

要求创建员工表,并在员工表中添加外键关联部门主键

– 创建员工表

create table emp(
    id int primary key auto_increment, -- 员工编号
    name varchar(20), -- 员工姓名
    dept_id int, -- 部门编号
    foreign key(dept_id) references dept(id) -- 指定dept_id为外键
);

2、添加外键方式二:建表后添加外键

现有部门表和员工表:

– 创建部门表

create table dept(
    id int primary key auto_increment, -- 部门编号
    name varchar(20) -- 部门名称
);

– 创建员工表

create table emp(
    id int primary key auto_increment, -- 员工编号
    name varchar(20), -- 员工姓名
    dept_id int -- 部门编号
);

– 如果表已存在,可以使用下面这种方式:

alter table emp add constraint fk_dept_id foreign key(dept_id) references dept(id);

其中 fk_dept_id (名字由自己定义),是指外键约束名称,也可以将【constraint fk_dept_id】省略,MySQL会自动分配一个外键名称,将来可以通过该名称删除外键。

foreign key(dept_id)中的dept_id为外键

删除外键约束

1、首先通过 “show create table 表名”语法,查询含有外键表的建表语句,例如:

show create table emp;

显示结果如下:
在这里插入图片描述
其中,emp_ibfk_1是在创建表时,数据库为外键约束指定的一个名字,删除这个名字即可删除外键关系,例如:

alter table emp drop foreign key emp_ibfk_1;

在这里插入图片描述
外键删除成功!

添加外键约束(多对多)

– 现有学生(stu)表和教师(tea)表:

– 创建学生表

create table stu(
    stu_id int primary key auto_increment, -- 学生编号
    name varchar(20) -- 学生姓名
);

– 创建教师表

create table tea(
	tea_id int primary key auto_increment, -- 教师编号
	name varchar(20) -- 教师姓名
);

– 添加第三方表(stu_tea)表示学生表和教师表关系

– 创建学生和教师关系表

create table stu_tea(
    stu_id int, -- 学生编号
    tea_id int, -- 教师编号
    primary key(stu_id,tea_id), -- 设置联合主键
    foreign key(stu_id) references stu(stu_id), -- 添加外键
    foreign key(tea_id) references tea(tea_id) -- 添加外键
);

其中为了防止重复数据,将stu_id和tea_id设置为联合主键。

将stu_id设置为外键,参考stu表中的stu_id列

并将tea_id设置为外键,参考tea表中的tea_id列

级联更新、级联删除

– 创建db20库、dept表、emp表并插入记录

– 删除db20库(如果存在),并重新创建db20库

drop database if exists db20;
create database db20 charset utf8;
use db20;

– 创建部门表, 要求id, name字段

create table dept(
	id int primary key auto_increment, -- 部门编号
	name varchar(20) -- 部门名称
);

– 往部门表中插入记录

insert into dept values(null, '财务部');
insert into dept values(null, '人事部');
insert into dept values(null, '科技部');
insert into dept values(null, '销售部');

– 创建员工表, 要求id, name, dept_id

create table emp(
    id int primary key auto_increment, -- 员工编号
    name varchar(20), -- 员工姓名
    dept_id int, -- 部门编号
    foreign key(dept_id) references dept(id) -- 指定外键
    on update cascade -- 级联更新
    on delete cascade -- 级联删除
);
insert into emp values(null, '张三', 1);
insert into emp values(null, '李四', 2);
insert into emp values(null, '老王', 3);
insert into emp values(null, '赵六', 4);
insert into emp values(null, '刘能', 4);

级联更新:主表(dept表)中的主键发生更新时(例如将销售部的id改为40),从表(emp表)中的记录的外键数据也会跟着该表(即赵六和刘能的部门编号也会更新为40)

级联删除:如果不添加级联删除,当删除部门表中的某一个部门时(例如删除4号部门),若该部门在员工表中有对应的员工(赵六和刘能),删除会失败!

若果添加了级联删除,当删除部门表中的某一个部门时,若该部门在员工表中有对应的员工,会在删除部门的同时,将员工表中对应的员工也删除!

where中不能使用列别名

SQL语句的书写顺序:

select * | 列名 -- 确定要查询的列有哪些
from 表名 -- 确定查询哪张表
where 条件 -- 通过筛选过滤,剔除不符合条件的记录
group by 分组的列 -- 指定根据哪一列进行分组
having 条件 -- 通过条件对分组后的数据进行筛选过滤
order by 排序的列 -- 指定根据哪一列进行排序
limit (countPage-1)*rowCount, rowCount -- 指定返回第几页记录以及每页显示多少条

SQL语句的执行顺序:

from 表名 -- 确定查询哪张表
where 条件 -- 通过筛选过滤,剔除不符合条件的记录
select * | 列名 列别名 -- 确定要查询的列有哪些,
group by 分组的列 -- 指定根据哪一列进行分组
having 条件 -- 通过条件对分组后的数据进行筛选过滤
order by 排序的列 -- 指定根据哪一列进行排序
limit (countPage-1)*rowCount, rowCount

**** 关于where中不能使用列别名但是可以使用表别名?**

是因为,表别名是声明在from中,from先于where执行,先声明再使用没有问题,但是列别名是声明在select中,where先于select执行,如果先使用列别名,再声明,这样执行会报错!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值