ICode9

精准搜索请尝试: 精确搜索
首页 > 数据库> 文章详细

数据库之mysql入门笔记一

2021-05-15 22:33:39  阅读:106  来源: 互联网

标签:入门 -- 数据库 dept emp mysql id select name


笔记一
1: 数据库概述
1.1: 什么是数据库
	数据库是一个专业的存储和管理数据的仓库

	扩展内容:数据库的分类
		早期: 层次式数据库,网络型数据库
		现在: 关系型数据库,非关系型数据库
		现在市面上大部分用的还是关系型数据库

1.2: 什么是关系型数据库
	底层以二维表的形式保存数据的库,就是关系型数据库
	常见的关系型数据库有哪些?
		Oracle: 甲骨文公司提供的一款数据库产品,收费的,之前在Java中的市场份额超过50%。
			主要适用于一些大型或者超大型应用系统。

		SQL Server: 微软提供的一款数据库产品,收费,主要适用于一些中型或者大型的应用系统
		MySQL: 瑞典的一个公司(MySQLAB)提供的一款数据库产品,特点是小巧轻量,简单易用,适用于一些小型或中型的应用系统,如果做mysql集群,也可以用于一些大型或者超大型系统。免费!
			mysql被甲骨文收购了!

		DB2: IBM公司提供的一款数据库产品, 用于金融/银行等系统较多, 收费!
		SQLite: 迷你数据库, 用于嵌入式设备(手机/智能家居等产品)
		...

1.3: 数据库相关名字解释
	数据库服务器: 其实就是你安装的哪个mysql软件,将mysql安装在计算机上,那么这台计算机就可以作为数据库服务器使用,可以实现数据的存和取。一个数据库服务器中可以包含多个数据库。
	比如:装好的mysql服务器中自带了四个数据库
		+--------------------+
		| Database           |
		+--------------------+
		| information_schema |
		| mysql              |
		| performance_schema |
		| test               |
		+--------------------+

	数据库: 数据库就是存储数据的仓库,通常情况下一个网站(系统)中的所有数据会存放在一个数据库中
		京东网站的所有数据		db_jd
		淘宝网站的所有数据		db_taobao
		百度网站的所有数据		db_baidu
		...

	表: 数据库中的数据是安装类型存放的, 一类数据往往存储在一张表中, 一个数据库中可以创建多张表!
		京东网站的用户数据		tb_user
		京东网站的商品数据		tb_product
		京东网站的订单数据		tb_order
		...
	
	表记录: 一张表中可以包含多行表记录, 一张表中用于存储一类信息, 一行表记录就用于存储某一个具体的数据
		数据库中的表		java中的类(student)
		表记录			对象
		
1.4: SQL语言
	SQL语言是一门操作关系型数据库的通用的语言(学会了SQL可以操作所有的关系型数据库)
	SQL语言可以操作的有:
		1)查看库、创建库、删除库、修改库(了解)
		2)创建表、删除表、修改表(扩展内容中)、查看表
		3)新增表记录、删除表记录、修改表记录、查询表记录(数据)
		4)存储过程/视图/索引等也可以操作
	SQL语言是一门通用的操作关系型数据库的语言,但每个数据库厂商为了增强自己数据库的功能,都提供了少量的"方言"(独有的SQL语句),SQL语言通用,但方言不通用!

1.5: 如何连接mysql服务器(cmd窗口)
	方式一: mysql -u用户名 -p密码
		mysql中默认有一个超级管理员(具有所有权限),用户名就是root
	方式二: mysql -u用户名 -p
		在下一行键入密码
	方式三: mysql -u用户名 -p -h主机名或ip地址 -P端口
		-h: 后面跟的是主机名或ip地址,如果不写-h,默认连接localhost(127.0.0.1)
		-P: 后面跟的是端口, 如果不写-P,默认端口是3306
	退出连接mysql服务器:
		exit
		quit
		或者直接关闭窗口
		
	扩展内容: SQL注释
		-- 单行注释(注意--后面的空格不要省去)
		#单行注释
		/* 多行注释 */
	扩展内容:
		\c: 取消当前sql语句的执行
	
----------------------------------
1.数据库及表操作
1.1.创建、删除、查看数据库
----------------------------------
-- 01.查看mysql服务器中所有数据库
	show databases;
-- 02.进入某一数据库(进入数据库后,才能操作库中的表和表记录)
-- 语法:USE 库名;
	use mysql; -- 进入mysql数据库
	use test; -- 进入test数据库
	
-- 查看已进入的库
	select database();

-- 03.查看当前数据库中的所有表
-- 先进入某一个库,再查看当前库中的所有表
	use test;
	show tables;
	
-- 04.删除mydb1库
-- 语法:DROP DATABASE 库名;
	drop database test; -- 删除test库
	
	drop database mydb1; 
	-- 删除mydb1库,如果删除的库不存在,会报错!
	
-- 思考:当删除的库不存在时,如何避免错误产生?
	drop database if exists mydb1; 
	-- 删除mydb1库,如果存在则删除mydb1,如果不存在则不执行删除操作,也不会报错
	
-- 05.重新创建mydb1库,指定编码为utf8
-- 语法:CREATE DATABASE 库名 CHARSET 编码;
	create database mydb1 charset utf8;
	-- 需要注意的是,mysql中不支持横杠(-),所以utf-8要写成utf8;
	
	-- 如果不存在则创建mydb1;
	create database if not exists mydb1 charset utf8;
	-- 如果不存在则创建mydb1,如果已存在,则不执行创建操作,也就不会报错了!
	
