MySQL基础

MySQL的三层结构

数据库-表的本质任然是文件
在这里插入图片描述

数据在数据库中的存储方式

在这里插入图片描述

SQL语句的分类

  • DDL:数据定义语句(create表、库…)
  • DML:数据操作语句(增加insert、修改update、删除delete)
  • DQL:数据查询语句(select)
  • DCL:数据控制语句(管理数据库,比如用户权限grant revoke)

创建数据库

基本语法:

CREATE DATABASE [IF NOT EXISTS] db_name
                  [create_specification[,create_specification]...]
 create_specification:
     [DEFAULT] CHARACTER SET charset_name
     [DEFAULT] COLLATE collation_name                 
  1. CHARACTER SET : 指定数据库采用的字符集,默认为utf8mb4。
  2. COLLATE : 指定数据库字符集的校对规则(常用的utf8mb4_bin[区分大小写]、utf8mb4_general_ci[不区分大小写]),默认为utf8mb4_general_ci。

查看、删除数据库

显示数据库语句:

SHOW DATABASE

显示数据库创建语句:

SHOW CREATE DATABASE db_name

数据库删除语句(慎用):

DROP DATABASE [IF EXISTS] db_name

在创建数据库表的时候为了规避规避关键字,可以用反引号`解决

CREATE DATABASE `CREATE`
DROP DATABASE `CREATE`

备份恢复数据库

  • 备份数据库(注意:在DOS执行)cmd
mysqldump -u 用户名 -p -B 数据库1 数据库2 表n > 文件名.sql
  • 回复数据库(注意:进入SQLyog再执行)cmd
Source 文件名.sql

创建表

基本语法:

CREATE TABLE table_name
(
				field1 datatype,
				field2 datatype,
				field3 datatype,
)character set 字符集  collate 校对规则 engine 引擎

field:指定列名
datatype:指定列类型(字段类型)
character set:如不指定则为所在数据库字符集
collate:如不指定则为所在数据库校对规则
engine:引擎(后续单独讲解)
注意:创建表时要根据所需保存的数据创建相应的列,并根据数据的类型定义相应的列类型。
比如:创建一个user表,要求:id 整形;name 字符串;password 字符串;birthday 日期。

CREATE TABLE `user`
(
	id INT,
	`name` VARCHAR(255),
	`password` VARCHAR(255),
	`birthday` DATE 
)
CHARACTER SET utf8mb4 COLLATE utf8mb4_bin ENGINE INNODB

常用数据类型

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

CREATE TABLE t2
(
	birthday DATE,
	jobtime DATETIME,
	logintime TIMESTAMP 
		NOT NULL DEFAULT CURRENT_TIMESTAMP 
		ON UPDATE CURRENT_TIMESTAMP -- 如果希望timestamp自动更新,则需要配置
);
INSERT INTO t2(birthday, jobtime) VALUES('2022-11-11','2022-11-11 10:10:10')
SELECT * FROM t2
-- 如果我们跟新表的某条记录,logintiem会自动以当前时间记录

修改表

基本语法:

#添加
ALTER TABLE table_name
ADD                 (column datatype [DEFAULT expr]
						 [,column datatype]...);

#修改
ALTER TABLE table_name
MODIFY                 (column datatype [DEFAULT expr]
						 [,column datatype]...);

#删除
ALTER TABLE table_name
DROP                 (column)

查看表的结构: desc 表名; -- 可以查看所有的列
修改表名:Rename table 表名 to 表名;
修改表字符集:alter table 表名 character set 字符集; 

操作:

#修改表
-- 给t2表增加一个image列,varchar类型,要求在birthday后面
ALTER TABLE t2
	ADD image VARCHAR(32) 
	NOT NULL 
	DEFAULT ' '
	AFTER birthday
	
DESC t2

#修改image列,使其长度为60
ALTER TABLE t2
	MODIFY image VARCHAR(32) 
	NOT NULL 
	DEFAULT ' '
	
#删除image列
 ALTER TABLE t2
	DROP image
	
#将列名image改为sb
ALTER TABLE t2 
	CHANGE image sb VARCHAR(64)
	NOT NULL
	DEFAULT ' '

数据库CRUD语句(create创建、retrieve检索、update更新、delete删除)

insert语句

基本语法

INSERT INTO table_name[(column[,,column...])]
VALUES          (value [,value...]);

操作

创建一张商品表goods(id int , goods_name varchar(10) , price double);
CREATE TABLE 'goods'(
	id INT,
	goods_name VARCHAR(10),
	price DOUBLE);

添加数据
INSERT INTO `goods` (id, goods_name, price)
	VALUES(10, '苹果手机', 2000);
INSERT INTO `goods` (id, goods_name, price)
	VALUES(20, '华为手机', 3000);

insert语句基本细节

1、插入的数据应与字段的数据类型相同。比如把abc添加到int类型会报错
2、数据的长度一个在列的规定范围内。比如:不能将长度为80的字符串加入到长度为40的列中。
3、在values中列出的数据位置必须与被加入的列的排列位置相对应。
4、字符和日期型数据应包含在单引号‘’中。
5、列可以插入空值,前提是该字段允许为空。

insert into table_name ()
				value(null)

6、可以同时添加多段数据

insert into table_name(1,2,3)
				values(),(),()

7、如果是给表中的所有字段添加数据,可以不写前面的字段名称。
8、默认值的使用,当不给某个字段值时,如果有默认值就是默认值,否则报错。比如:没有指定not null ,没有填写时默认为null。

CREATE TABLE 'goods'(
	...
	price DOUBLE NOT NULL DEFAULT 10);

update语句

基本语法

UPDATE table_name
				SET col_name1=expr1 [, col_name2 = expr2 ...]
				[WHERE where_definition]

操作

--创建员工表employee
CREATE TABLE employee (
	id INT,
	user_name VARCHAR(10),
	brithday DATETIME,
	entey_date DATETIME,
	job VARCHAR(10),
	salary INT,
	`resume` VARCHAR(10)
	);
INSERT INTO employee (id, user_name, salary)
	VALUES(100,'小妖怪',2000),(101,'老妖怪',3200),(201,'老不死',2300),(203,'吸血鬼',2340);
	
--将所有员工的薪水修改为5000
UPDATE	employee SET salary = 5000

--将姓名小妖怪的员工薪水修改为3000
UPDATE	employee 
	SET salary = 3000
	WHERE user_name = '小妖怪'
	
--将姓名老妖怪的薪水在原有的基础上增加1000
UPDATE	employee 
	SET salary = salary + 1000
	WHERE user_name = '老妖怪'

update语句基本细节

1、update语法可以用新值更新原有表行中的各列。
2、set子句表示要修改哪些列和要赋予哪些值。
3、where子句指定更新哪些行。如果没有where子句,则更新所有的行。
4、如果需要修改多个字段,可以通过 set字段1=值1,字段2=值2…

delete语句

基本语法

delete from table_name
			where where_definition

操作

-- 删除表中名称为吸血鬼的记录
DELETE FROM employee
	WHERE user_name = '吸血鬼';

-- 删除表中所有记录
DELETE FROM employee;

delete语句使用系列

1、没法删除具体某一列的值,最多用update设置为null。
2、delete不能删除表本身,只能用drop删除表本身。

select语句(单表)

基本语句

select [distinct] *| {column1, column2...}
			from table_name;
1、select指定查询哪些列的数据。
2、column指定列名。
3、*号代表查询所有列。
4、from指定查询哪张表。
5、distinct可选,指显示结果时,是否去掉重复数据。

在select语句中可使用as语句

select column_name as 别名 from 表名;

-- 统计每个学生的总分
SELECT `name`,(chinese+english+math) FROM student;

-- 给所有学生的总分加10分
SELECT `name`,(chinese+english+math+10) FROM student;

-- 使用别名表示学生分数
SELECT `name` AS '名字',(chinese+english+math+10) AS total_score FROM student;

在where语句中经常使用的运算符

在这里插入图片描述

-- 查询数学大于60并且英语大于90的学生姓名和成绩
SELECT `name`,english,math FROM student
	WHERE math > 60 AND english > 90;

-- 查询英语成绩大于语文成绩的同学
SELECT `name`,chinese,english FROM student
	WHERE	chinese < english;

-- 查询总分大于200分并且数学成绩小于语文成绩的姓张的学生
SELECT `name`,chinese,math,(chinese+english+math) AS total_score FROM student
	WHERE (chinese+english+math) > 200 AND chinese > math AND `name` LIKE '张%';

在select语句中用order by 子句排序查询结果

select [distinct] *| {column1, column2...}
			from table_name
			order by column asc|desc, ...
1、order by 指定排序的列,排序的列既可以是表中的列名,也可以是select语句后面指定的别名。
2、asc升序(默认),desc降序
3、order by 子句应位于select语句的结尾

操作

-- 对数学成绩排序后输出(升序)
SELECT `name`,math FROM student
	ORDER BY math;

-- 对总分从高到低的顺序输出(降序)
SELECT `name`,(chinese+english+math) AS total_score FROM student
	ORDER BY total_score DESC;

在select语句中用group by 子句对列进行分组

基本语句

select column1,column2... from table_name
			group by column

操作

-- 显示每个部门的平均工资和最低工资
SELECT AVG(salary),MIN(salary),deptno FROM emp
	GROUP BY deptno
	ORDER BY deptno;
	
-- 显示每个部门的各种岗位的平均工资和最低工资
SELECT AVG(salary),MIN(salary),deptno,job FROM emp
	GROUP BY deptno,job
	ORDER BY deptno;

在select语句中用having子句对分组后的结果进行过滤

一般与group by 搭配使用
操作

-- 显示平均工资低于2000的部门号和他的平均工资
SELECT deptno,AVG(salary) AS ms FROM emp
	GROUP BY deptno
	HAVING ms < 2000;

统计函数-count

基本语句

select count(*) |count(列名) from table_name
   		where where_definition

操作

-- 统计一个班共有多少名学生
SELECT COUNT(*) FROM student

-- 统计数学成绩大于60的学生有多少个
SELECT COUNT(*) FROM student
	WHERE math > 60
	
-- 统计总分大于250的人数
SELECT COUNT(*) FROM student
	WHERE (chinese+english+math) > 250

-- count(*)和count(列)的区别
count(*)返还满足条件的记录的行数
count(列)是统计满足条件的某列有多少个,但是会排除null
SELECT COUNT(`name`) FROM student
	WHERE math > 60

合计函数-sum、-avg、-max/min

sum函数返回满足where条件的行的和,一般使用在数值列
基本语法

select sum(列名) from table_name
	where where_definition

操作

-- 统计一个班数学总成绩
SELECT SUM(math) FROM student;

-- 统计一个班语文,数学,英语各科的总成绩
SELECT SUM(math),SUM(chinese),SUM(english) FROM student;

-- 统计一个班语文,数学,英语的成绩综合
SELECT SUM(math+chinese+english) AS total_score FROM student;

-- 统计一个班语文平均分
SELECT AVG(math) FROM student;

-- 统计一个班数学最高分
SELECT MAX(math) FROM student;

字符串相关函数

在这里插入图片描述操作

-- charset(str) 返回字串字符集
SELECT CHARSET(ename) FROM emp

-- concat(string2[,...]) 连接字符串
SELECT CONCAT(ename ,' job is ', job) FROM emp

-- instr(string,substring) 返回substring在string中出现的位置,如果没有就返回0
SELECT INSTR('zmx' , 'x') FROM DUAL  # dual 是系统的亚元表,没有表可用时用来做测试表

-- ucase(string2) 转换成大写
SELECT UCASE(ename) FROM emp

-- lcase(string2) 转换成小写
SELECT LCASE(ename) FROM emp 

-- left(string2,length) 从string2中的左边起取length个字符
SELECT LEFT(ename,2) FROM emp
SELECT RIGHT(ename,2) FROM emp

-- length(string) 返回string长度【按照字节】
SELECT LENGTH(ename) FROM emp

-- replace(str,search_str,replace_str) 在str中用replace_str替换search_str
SELECT REPLACE(job,'经理','manager') FROM emp

-- strcmp(string1,string2) 逐字符比较俩字符串大小
SELECT STRCMP('zmx','zmx1') FROM DUAL

-- substring(str,position[,length]) 从str的position开始[从1开始计算],取length个字符
SELECT SUBSTRING(ename,1,2) FROM emp

-- ltrim(string2) 去除前端空格 rtrim(string2) 去除后端空格 trim 去除两端空格
SELECT LTRIM(' zmx ') FROM DUAL
SELECT RTRIM(' zmx ') FROM DUAL
SELECT TRIM(' zmx ') FROM DUAL

-- 以首字母大写的方式显示所有员工的姓名
SELECT REPLACE(ename,SUBSTRING(ename,1,1),UCASE(SUBSTRING(ename,1,1))) AS new_name FROM FROM emp
SELECT REPLACE(ename, LEFT(ename,1),UCASE(LEFT(ename,1))) AS new_name FROM FROM emp
SELECT CONCAT(UCASE(SUBSTRING(ename,1,1)),SUBSTRING(ename,2)) AS new_name FROM emp

数学相关函数

在这里插入图片描述
操作

-- abs(num) 绝对值
SELECT ABS(-10) FROM DUAL

-- bin(decimal_number) 十进制转二进制
SELECT BIN(10) FROM DUAL

-- ceiling(number2) 向上取整
SELECT CEILING(10.1) FROM DUAL

-- conv(number2,from_base,to_base) 进制转换
SELECT CONV(8,10,2) #8是十进制,转成二进制

-- floor(number2) 向下取整
SELECT FLOOR(10.1) FROM DUAL

-- format(number,decimal_plaaces) 保留小数位
SELECT FORMAT(10.234142,2) FROM DUAL

-- hex(DecimalNumber)  转十六进制
SELECT HEX(100) FROM DUAL

-- least(number,number2....) 求最小值
SELECT LEAST(1,3) FROM DUAL

-- mod(numerator,denomniator) 求余
SELECT MOD(5,3) FROM DUAL

-- rand([seed]) 其范围为0<= v <=1.0,返回一个随机数
SELECT RAND() FROM DUAL
SELECT RAND(1) FROM DUAL # 固定rand(1)的值

时间日期相关函数

在这里插入图片描述
操作

-- current_date() 当前日期
SELECT CURRENT_DATE FROM DUAL

-- current_time 当前时间
SELECT CURRENT_TIME FROM DUAL

-- current_timestamp 当前时间戳
SELECT CURRENT_TIMESTAMP FROM DUAL

CREATE TABLE mes(
id INT,
content VARCHAR(30),
sendtime DATETIME
);

INSERT INTO mes VALUES(1,'北京新闻',CURRENT_TIMESTAMP)
INSERT INTO mes VALUES(2,'上海新闻',NOW())
INSERT INTO mes VALUES(3,'江苏新闻',NOW())

SELECT * FROM mes

-- 显示所有留言信息,发布日期只显示日期不显示时间
SELECT id,content,DATE(sendtime) FROM mes;

-- 查询在十分钟内发布的新闻
SELECT * FROM mes
	WHERE DATE_ADD(sendtime,INTERVAL 10 MINUTE) >= NOW()
	
-- 求出2011-11-11 和1990-1-1相差多少天
SELECT DATEDIFF('2011-11-11','1990-1-1') FROM DUAL

-- 求出你活了多少天
SELECT DATEDIFF(NOW(),'2002-02-03') FROM DUAL

-- 如果你能活到80岁,求你还能活多少天
SELECT DATEDIFF(DATE_ADD('2002-02-03',INTERVAL 80 YEAR),NOW()) FROM DUAL

-- date(datetime) 返回datetime的日期部分

-- date_add(date2,interval d_value d_type) 在date2中加上日期或时间

-- date_sub(date2,interval d_value d_type) 带date2中减去一个时间

-- datediff(date1.date2) 两个日期差(结果是天)

-- timediff(date1,date2) 两个时间差(结果是小时,分,秒)

-- now() 当前时间

-- year|month|date(datetime)  年月日
SELECT YEAR(NOW()) FROM DUAL
SELECT MONTH(NOW()) FROM DUAL
SELECT DAY(NOW()) FROM DUAL

-- unix_timestamp() 返还从开始到现在的秒数
SELECT UNIX_TIMESTAMP() FROM DUAL

-- from_unixtime() 把一个unix_timestamp()秒数转成指定格式的日期
SELECT FROM_UNIXTIME(1618483484,'%Y-%m-%d %H:%i:%s') FROM DUAL
#在开发中可以存放一个整数来存放时间。

加密和系统函数

在这里插入图片描述
操作

-- user() 查询用户
SELECT USER() FROM DUAL  #可以查看登录mysql的用户以及IP

-- database() 数据库名称
SELECT DATABASE() FROM DUAL

-- md5(str) 为字符串算出一个MD5 32的字符串,(用户密码)加密
SELECT MD5('123456') FROM DUAL 
SELECT LENGTH(MD5('123456')) FROM DUAL # md5是32位

-- password(str) 也是加密函数,mysql默认的加密函数
SELECT PASSWORD('123456') FROM DUAL;

-- select * from mysql.user \G 从原文密码str计算并返回密码字符串,通常用于对mysql
SELECT * FROM mysql.user

-- 创建用户表,并新建一个用户
CREATE TABLE users(
id INT,
`name` VARCHAR(32) NOT NULL DEFAULT '',
pwd CHAR(32) NOT NULL DEFAULT ''
);

INSERT INTO users VALUES(100,'zmx',MD5('zmx'))

SELECT * FROM users
	WHERE `name` = 'zmx' AND pwd = 'zmx' #查不到
SELECT * FROM users
	WHERE `name` = 'zmx' AND pwd = MD5('zmx')	

流程控制函数

在这里插入图片描述
操作

-- if(e1,e2,e3) 如果e1为True,则返回e2,否则返回e3
SELECT IF(TRUE,'北京','上海') FROM DUAL;
SELECT IF(FALSE,'北京','上海') FROM DUAL;

-- ifnull(e1,e2) 如果e1不为null,则返回e1,否则返回e2
SELECT IFNULL(NULL,'北京') FROM DUAL;
SELECT IFNULL('北京','上海') FROM DUAL;

-- select case when e1 then e2 when e3 then e4 else e5 end 如果e1为Ture,则返还e2,如果e3为True,则返还e4,否则返还e5
SELECT CASE
	WHEN TRUE THEN 'jack'
	WHEN FALSE THEN 'ben'
	ELSE 'pig'
	END

-- 查询emp表,如果comm是null,则显示0.0
SELECT ename,IF(comm IS NULL , 0.0 , comm) AS com FROM emp
SELECT ename,IFNULL(comm , 0.0) AS com FROM emp

-- 如果emp表的job是CLERK则显示职员,manager显示经理,salesman显示销售,其他则正常显示
SELECT ename , (SELECT CASE
		WHEN job = 'clerk' THEN '职员'
		WHEN job = 'manager' THEN '经理'
		WHEN job = 'salesman' THEN '销售'
		ELSE job
		END) AS 'job'
	FROM emp

select查询-加强

where、like

-- 使用where子句查找1992.1.1后入职的员工
SELECT * FROM emp
	WHERE hiredate > '1991-1-1';
	
-- 使用like(模糊)
-- 		%:表示0到多个容易字符
--		_: 表示单个任意字符
-- 显示首字符为s的员工姓名和工资
SELECT ename,salary FROM emp
	WHERE ename LIKE 's%';

-- 显示名字第三个字母为o的员工的姓名和工资
SELECT ename,salary FROM emp
	WHERE ename LIKE '__o%';

-- 显示没有上级的员工的信息
SELECT * FROM emp
	WHERE mgr IS NULL;
	
-- 查询表的结构
DESC emp

order by

-- 使用order by 子句
-- 按照工资的高低(升序)来显示雇员的信息
SELECT * FROM emp
	ORDER BY salary ASC;
	
-- 按照部门号升序,而工资降序的方式来显示雇员的信息
SELECT * FROM emp
	ORDER BY deptno ASC , salary DESC;

分页查询

基本语法

select ... limit start, rows
表示从start + 1行开始取,取出rows行 ,start 从0开始计算

操作

-- 按雇员的id号升序取出,每页显示3条记录,分别显示前两页。
SELECT * FROM emp
	ORDER BY empno ASC
	LIMIT 0 , 3;#第一页
SELECT * FROM emp
	ORDER BY empno ASC
	LIMIT 1 , 3;#第二页
	-- limit公式  limit 每页显示的记录数*(第几页-1) , 每页显示记录数

group by

-- 显示每种岗位的雇员总数、平均工资
SELECT job,COUNT(*),AVG(salary) FROM emp
	GROUP BY job;

-- 显示雇员总数,以及获得补助的雇员数
SELECT COUNT(*),COUNT(comm) FROM emp   # count不会统计空值
-- 没有获得补助的员工数
SELECT COUNT(*),COUNT(IF(comm IS NULL , 1 ,NULL)) FROM emp 

-- 显示管理者的总人数
SELECT COUNT(mgr) FROM emp # 有重复
SELECT COUNT(DISTINCT mgr) FROM emp

-- 显示雇员工资的最大差额
SELECT (MAX(salary)-MIN(salary)) AS sal_diff FROM emp

顺序

在这里插入图片描述
操作

-- 统计每个部门的平均工资,并且是大于1000的,并且按照平均工资从高到低排序,取出前两行数据
SELECT deptno , AVG(salary) AS avgsal FROM emp
	GROUP BY deptno
	HAVING avgsal > 1000
	ORDER BY avgsal DESC
	LIMIT 0 , 2;

多表查询

以emp、dept、salgrade三表为例

-- 显示雇员名,雇员工资以及所在部门的名字[笛卡尔集]
SELECT * FROM emp , dept #emp表的每一行都与dept表的每行相乘,列相加,行相乘,默认处理方式成为笛卡尔集
SELECT ename , salary , dname , emp.deptno FROM emp , dept
	WHERE emp.deptno = dept.deptno
-- tips:多表查询的条件不能少于表的个数-1,否则会出现笛卡尔集

-- 显示部门号为10的部门名、员工名和工资
SELECT ename , emp.deptno , salary FROM emp , dept
	WHERE emp.`deptno` = dept.`deptno`  AND emp.`deptno` = 10

-- 显示各个员工的姓名,工资,以及其工资的级别
SELECT ename , salary , salgrade.`grade` FROM emp , salgrade
	WHERE emp.`salary` BETWEEN salgrade.`losal` AND salgrade.`hisal`

自连接

自连接是指将同一张表的连接查询看作两张表来使用。
操作

-- 显示公司员工和他的上级的名字
SELECT worker.ename , boss.ename FROM emp AS worker , emp AS boss
	WHERE worker.`mgr` = boss.`empno`

自连接特点:
1、把同一张表当作两张表来使用
2、需要给表取别名
3、列名不明确,要指定列的别名

子查询

引例

-- 显示与smith同一个部门的所有员工
-- select deptno from emp
--	where ename = 'smith'  第一步

SELECT * FROM emp
	WHERE deptno = (
	SELECT deptno FROM emp
		WHERE ename = 'smith' 
	);


-- 多行子查询
-- 查询和10号部门的工作相同的员工的名字、岗位、工资、部门号,但是不含10号部门自己的
SELECT ename , job , salary , deptno FROM emp
	WHERE job IN (
		SELECT DISTINCT job FROM emp
			WHERE deptno = 10
	)
	AND deptno != 10

子查询当做临时表使用

-- 得到各个类别中价格最高的商品
SELECT cat_id , MAX(shop_price) FROM scshop 
	GROUP BY cat_id;

SELECT temp.cat_id , goods_id , goods_name , shop_price FROM(
	SELECT cat_id , MAX(shop_price) AS max_price FROM scshop 
		GROUP BY cat_id;
	) AS temp , ecs_goods
	WHERE temp.cat_id = ecs_goods.cat_id
	AND tep.max_price = ecs_goods.shop_price

all操作符

全部

-- 显示工资比部门30的所有员工高的员工的姓名、工资和部门号
SELECT ename , salary , deptno FROM emp
	WHERE salary > ALL(
		SELECT salary FROM emp
			WHERE deptno = 30
		);

any操作符

其中一个 = min()

-- 显示工资比部门30的其中一个员工高的员工的姓名、工资和部门号
SELECT ename , salary , deptno FROM emp
	WHERE salary > ANY(
		SELECT salary FROM emp
			WHERE deptno = 30
		);
也可以写成
SELECT ename , salary , deptno FROM emp
	WHERE salary > (
		SELECT MIN(salary) FROM emp
			WHERE deptno = 30
		);

多列子查询

-- 查询与smith的部门和岗位完全相同的所有雇员
#第一步,查询allen的部门和岗位
SELECT depno , job FROM emp
	WHERE ename = 'allen'
#第二布,把上面的查询当作子查询来使用,并且使用多列子查询的语法进行匹配
SELECT * FROM emp
	WHERE (deptno , job) = (
			SELECT deptno , job FROM emp
				WHERE ename = 'allen'
			)
	AND ename != 'allen'

-- 查询与宋江数学、英语、语文成绩完全相同的学生
SELECT math , chinese , english FROM student
	WHERE `name` = '张飞'

SELECT * FROM student
	WHERE (math , chinese , english) = (
		SELECT math , chinese , english FROM student
			WHERE `name` = '张飞'
		)
	AND `name` != '张飞'

子查询练习

-- 查找每个部门工资高于本部门平均工资的人的资料
# 1、得到每个部门的部门号和平均工资
SELECT deptno , AVG(salary) AS avg_sal FROM emp
	GROUP BY deptno;
# 2、把上面的结果当作子查询,和emp进行多表查询	
SELECT * FROM emp , (SELECT deptno , AVG(salary) AS avg_sal FROM emp
				GROUP BY deptno
	) AS temp
	WHERE emp.`deptno` = temp.deptno
	AND emp.`salary` > temp.avg_sal
	
	
-- 查找每个部门工资最高的人的详细资料
SELECT deptno , MAX(salary) AS max_sal FROM emp
	GROUP BY deptno
	
SELECT * FROM emp , (
	SELECT deptno , MAX(salary) AS max_sal FROM emp
		GROUP BY deptno
	) AS temp 
	WHERE emp.`deptno` = temp.deptno
	AND emp.`salary` = temp.max_sal


-- 查询每个部门的信息(包括:部门名,编号,地址和人员数量)
# 分析: 部门名、地址来自dept表,编号dept、emp,人员数量-临时表
SELECT deptno , COUNT(*) AS num_peop FROM emp
	GROUP BY deptno;
SELECT dname, loc , temp.* 
	FROM dept , (
		SELECT deptno , COUNT(*) AS num_peop 
			FROM emp
			GROUP BY deptno
	) AS temp
	WHERE dept.`deptno` = temp.deptno

表复制、删除表的重复记录

自我复制数据(蠕虫复制)

-- 有时,为了对某个sql语句进行效率测试,我们需要海量数据时,可以使用此法为表创建海量数据
CREATE TABLE my_tab01(
	id INT,
	`name` VARCHAR(32),
	sal DOUBLE,
	job VARCHAR(32),
	deptno INT
	);
DESC my_tab01;
SELECT * FROM my_tab01;

-- 演示如何自我复制
-- 1、先把emp表的记录复制到my_tab01
INSERT INTO my_tab01
	(id,`name`,sal,job,deptno)
	SELECT empno,ename,salary,job,deptno FROM emp;

-- 2、自我复制
INSERT INTO my_tab01
	SELECT * FROM my_tab01;


-- 思考题:如何删除一张表的重复记录
-- 1、先创建一张表 my_tab02
-- 2、让 my_tab02 有重复的记录
CREATE TABLE my_tab02 LIKE emp; # 这个语句, 把emp表的结构(列),复制到my_tab02
DESC my_tab02;
INSERT INTO my_tab02
	SELECT * FROM emp;
SELECT * FROM my_tab02;
-- 3、考虑去重
/*
思路:	1、创建一张临时表temp,该表的结构与my_tab02一样
	2、把temp的记录通过distinct关键字把处理后的记录复制到tenp
	3、清楚掉my_tab02 记录
	4、把temp表记录复制到my_tab02
	5、drop掉临时表temp
*/
CREATE TABLE temp LIKE my_tab02;
INSERT INTO temp
	SELECT DISTINCT * FROM my_tab02;
DELETE FROM my_tab02;
INSERT INTO my_tab02
	SELECT * FROM temp;
DROP TABLE temp;
SELECT * FROM my_tab02;

合并查询union、union all

有时在实际应用中,为了合并多个select语句的结果,可以使用合集操作符号union,union all
union all 不会去重; union会去重

-- 合并查询
SELECT ename , salary , job FROM emp
	WHERE salary > 2500

SELECT ename , salary , job FROM emp
	WHERE job = 'manager'

-- union all 就是将两个查询结果合并,不会去重
SELECT ename , salary , job FROM emp
	WHERE salary > 2500
UNION ALL
SELECT ename , salary , job FROM emp
	WHERE job = 'manager'

-- union 与union all 相同,但是会自动去重
SELECT ename , salary , job FROM emp
	WHERE salary > 2500
UNION
SELECT ename , salary , job FROM emp
	WHERE job = 'manager'

表外连接

引例

-- 用多表查询列出部门名称和这些部门的员工名称和工作,同时要求显示那些没有员工的部门。
SELECT 	dname , ename , job
	FROM emp , dept
	WHERE emp.`deptno` = dept.`deptno`
	ORDER BY dname;
-- 多表查询中,只能显示匹配上的内容,匹配不上的不显示 比如40号部门就不显示出来

这时就需要用到外连接
外连接分为左外连接跟右外连接:
1、左外连接:如果左侧的表完全显示我们就说时左外连接
2、右外连接:如果右侧的表完全显示我们就说时右外连接
在这里插入图片描述
基本语法

左外连接
select ... from tab_01 left join tab_02  
			on 条件
右外连接
select ... from tab_01 right join tab_02  
			on 条件

操作

-- 创建stu
CREATE TABLE stu(
	id INT,
	`name` VARCHAR(32)
	);
INSERT INTO stu VALUES(1,'jack'),(2,'tom'),(3,'kity'),(4,'nono');
SELECT * FROM stu;
-- 创建 exam
CREATE TABLE exam(
	id INT,
	grade INT
	);
INSERT INTO exam VALUES(1,56),(2,76),(11,8);
SELECT * FROM exam;
-- 使用左外连接,显示所有人的成绩,如果没有成绩,也要显示该人的姓名和id,成绩显示为空
SELECT `name`,stu.`id`,grade
	FROM stu LEFT JOIN exam
	ON stu.`id` = exam.`id`;
-- 使用右外连接,显示所有人的成绩,如果没有名字示为空
-- 右边的表和左表没有匹配的记录,也会把右表的记录显示出来
SELECT `name`,stu.`id`,grade
	FROM stu RIGHT JOIN exam
	ON stu.`id` = exam.`id`;
	
-- 练习:用多表查询列出部门名称和这些部门的员工名称和工作,同时要求显示那些没有员工的部门。
-- 左外连接
SELECT dname,ename,job 
	FROM dept LEFT JOIN emp
	ON dept.`deptno` = emp.`deptno`
-- 右外连接
SELECT dname,ename,job 
	FROM emp RIGHT JOIN dept
	ON dept.`deptno` = emp.`deptno`

mysql 约束

约束主要用于确保数据库的数据满足特定的商业规则。
约束主要包括:not null 、unique 、primary key 、foreign key和check五种

primary key

主要用于唯一的标示表行的数据,当定义主键约束后,该列不能重复

CREATE TABLE t17(
	id INT PRIMARY KEY,  -- 表示id列是主键
	`name` VARCHAR(32),
	email VARCHAR(32)
	);

-- 主键列的值是不可以重复的
INSERT INTO t17
	VALUES(1,'jack','jack@souhu.com'),(2,'tom','tom@souhu.com');

INSERT INTO t17 VALUES(1,'zmx','zmx@souhu.com'); -- 报错 id 1 不可重复

SELECT * FROM t17;

细节:
1、主键不能重复且不可以为空
2、一张表最多有一个主键,但可以是复合主键

-- 报错,一张表不能有两个主键
CREATE TABLE t18(
	id INT PRIMARY KEY,
	`name` VARCHAR(32) PRIMARY KEY,
	email VARCHAR(32)
	);
-- 但可以设置复合主键 , 只有同时满足id,name相同才不能生成
CREATE TABLE t18(
	id INT,
	`name` VARCHAR(32),
	email VARCHAR(32),
	PRIMARY KEY (id , `name`)
	);

3、主键的指定方式有两种

第一钟
CREATE TABLE t17(
	id INT PRIMARY KEY,  -- 表示id列是主键
	`name` VARCHAR(32),
	email VARCHAR(32)
	);
第二种
CREATE TABLE t18(
	id INT,
	`name` VARCHAR(32),
	email VARCHAR(32),
	PRIMARY KEY (id)
	);

4、使用desc可以查看主键(表的结构)

unique(唯一)

-- unique 的使用
CREATE TABLE t21(
	id INT UNIQUE,  -- 表示id列是不可重复的
	`name` VARCHAR(32),
	email VARCHAR(32)
	);

INSERT INTO t21
	VALUES(1,'jack','jack@souhu.com'),(2,'tom','tom@souhu.com');

INSERT INTO t21 VALUES(1,'tom','111') -- 报错,不可重复

细节
1、如果没有指定 not null ,则unique字段可以有多个null

INSERT INTO t21 VALUES(NULL,'tom','111'),(NULL,'pig','1112222')

2、一张表可以有多个unique字段

foreign key(外键)

用于定义主表和从表之间的关系:外键约束要定义在从表上,主表必须具有主键约束或是unique约束。当定义外键约束后,要求外键列数据必须在主表的主键列存在或是为null(学生/班级 图示)
在这里插入图片描述
基本语句

foreign key (本表字段名)references 主表名(主键名或unique字段名)

操作

-- 先创建主表class
CREATE TABLE class(
	id INT PRIMARY KEY,
	`name` VARCHAR(30) NOT NULL DEFAULT '',
	address VARCHAR(30)
	);
-- 创建从表cla_stu
CREATE TABLE cla_stu(
	id INT PRIMARY KEY,
	`name` VARCHAR(32) NOT NULL DEFAULT '',
	class_id INT,
	FOREIGN KEY (class_id) REFERENCES class(id) -- 创建外键
	);

INSERT INTO class VALUES(100,'java','北京'),(200,'mysql','上海');
INSERT INTO cla_stu VALUES(1,'tom',100),(2,'jack',200);
INSERT INTO cla_stu VALUES(3,'pig',300); -- 报错,在class中300 号班级不存在

细节
1、外键指向的表的字段,要求是primary key 或者是unique
2、表达类型是inodb,这样的表才支持外键
3、外键字段的类型必须要和主键字段的类型一致(长度可以不一致)
4、外键字段的值,必须在主键字段中出现过,或者为null(前提是主键字段允许为null)
5、一但建立主外键的关系,数据就不能随意删除了。删除时要先删除从表才能删除主表

check

用于强制行数据必须满足的条件,假定在sal列上定义了check约束,并且要求sal的值在1000~2000之间如果不在就会提示出错。

CREATE TABLE t23(
	id INT PRIMARY KEY,
	`name` VARCHAR(32),
	sex VARCHAR(6) CHECK (sex IN('man','woman')),
	sal DOUBLE CHECK (sal BETWEEN 1000 AND 2000)
	);
INSERT INTO t23 VALUES(1,'jack','mid',1); -- 报错

练习

现有一个商店的数据库shop_db,记录客户及其购物情况,由下面三个表组成:商品表goods(商品id goods_id,商品名goods_name,单价unitprice,类别category,供应商probider),客户customer(客户号cus_id,姓名name,住址address,邮箱email,性别sex,身份证card_id),购买purchase(订单号order_id, 客户号cus_id, 商品号goods_id, 购买数量nums)
要求:建表,在定义中要求声明
1、每个表的主外键
2、客户的姓名不能为空值
3、电邮不能够重复
4、客户的性别【男/女】
5、单价unitprice在1.0-9999.99之间

CREATE DATABASE shop_db;
CREATE TABLE goods(
	goods_id INT PRIMARY KEY NOT NULL,
	goods_name VARCHAR(32) NOT NULL,
	unitprice DOUBLE CHECK (unitprice BETWEEN 1.0 AND 9999.99),
	category INT NOT NULL DEFAULT 0,
	provider VARCHAR(32)
	);
CREATE TABLE customer(
	cus_id INT PRIMARY KEY NOT NULL,
	address VARCHAR(32),
	email VARCHAR(32) UNIQUE,
	sex VARCHAR(6) CHECK (sex IN('man','woman')),
	card_id INT
	);
CREATE TABLE purchase(
	order_id INT PRIMARY KEY NOT NULL,
	cus_id INT NOT NULL,
	goods_id INT NOT NULL,
	nums INT NOT NULL DEFAULT 0,
	FOREIGN KEY (cus_id) REFERENCES customer(cus_id),
	FOREIGN KEY (goods_id) REFERENCES goods(goods_id)
	);

自增长

基本语句

字段名 整型 primary key auto_increment

-- 添加自增长的字段方式
insert into xxx(字段1,字段2.,,,) values (null , '值' ...) -- 从1开始自增长
-- 方法 2
insert into xxx(字段2.,,,) values ( '值1','值2' ...)
 --方法3
insert into xxx  values (null , '值1' ...)

操作

INSERT INTO t24
	VALUES(NULL , 'jack@qq.com' , 'jack');

在这里插入图片描述

INSERT INTO t24
	VALUES(NULL , 'tom@qq.com' , 'tom');

在这里插入图片描述
细节:
1、自增长一般与primary key配合使用
2、自增长也可以单独使用,但需要配合一个unique
3、自增长修饰的字段为整数型的(极少情况用在小数上)
4、自增长默认从1开始,也可以通过以下命令修改

alter table table_name auto_increment = x

5、如果添加数据时,给自增长字段(列)指定的值,则以指定的值为准(可以不用自增长,但是之后自增长的值从你指定的值开始。)

INSERT INTO t24
	VALUES(666 , 'tom@qq.com' , 'tom');
INSERT INTO t24
	VALUES(NULL , 'tom@qq.com' , 'tom');

在这里插入图片描述

索引

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值