-- 06.查看建库时的语句(并验证数据库库使用的编码)
-- 语法:SHOW CREATE DATABASE 库名;
	show create database mydb1;
	
----------------------------------
1.2.创建、删除、查看表
----------------------------------
-- 07.进入mydb1库,删除stu学生表(如果存在)
-- 语法:DROP TABLE 表名;
	use mydb1;
	drop table if exists stu;
	
-- 08.创建stu学生表(编号[数值类型]、姓名、性别、出生年月、考试成绩[浮点型]),建表的语法:
	CREATE TABLE 表名(
		列名 数据类型,
		列名 数据类型,
		...
	  	列名 数据类型
	);
	创建stu表的SQL语句如下:
	create table stu(
		id int,
		name varchar(50), -- 50表示最多存50个字符
		gender varchar(10), 
		birthday date,
		score double
	);
	
	-- mysql中也有数据类型,这里先使用,后面再做说明!

	
-- 09.查看stu学生表结构
-- 语法:desc 表名
	desc stu;
	
----------------------------------
2.新增、更新、删除表记录
----------------------------------
-- 10.往学生表(stu)中插入记录(数据)
	select * from stu;
-- 语法:INSERT INTO 表名(列名1,列名2,列名3...) VALUES(值1,值2,值3...);
-- 创建mydb1库时一定要指定编码utf8,这样在库中创建的表也是utf8编码
-- 如果是在cmd中执行插入记录的语句,先 set names gbk; 再插入记录!
-- mysql中推荐使用单引号包裹字符串和日期(有些版本的数据库双引号包裹会报错!)
-- 一个cmd窗口只需要设置一次(set names gbk;)编码
-- 注意: 如果是要给表中的所有列都插入值,列名可以省略不写, 值的个数和顺序必须和表中创建的列的个数和顺序保持一致!
-- value后面只能跟一个括号,只能一次插入一条记录,values后面可以跟多个括号,用逗号分隔,一次可以插入多条数据!
	insert into stu(id, name, gender, birthday, score)
		      value(1, 'tom', 'male', '1985-10-11', 86);
	insert into stu values(2, '陈子枢', '男', '1978-10-12', 75);
	insert into stu values(3, '程晓宇', '女', '2000-6-12', 80);
		
-- 11.查询stu表所有学生的信息
-- 语法:SELECT 列名 | * FROM 表名
	select * from stu;
	
-- 12.修改stu表中所有学生的成绩,加10分特长分
-- 修改语法: UPDATE 表名 SET 列=值,列=值,列=值...[WHERE子句];
	update stu set score=score+10; 
	-- mysql不支持复合运算符 score+=10 错!

-- 13.修改stu表中编号为1的学生成绩,将成绩改为83分。
	update stu set score=83 where id=1; -- 只修改编号为1的学生的成绩
	update stu set id=22, name='刘沛霞', gender='女',
		birthday='1985-7-7', score=88 where id=2;
		
	提示:where子句用于对记录进行筛选过滤,保留符合条件的记录,将不符合条件的记录剔除。

-- 14.删除stu表中所有的记录
-- 删除记录语法: DELETE FROM 表名 [where子句]
-- 仅删除符合条件的
	delete from stu where id<2; -- 仅删除复合条件的记录
	delete from stu; -- 没有where默认删除所有记录
	
----------------------------------
3.查询表记录 
3.1.基础查询
-- 准备数据: 以下练习将使用db10库中的表及表记录,请先进入db10数据库!!
----------------------------------
-- 15.查询emp表中的所有员工,显示姓名,薪资,奖金
	select * from emp; -- *是通配符,表示查询所有的列
	select name,sal,bonus from emp; -- 查询指定的列(只会显示查询的列)
	
-- 16.查询emp表中的所有部门和职位
	select dept, job from emp;
	-- 上面的查询结果中有很多重复的记录,如何剔除重复记录,只保留一条?
	-- distinct用于去除重复记录,只保留一行!
	select distinct dept, job from emp;
	
3.2.WHERE子句查询
-- 17.查询emp表中【薪资大于3000】的所有员工,显示员工姓名、薪资
	select name,sal from emp where sal>3000;
	
-- 18.查询emp表中【总薪资(薪资+奖金)大于3500】的所有员工,显示员工姓名、总薪资
	select name,sal+bonus from emp where sal+bonus > 3500;
	-- null和任何数据运算结果都是null,这里应该将null值看做零来处理
	-- 方式一: 将所有的奖金为null的列值更新为0
		update emp set bonus=0 where bonus is null;
		
	-- 方式二: 在查询时将null值看做0来处理(这种方式对表中的数据不产生任何影响)
	-- ifnull(列名, 值)函数: 判断指定的列是否包含null值,如果有null值,用第二个值替换null值
		ifnull(bonus, 0) -- 对bonus列中的null进行处理,将null值用第二个参数0进行替换
	select name,sal+ifnull(bonus,0) from emp 
	where sal+ifnull(bonus,0) > 3500;
	
	-- 注意查看上面查询结果中的表头,如何将表头中的 sal+bonus 修改为 "总薪资"
	-- 使用`as`可以为表头指定别名(另外as可以省略)
	select name as 姓名,sal+ifnull(bonus,0) as 总薪资 from emp 
	where sal+ifnull(bonus,0) > 3500;
	-- as可以省略
	select name 姓名,sal+ifnull(bonus,0) 总薪资 from emp 
	where sal+ifnull(bonus,0) > 3500;
	
-- 19.查询emp表中【薪资在3000和4500之间】的员工,显示员工姓名和薪资
	select name,sal from emp where sal>3000 and sal<4500;
	-- and是并的意思(相当于java中的&),要求表中的记录要同时满足and两边的条件才算满足条件!

	select name,sal from emp where sal>=3000 and sal<=4500;

	-- 也可以使用`between 值1 and 值2` 来完成, 表示判断某个列的值是否在值1和值2之间(包含值1也包含值2)
	select name,sal from emp where sal between 3000 and 4500;
	
-- 20.查询emp表中【薪资为 1400、1600、1800】的员工,显示员工姓名和薪资
	select name,sal from emp where sal=1400 or sal=1600 or sal=1800;
	-- sal in(1400,1600,1800),意思时只要员工的薪资等于in括号里面的任何一个值就算满足条件
	select name,sal from emp where sal in(1400,1600,1800);
	
-- 21.查询薪资不为1400、1600、1800的员工,显示员工姓名和薪资
	select name,sal from emp where !(sal=1400 or sal=1600 or sal=1800);
	select name,sal from emp where not(sal=1400 or sal=1600 or sal=1800);

	select name,sal from emp where sal not in(1400,1600,1800);

-- 22.(自己完成) 查询emp表中薪资大于4000和薪资小于2000的员工,显示员工姓名、薪资。
	select name, sal from emp where sal>4000 or sal<2000;
	
-- 23.(自己完成) 查询emp表中薪资大于3000并且奖金小于600的员工,显示员工姓名、薪资、奖金。
	select name, sal, bonus from emp where sal>3000 and bonus<600;
	-- 查询结果有误差
	-- 对null值进行处理
	select name, sal, bonus from emp 
	where sal>3000 and ifnull(bonus,0)<600;

-- 24.查询没有部门的员工(即部门列为null值)
	select * from emp where dept is null;
	-- 判断一个列中的值是不是null不能用 = (等号), 而是用 is 判断
	
-- 思考:如何查询有部门的员工(即部门列不为null值)
	select * from emp where not(dept is null);
	select * from emp where dept is not null;

3.3.模糊查询(like)
	like可以用于做模糊查询(可以按照指定的模式进行搜索),需要结合%和_使用
	select * from emp where name like '王海涛';
	select * from emp where name='王海涛';
	在通过like进行模糊查询时,如果不配合%以及_使用,和=作用相同
	%: 是通配符,可以表示0个或多个任意字符
	_: 是通配符,只能表示1个任意字符
	
-- 25.查询emp表中姓名中以"刘"字开头的员工,显示员工姓名。
	select name from emp where name like '刘%';
	-- 查询姓名列中以'刘'开头的名字, %表示'刘'的后面可以是0个或者1个或者多个任意字符
	
-- 26.查询emp表中姓名中包含"涛"字的员工,显示员工姓名。
	select name from emp where name like '%涛%';
	-- %涛%,可以匹配三种情况,1)当第一个%匹配0个字符时,表示以'涛'开头 2)第二个%匹配0个字符时,表示以'涛'结尾, 3)当前后两个%至少匹配一个字符时,包含涛在中间的某一个位置(既不在开头,也不再结尾的情况)
	
-- 27.查询emp表中姓名以"刘"开头,并且姓名为两个字的员工,显示员工姓名。
	select name from emp where name like '刘_';
	select name from emp where name like '刘__';
	-- 刘_,可以匹配姓名中以'刘'开头,并且刘的后面只能有一个字符的情况
	-- 刘__,可以匹配姓名中以'刘'开头,并且刘的后面只能有两个字符的情况
	
3.4.多行函数查询
	多行函数也叫做聚合函数(聚集函数), 常见的多行函数有:
	(多行函数会默认过滤null值,即不统计null值)
	count(列名 | *): 
		count(列名): 表示统计当前列的值有多少个(不统计null值)
		count(*): 以行为单位,统计查询结果中有多少行记录
	max(列名): 表示统计当前这一列中所有值中的最大值
	min(列名): 表示统计当前这一列中所有值中的最小值
	sum(列名): 表示统计当前这一列中所有值的和(也就是说会将这一列中所有的值加在一起返回)
	avg(列名): 表示统计当前这一列中所有值的平均值(这一列中所有值的和 / 不是null值的个数 )
	
-- 28.统计[emp表中薪资大于3000的员工]个数
	select count(*) from emp where sal>3000;
	
	select count(*), name from emp where sal>3000;
	-- 在进行统计时,不要添加额外的列,因为没有任何意义(这里的name只会将第一行的name显示出来)
	
-- 29.求emp表中的最高薪资
	select max(sal) from emp; 
	select min(sal) from emp; 
	
	select max(sal), name from emp; 
	-- 在进行统计时,不要添加额外的列,因为没有任何意义(这里的name也是只会将第一行的name显示出来)
	-- 这里的最高薪资和姓名没有任何关系, 薪资是所有薪资中的最大值,但name就是结果中的第一行的name
	
-- 30.统计emp表中所有员工的薪资总和(不包含奖金)
	select sum(sal) from emp; -- 所有员工薪资总和
	select sum(bonus) from emp; -- 所有员工奖金总和
	-- 虽然bonus列中有null值,但是在通过多行函数统计时,遇到null会直接剔除,不会参与统计!

-- 31.统计emp表员工的平均薪资(不包含奖金)
	select avg(sal) from emp; -- 所有薪资的平均值
	select avg(bonus) from emp; -- 所有奖金的平均值
	select sum(bonus) / count(bonus) from emp; -- 所有奖金的平均值

	-- 统计emp表员工的平均总薪资(包含奖金)
	select avg(sal+bonus) from emp;
	-- 错!,因为韩少云的薪资(5000)加上奖金(null),结果是null,会被avg直接过滤
	select avg(sal)+avg(bonus) from emp;
	-- 错!,avg(sal)由于sal中没有null值,是总薪资/12, 而avg(bonus)由于bonus中有一个null值,是总奖金/11
	select avg(sal+ifnull(bonus,0)) from emp;
	

	不分组使用多行函数 和 分了组使用多行函数的区别?
	-------------------------------------
	select count(*) from emp;
	-- 如果没有分组,其实在使用count统计时会默认将整个查询结果当成一个组,这样的话,统计这一个组的人数,返回的就是一个数值;
	select count(*) from emp group by dept;
	-- 如果分了组(按照部门分了3组), 再使用count统计时会根据每个组来进行统计,有多少个组,就会统计出多少个结果(现有3个组,因此会统计出三个组的人数)
	select count(*),dept from emp
	-- 如果没有分组, 再通过多行函数进行统计时, 不要显示额外的列, 因为没有任何意义
	-- (比如,上面的dept只会将第一行的dept显示出来, 和前面统计的人数没有任何关系)
	
	select count(*),dept from emp group by dept;
	-- 如果分了组, 再通过多行函数进行统计时, 可以将进行分组的列和多行函数一起显示
	-- 比如:按照dept分了组(分成了3组,此时每组中的dept是相同), 可以将dept这一列的值显示出来, 因为是根据这个列分的组,每组中的这个列的值也是相同的,所以显示这个组中的dept列的任意一个值都是一样的。
	-------------------------------------

3.5.分组查询
	语法:SELECT 列 | * FROM 表名 [WHERE子句] GROUP BY 列;
-- 32.对emp表,按照部门对员工进行分组,查看分组后效果。
	select id,name,dept from emp group by dept;
	-- 如何证明上面查询的结果是三组,而不是三条记录?
	-- 可以通过多行函数对分组后的数据进行统计,分成几组,就会统计出几个结果。
	select count(*) from emp group by dept;

-- 33.对emp表按照职位进行分组,并统计每个职位的人数,显示职位和对应人数
	select id,name,job from emp group by job;
	+----+--------+------+
	| id | name   | job  |
	+----+--------+------+
	| 10 | 韩少云   | CEO  |
	|  4 | 陈子枢   | 总监 |
	|  1 | 王海涛   | 讲师 |
	+----+--------+------+
	-- 显示职位和对应人数
	select count(*),job from emp group by job;
	+----------+------+
	| count(*) | job  |
	+----------+------+
	|        1 | CEO  |
	|        2 | 总监  |
	|        9 | 讲师  |
	+----------+------+

-- 34.对emp表按照部门进行分组,求每个部门的最高薪资(不包含奖金),显示部门名称和最高薪资
	select id,name,sal,dept from emp group by dept;
	+----+--------+------+--------+
	| id | name   | sal  | dept   |
	+----+--------+------+--------+
	| 10 | 韩少云   | 5000 | NULL   |
	|  1 | 王海涛   | 1800 | 培优部   |
	|  6 | 王克晶   | 3700 | 就业部   |
	+----+--------+------+--------+
	-- 显示部门名称和最高薪资
	select max(sal), dept from emp group by dept;
	+----------+--------+
	| max(sal) | dept   |
	+----------+--------+
	|     5000 | NULL   |
	|     4500 | 培优部   |
	|     4850 | 就业部   |
	+----------+--------+

3.6.排序查询
	语法:SELECT 列名 FROM 表名 [where子句] [group by 列] ORDER BY 列名 [ASC|DESC]
	ASC(默认)升序,即从低到高;DESC 降序,即从高到低。
-- 35.对emp表中所有员工的薪资进行升序(从低到高)排序,显示员工姓名、薪资。
	select name, sal from emp order by sal; -- 默认是asc,就是升序
	select name, sal from emp order by sal asc; -- 默认是asc,就是升序
	
-- 36.对emp表中所有员工的奖金进行降序(从高到低)排序,显示员工姓名、奖金。
	select name, bonus from emp order by bonus desc; -- 降序必须写desc

	-- 按照奖金降序排序,如果奖金相同,再按照薪资降序排序
	select name, bonus, sal from emp order by bonus desc, sal desc; 
	
3.7.分页查询
	在mysql中,通过limit进行分页查询,查询公式为:
	limit (页码-1)*每页显示记录数, 每页显示记录数
-- 37.查询emp表中的所有记录,分页显示:每页显示3条记录,返回所有页的数据
	-- 查询emp表中的记录,每页3条,查询第1页
	select * from emp limit 0, 3;
	-- 查询emp表中的记录,每页3条,查询第2页
	select * from emp limit 3, 3;
	-- 查询emp表中的记录,每页3条,查询第3页
	select * from emp limit 6, 3;
	-- 查询emp表中的记录,每页3条,查询第4页
	select * from emp limit 9, 3;
	
-- 38.求emp表中薪资最高的前3名员工的信息,显示姓名和薪资
	-- 根据薪资降序排序(从高到低), 第一条就是薪资最高的记录
	select name, sal from emp order by sal desc;
	-- 在上面查询的基础上, 将第一条取出来(每页显示1条,查询第1页)
	select name, sal from emp order by sal desc limit 0,1;

	-- 根据薪资降序排序, 每页显示3条, 查询第一页就是薪资最高的前3名
	select name, sal from emp order by sal desc limit 0,3;
	
3.8.其他函数
	curdate() -- 获取当前日期: 年月日
	curtime() -- 获取当前时间: 时分秒
	sysdate()/now() -- 获取当前日期+时间, 年月日 时分秒
	year('2020-8-10'): 返回日期中的年份, 2020
	month('2020-8-10'): 返回日期中的月份, 8
	day('2020-8-10'): 返回日期中的天数, 10
	hour('2020-8-10 12:34:56'): 返回时间中的小时, 12
	minute('2020-8-10 12:34:56'): 返回时间中的分钟数, 34
	second('2020-8-10 12:34:56'): 返回时间中的秒值, 56
	------------------------------------------
	concat(s1,s2,...sn): 将 s1、s2、...sn 拼接在一起返回
		例如: name('王海涛'),birthday('1995-03-25'),sal(2450)
		select concat('王海涛', '1995-03-25', 2450);
	concat_ws(x,s1,s2,...sn): 
		将 s1、s2、...sn 拼接在一起,并且每两个拼接时会通过x作为分隔符进行拼接,再返回
		select concat_ws(',' ,'王海涛', '1995-03-25', 2450);
		
-- 39.查询emp表中所有【在1993和1995年之间出生】的员工,显示姓名、出生日期。
	select name, birthday from emp where birthday between 1993 and 1995;
	-- 错误,由于birthday是日期类型(年月日格式),而1993和1995都是数值,没法比较
	
	-- 方式一: 将1993和1995两个数值转成日期格式,再和birthday进行比较!
	select name, birthday from emp 
	where birthday between '1993-1-1' and '1995-12-31';

	-- 方式二: 将birthday中的年份用year函数提取出来,再和1993以及1995进行比较
	select name, birthday from emp
	where year(birthday) between 1993 and 1995;
	
-- 40.查询emp表中本月过生日的所有员工
	-- 首先通过month函数从当前日期中获取本月是几月: month( now() )
	-- 再通过month函数从员工的birthday中获取出生月份: month( birthday )
	select * from emp where month( now() ) = month( birthday );

-- 41.查询emp表中员工的姓名和薪资(薪资格式为: xxx(元) )
	select name, concat(sal, '(元)') from emp;
		
-- 补充练习:查询emp表中员工的姓名和薪资(薪资格式为: xxx/元 )
	select name, concat(sal, '/元') from emp;
	
----------------------------------
补充内容1: mysql的数据类型
1.1:数值类型
	mysql中提供了多种数值类型,其中包括:
		tinyint、smallint、int、bigint、float、double、decimal等
		其中较为常用的就是 int、double
1.2.字符串类型
	char类型: 定长字符串, char(n), n的范围是: 0~255个字符
		char类型之所以叫做定长字符串,是因为一旦确定了n的最大字符数,不管存的数据是多少,该数据占用的空间就是n个字符。例如:name char(10), 存入'张三丰', 存入了3个字符,剩余的空间会用空格补全.
		因此char类型可能会浪费空间!

		所以char类型适合存储长度固定的数据, 比如:
			student_id char(11), 用这个列存储所有学生的编号.
			idcard char(18), 用这个列存储所有人的身份证号.
		char类型相比varchar类型速度要快一些,因为char类型只需要判断一个数据是否能存入该列中,而不需要将剩余的空间留给别的数据使用!
		
	varchar类型: 变长字符串, varchar(n), n的范围是: 0~?个字符
		varchar类型之所以叫变长字符串,是因为n只是限制该列中最多能存的字符数, 如果你实际存的数据量小于n,剩余的空间还可以留给别的数据使用。例如:name char(10),  存入'张三丰', 存入了3个字符,剩余的7个空间会留给别的数据使用!
		因此varchar类型不会浪费空间!
		所以varchar类型适合存储长度不固定的数据(长度固定的数据我们会使用char类型)
		
		varchar类型最大能存的数据量是 0~65535个字节
		latin1编码中,1个字符对应1个字节, n的最大值约是 65535/1 (max = 65532)
			测试表: create table t2(id int, name varchar(60000)) charset latin1;
		gbk编码中,1个字符对应2个字节, n的最大值约是 65535/2 (max = 32766)
			测试表: create table t3(id int, name varchar(40000)) charset gbk;
		utf8编码中,1个字符对应3个字节, n的最大值约是 65535/3 (max = 21844)
			测试表: create table t4(id int, name varchar(20000)) charset utf8;
		
		create table t5(id int, name varchar(5));

	面试题: char和varchar有什么区别?
		1) char和varchar存的数量是不同的, char类型最多能存255个字符, varchar类型最多能存65535个字节
		2) char类型如果存的数据量小于最大长度, 剩余的空间会使用空格填充, 因此可能会浪费空间
			所以char类型适合存储长度固定的数据, 这样既不会浪费空间, 效率还比varchar略高
		3) varchar类型如果存的数据量小于最大长度, 剩余的空间会留给别的数据使用
			所以varchar类型适合存储长度不固定的数据, 这样虽然没有char存储效率高, 但至少不会浪费空间。
1.3: 日期类型
	date: 日期类型, 格式是: 年月日
	time: 时间类型, 格式是: 时分秒
	datetime: 日期+时间,格式是: 年月日 时分秒
	timestamp: 时间戳, 格式和datetime相同, 也是: 年月日 时分秒, 和datetime不同的是:
		1) 范围上: datetime范围是: 1000~9999(年份)
			timestamp范围是: 1970到2038年
		2) 实际存的数据: datetime实际存的就是一个`年月日 时分秒`格式的日期+时间
			而timestamp实际存储的是这个从1970年1月1日到这个日期+时间的时间毫秒值
			create_time timestamp, 2018-2-3 14:45:56, 实际存储的是 1970年1月1日到2018-2-3 14:45:56时间的时间毫秒值
		3) 在使用上: timestamp可以设置自动获取当前时间作为值插入到表中, 而datetime不可以.
			2018-2-3 14:45:56
		
补充内容2: mysql的字段约束
	----------------------------------
	use mydb1;
	drop table if exists stu;
	create table stu(
		id int primary key, -- id是主键,值不能为空且不能重复
		name varchar(50), -- 50表示最多存50个字符
		gender varchar(10), 
		birthday date,
		score double
	);
	insert into stu value('a', '张飞', '男', '1980-1-2', 80);
	insert into stu value('b', '刘备', '男', '1981-2-2', 90);
	insert into stu value('c', '关羽', '男', '1982-3-2', 85);
	----------------------------------
2.1: 主键约束
	如果一个列添加了主键约束, 那么这个列的值就必须是非空的且不能重复
	主键通常用于唯一的表示一行表记录(就像人的身份证号一样)
	一张表中通常都会有且只有一个主键
	添加主键约束的格式:
		create table stu(
			id int primary key,
			...
		);
	----------------------------------
	如果id是主键并且是数值类型,为了方便维护,可以设置主键自增策略,设置方法:
		create table stu(
			id int primary key auto_increment,
			...
		);
	在设置完主键自增之后,表中会维护一个AUTO_INCREMENT的值,这个值从1开始,如果插入主键时没有给主键赋值,就会从AUTO_INCREMENT这里获取一个值再作为主键插入到表中。再用完之后,会自动将AUTO_INCREMENT的值加1
	
2.3: 非空约束
	如果一个列添加了非空约束, 那么这个列的值就不能为空(null), 但可以重复
	添加非空约束的格式:
		create table stu(
			...
			gender varchar(10) not null,
			...
		);

2.4: 唯一约束
	如果一个列添加了唯一约束, 那么这个列的值就不能重复, 但可以为空(null)
	比如: 网站绑定的邮箱, 前期可以不绑定, 即可以为null, 但一旦绑定, 这个邮箱是不能和其他账号的邮箱重复的。
	添加唯一约束的格式:
		create table stu(
			...
			email varchar(50) unique,
			...
		);
		create table stu(
			...
			username varchar(50) unique not null, -- 用户名既不能重复,也不能为空
			...
		);
	----------------------------------
	主键约束 和 (非空+唯一约束) 有什么区别:
		1) 主键约束 和 非空+唯一 特点是相同的, 都是不能为空且不能重复
		2) 主键约束除了非空且不能重复之外, 还可以表示唯一一行表记录, 即作为表记录的唯一标识。
	
补充内容3: mysql的外键约束
	外键约束不同于主键、非空、唯一约束,外键约束是用于表示两张表的对应关系

	1、如何保存部门(dept) 和 员工(emp)的对应关系?
		可以在员工表中添加一个列(比如: dept_id)用于保存部门的编号, 就可以保存员工和部门的对应关系(可以将dept_id设置为外键, 当然也可以不这样做)
	2、添加外键和不添加外键有什么区别?
	1)如果不添加外键:对于数据库来说,dept_id这个列就是一个普通的列,数据库也不会知道 dept 和 emp两张表存在任何关系,自然也不会帮我们去维护这层关系。
		假如,现在要删除dept表中的某一个部门(4号部门),删除后就会造成emp表中的赵六和刘能找不到部门,而赵六和刘能后面对应的dept_id值为4, 这个数据也变成了冗余数据。
		这样会破坏数据库中数据的完整性和一致性!
	2)如果将dept_id添加为外键:将dept_id添加为外键就等同于:通知数据库 dept 和 emp 两张表存在对应关系, 而且emp表中的dept_id列要参考dept表中的id列。
		这样数据库就会帮我们维护这两张表的对应关系,如果此时删除dept表中的某一个部门(4号部门),数据库会首先检查这个4号部门在emp表中还有没有对应的员工,如果有,数据库就会阻止我们删除!这样就保证了数据的完整性和一致性。
		如果非要删除,可以将4号部门里面的员工记录转移到其他部门或者删除,只要保证所删除部门中没有对应的员工即可!
	
补充内容4: 表关系
	1对多(多对1): 在这种关系中,往往会在多的一方添加列,保存一的一方的主键(可以设置外键,当然也可以不设置,看需求),比如:
		部门表(1)	员工表(*), 在员工表(*)中添加列(dept_id)保存部门的编号
		班级表(1) 学生表(*), 在学生表(*)中添加列(class_id)保存班级的编号

	1对1: 在这种关系中,可以在任意一方添加列保存另一方的主键(可以设置外键,当然也可以不设置,看需求), 比如:
		班级表(1) 教室表(1), 在班级表(1)添加列(room_id)来保存教室的编号
		班级表(1) 教室表(1), 在教室表(1)添加列(class_id)来保存班级的编号
	
	多对多: 在这种关系中,在任何一方添加列保存另一方的主键都不合适
		此时可以再创建一张表,在这种表中分别添加两个列(stuid,teaid), 分别用于保存学生表的主键和教师表的主键,以此来保存学生和教师的对应关系!
----------------------------------
4.多表查询
4.1.连接查询
-- 准备数据: 以下练习将使用db30库中的表及表记录,请先进入db30数据库!!!
----------------------------------
-- 42.查询部门和部门对应的员工信息
	select * from dept,emp;
	以上查询有一个名字叫做笛卡尔积查询
	笛卡尔积查询: 其实就是同时查询两张表,其中一张表有m条记录,另外一张表有n条记录,查询的结果是m*n条,但这种查询结果中包含大量错误的数据,所以我们一般不会直接使用这种查询。

	在笛卡尔积查询的基础上,通过where子句将错误的数据剔除,只保留正确的数据,这就是连接查询。
		select * from dept,emp where emp.dept_id=dept.id;

	内连接查询: 
		select * from dept inner join emp on emp.dept_id=dept.id;
----------------------------------
4.2.连接查询
----------------------------------
-- 43.查询【所有部门】及部门对应的员工,如果某个部门下没有员工,员工显示为null
	如果两张表在连接查询时,要求查询出其中一张表的所有数据,此时可以使用左外连接查询或者右外连接查询。
	
	select * from dept left join emp on emp.dept_id=dept.id;
	-- 如果要查询部门表(dept)中的所有数据,而部门表(dept)在左边,此时可以使用左外连接查询,就可以查询出所有的部门信息(而员工信息只显示和部门对应的)
	
	【左外连接查询】:可以将左边表中的所有记录都查询出来,右边表只显示和左边相对应的数据,如果左边表中某些记录在右边没有对应的数据,右边显示为null即可。

-- 44.查询【所有员工】及员工所属部门,如果某个员工没有所属部门,部门显示为null
	select * from dept right join emp on emp.dept_id=dept.id;
	
	【右外连接查询】:可以将右边表中的所有记录都查询出来,左边表只显示和右边相对应的数据,如果右边表中某些记录在左边没有对应的数据,可以显示为null。
	
	-- 查询所有部门以及所有员工, 如果部门没有对应员工,可以对应null,如果员工没有对应部门,也可以对应null,这种情况应使用全外连接查询。
	-- 但,mysql不支持全外连接查询!但可以通过union来模拟这种查询!
	union关键字是用于将两个查询结果上下合并在一起显示,并且会去除重复记录。
	union all关键字是用于将两个查询结果上下合并在一起显示,不会去除重复记录
	能够使用union和union all合并结果的查询语句,必须符合:
		1)两条SQL语句查询的结果列数必须相同
		2)两条SQL语句查询的结果列名必须相同(低版本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;

	select * from dept left join emp on emp.dept_id=dept.id
	union all
	select * from dept right join emp on emp.dept_id=dept.id;
	
----------------------------------
4.3.子查询练习
-- 准备数据:以下练习将使用db40库中的表及表记录,请先进入db40数据库!!!
----------------------------------
-- 45.列出薪资比'王海涛'的薪资高的所有员工,显示姓名、薪资
	-- 求出'王海涛'的薪资是多少
	select sal from emp where name='王海涛';#2450
	-- 求出薪资比'王海涛'的薪资还高的所有员工
	select name, sal from emp where sal>(select sal from emp where name='王海涛');
	-- 将一个SQL语句的执行结果作为另外一条SQL语句的条件来执行, 这就是子查询!
	
-- 46.列出与'刘沛霞'从事相同职位的所有员工,显示姓名、职位
	-- 求出'刘沛霞'从事的职位
	select job from emp where name='刘沛霞'; -- 推销员
	-- 求出和'刘沛霞'具有相同职位的员工
	select name, job from emp where job=(select job from emp where name='刘沛霞');
	
----------------------------------
4.4.多表查询练习
----------------------------------
-- 47.列出在'培优部'任职的员工,假定不知道'培优部'的部门编号,显示部门名称,员工名称。
	/*
	查询的列:select dept.name, emp.name
	查询的表:from dept, emp
	筛选条件:where emp.dept_id=dept.id
			and dept.name='培优部'
	 */
	SELECT dept.name, emp.name
	FROM dept, emp
	WHERE emp.dept_id=dept.id AND dept.name='培优部';
	----------------------------------
	SELECT dept.name, emp.name
	FROM dept INNER JOIN emp
	ON emp.dept_id=dept.id
	WHERE dept.name='培优部';
	
-- 48.(自查询)列出所有员工及其直接上级,显示员工姓名、上级编号,上级姓名

	/* emp e1(员工表) emp e2(上级表)
	查询的列: SELECT e1.name, e1.topid, e2.name
	查询的表: FROM emp e1, emp e2
	筛选条件: WHERE e1.topid=e2.id
	 */
	SELECT e1.name, e1.topid, e2.name
	FROM emp e1, emp e2
	WHERE e1.topid=e2.id;
	
-- 49.列出最低薪资大于1500的各种职位,显示职位和该职位的最低薪资
	/*
	列出职位: 
	1)求出各种职位的最低薪资
		先按照职位进行分组,职位相同为一组,再用min(sal)求每组中的最低薪资,也就是每种职位的最低薪资
		select job, min(sal) from emp group by job;
	2)求出有哪些职位的最低薪资是大于1500的
		select job, min(sal) from emp group by job where min(sal)>1500;-- 错误写法!
		1)where应在放在from子句后, group by子句前
		2)where中不能使用多行函数(列别名也不能用在where中)
		3)where是在分组之前之前,先过滤掉一些记录,再基于剩余的记录进行分组,
			而本地是先分组,再过滤,所以不能使用where,应该用having
	 */
	select job, min(sal) from emp group by job having min(sal)>1500;
	----------------------------------
	where和having的区别?
	1)where和having都是用于对表中的记录进行筛选过滤
	2)where用于在分组之前对记录进行筛选过滤,而having用于对分组之后的记录进行筛选过滤
	3)where子句中不能使用多行函数 和 列别名,但可以使用表别名!
		select name as 姓名, sal as 薪资 from emp e;
		-- 其中上面的'姓名','薪资'都是列别名, e是表别名
	4)having子句中可以使用多行函数 和 列别名 以及 表别名!
	----------------------------------
	
-- 50.列出在每个部门就职的员工数量、平均工资。显示部门编号、员工数量,平均薪资。
	select dept_id, count(*), avg(sal) from emp group by dept_id;
	
	select dept_id 部门编号, count(*) 员工数量, avg(sal) 平均薪资 
	from emp group by dept_id;
	
-- 51.列出受雇日期早于直接上级的所有员工,显示员工编号、员工姓名、部门名称、上级编号、上级姓名。
	/* emp e1(员工表), emp e2(上级表)
	查询的列:SELECT e1.id, e1.name, d.name, e2.id, e2.name
	查询的表:FROM emp e1, emp e2, dept d
	连接条件:WHERE e1.topid=e2.id
			 AND e1.dept_id=d.id
	筛选条件:  AND e1.hdate < e2.hdate
	 */
	SELECT e1.id, e1.name, d.name, e2.id, e2.name
	FROM emp e1, emp e2, dept d
	WHERE e1.topid=e2.id
		AND e1.dept_id=d.id
		AND e1.hdate < e2.hdate;
	
----------------------------------	
补充内容5: set names gbk;
	set names gbk;(这个命令是用在cmd窗口中)用来通知数据库服务器, 当前cmd窗口发送给服务器的数据的GBK的,那么服务器就会按照GBK编码来接收 cmd窗口发送过来的数据, 再将GBK的数据转换成utf8编码的数据存入数据库中!
	这个命令只能用在cmd窗口! 而且是每次新开一个cmd窗口都需要重新设置一次!
	像Navicat/SQLYog等工具不需要设置该命令,因为这些工具底层已经设置过编码了!
	
补充内容6: 数据库的备份和恢复
6.1.备份数据库
	1、备份单个数据库
		在cmd窗口(未登录、未连接到mysql服务器的界面)中,可以通过如下命令对指定的数据库进行备份:
		mysqldump -u用户名 -p密码 库名 > 备份文件的位置
		示例1: 对db40库中的数据(表,表记录)进行备份,备份到 d:/db40.sql 文件中
		mysqldump -uroot -proot db40 > d:/db40.sql

		注意: 1)如果输入命令回车之后没有提示错误,就说明备份成功了!
		2)备份单个数据库,其实只会备份这个库中的表和表记录,并不会备份库本身!
		
	2、备份多个数据库(比如备份两个数据库)
		在cmd窗口(未登录、未连接到mysql服务器的界面)中
		mysqldump -u用户名 -p密码 --databases 库名1 库名2 ... > 备份文件的位置
		
		示例2: 对db20 和 db40 库中的数据进行备份,备份到 d:/db2040.sql 文件中
		mysqldump -uroot -proot --databases db20 db40 > d:/db2040.sql
		
		注意: 1)如果输入命令回车之后没有提示错误,就说明备份成功了!
		2)备份多个数据库,不仅会备份这个库中的表和表记录,同时会备份库本身!

		或者如果想备份mysql服务器中的所有的库以及库中的表和表记录,可以通过如下命令:
		mysqldump -uroot -proot -A > d:/dball.sql
		输入完后回车如果没有提示错误(error是错误,警告不是错误可以忽略),即表示备份成功!
		
6.2.恢复数据库
	1、恢复数据库方式一(单个数据库):
		在cmd窗口中(未登录的状态下),可以通过如下命令对指定的数据库进行恢复
		mysql -u用户名 -p密码 库名 < 备份文件的位置
		示例1: 将 d:/db40.sql 文件中的数据恢复到 db60 库中
		1) 先在cmd窗口中(已登录的状态下), 先创建db60库
			create database db60 charset utf8;
		2) 再回到cmd窗口中(未登录的状态下), 执行下面恢复的命令
			mysql -uroot -proot db60 < d:/db40.sql

	2、恢复数据库方式二(多个数据库)
		在cmd窗口中(已登录的状态下),可以通过source命令来执行指定位置的sql文件中的sql语句:
		source sql文件的位置
		示例2: 将 d:/db40.sql 文件中的数据恢复到 db80 库中
		1) 先创建db80库, 并进入到db80库
			create database db80 charset utf8;
			use db80;
		2) 再通过source命令执行 d:/db40.sql 文件中的sql语句
			source d:/db40.sql

		示例3: 将 d:/db2040.sql 文件中的数据恢复回来
		1) 将db20,db40库删除(模拟数据丢失)
			drop database db20;
			drop database db40;
		2) 再通过source命令执行 d:/db2040.sql 文件中的sql语句
			source d:/db2040.sql
	
补充内容7: navicat软件的使用
	1)下发的navicat软件是绿色解压版,解压之后进入到目录,找到navicat.exe双击即可启动程序
	2)点击左上角的连接图标,输入连接名(就是个自定义的名字),输入主机或ip地址,以及端口,再输入用户名和密码,点击左下角的连接测试,如果连接成功,点击确定即可!
	3)使用navicat进行如下操作:
		数据库操作: 创建库, 修改库, 删除库
		表操作: 创建表, 修改表, 删除表
		表记录操作: 新增表记录, 修改表记录, 删除表记录, 查询表记录
		在navict中执行单条sql语句,或者执行多条/所有sql语句

 

标签:入门,--,数据库,dept,emp,mysql,id,select,name
来源: https://blog.csdn.net/m0_56057949/article/details/116863698

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有