MySQL基础篇(下,超详细)

这篇博客详细介绍了MySQL的基础知识,包括视图的创建、修改和删除,变量的分类及使用,存储过程的创建、调用、修改和删除,以及函数的创建和调用。此外,还讲解了流程控制语句、数据库范式、表与表之间的关系以及JDBC的基本概念和应用,是学习MySQL的良好参考资料。
摘要由CSDN通过智能技术生成

视图

含义:MySQL从5.0.1版本开始提供视图功能。一种虚拟存在的表,行和列的数据来自定义视图的查询中使用的表,并且是在使用视图时动态生成的,只保存了sql逻辑,不保存查询结果

应用场景

  • 多个地方用到同样的查询结果
  • 该查询结果使用的sql语句较复杂

优点

  • 重用sql语句
  • 简化复杂的sql操作,不必知道它的查询细节
  • 保护数据,提高安全性

创建视图

语法:

语法:
CREATE VIEW 视图名
AS
查询语句;

案例:

USE myemployees;
-- 1.查询姓名中包含a字符的员工名、部门名和工种信息
-- ①创建
CREATE VIEW myv1 AS SELECT last_name,department_name,job_title FROM employees e JOIN departments d ON e.department_id  = d.department_id JOIN jobs j ON j.job_id  = e.job_id;

-- ②使用
SELECT * FROM myv1 WHERE last_name LIKE '%a%';

-- 2.查询各部门的平均工资级别
-- ①创建视图查看每个部门的平均工资
CREATE VIEW myv2 AS SELECT AVG(salary) ag,department_id FROM employees GROUP BY department_id;

-- ②使用
SELECT myv2.`ag`,g.grade_level FROM myv2 JOIN job_grades g ON myv2.`ag` BETWEEN g.`lowest_sal` AND g.`highest_sal`;

-- 3.查询平均工资最低的部门信息
SELECT * FROM myv2 ORDER BY ag LIMIT 1;

-- 4.查询平均工资最低的部门名和工资
CREATE VIEW myv3 AS SELECT * FROM myv2 ORDER BY ag LIMIT 1;

SELECT d.*,m.ag
FROM myv3 m
JOIN departments d
ON m.`department_id`=d.`department_id`;

修改视图

语法:

-- 方式一:如果视图存在则修改,不存在则新建
CREATE OR REPLACE VIEW 视图名
AS
查询语句;

SELECT * FROM myv3 

-- 例:
CREATE OR REPLACE VIEW myv3 AS SELECT AVG(salary),job_id FROM employees GROUP BY job_id;

-- 方式二:
语法:
ALTER VIEW 视图名
AS 
查询语句;

-- 例
ALTER VIEW myv3 AS SELECT * FROM employees;

注意:视图的可更新性和视图中查询的定义有关系,以下类型的视图是不能更新的。一般视图创建后也不会进行修改或更新

  1. 包含以下关键字的sql语句:分组函数、distinct、group by、having、union或者union all
  2. 常量视图
  3. Select中包含子查询
  4. join
  5. from一个不能更新的视图
  6. where子句的子查询引用了from子句中的表

案例:

-- ①包含以下关键字的sql语句:分组函数、distinct、group  by、having、union或者union all
CREATE OR REPLACE VIEW myv1 AS SELECT MAX(salary) m,department_id FROM employees GROUP BY department_id;

SELECT * FROM myv1;

-- 更新
UPDATE myv1 SET m = 9000 WHERE department_id = 10;

-- ②常量视图
CREATE OR REPLACE VIEW myv2 AS SELECT 'john' NAME;

SELECT * FROM myv2;

-- 更新
UPDATE myv2 SET NAME='lucy';

-- ③Select中包含子查询
CREATE OR REPLACE VIEW myv3 AS SELECT department_id,(SELECT MAX(salary) FROM employees) 最高工资
FROM departments;

-- 更新
SELECT * FROM myv3;
UPDATE myv3 SET 最高工资 = 100000;


-- ④join
CREATE OR REPLACE VIEW myv4 AS SELECT last_name,department_name FROM employees e JOIN departments d
ON e.department_id  = d.department_id;

-- 更新
SELECT * FROM myv4;
UPDATE myv4 SET last_name  = '张飞' WHERE last_name='Whalen';
INSERT INTO myv4 VALUES('陈真','xxxx');

-- ⑤from一个不能更新的视图
CREATE OR REPLACE VIEW myv5 AS SELECT * FROM myv3;

-- 更新
SELECT * FROM myv5;

UPDATE myv5 SET 最高工资=10000 WHERE department_id=60;

-- ⑥where子句的子查询引用了from子句中的表
CREATE OR REPLACE VIEW myv6 AS SELECT last_name,email,salary FROM employees WHERE employee_id IN(
	SELECT  manager_id FROM employees WHERE manager_id IS NOT NULL);

-- 更新
SELECT * FROM myv6;
UPDATE myv6 SET salary=10000 WHERE last_name = 'k_ing';

删除视图

语法:

DROP VIEW 视图名1,视图名2,...;

案例:

DROP VIEW emp_v1,emp_v2,myv3;

查看视图

语法:

DESC 视图名;

SHOW CREATE VIEW 视图名;

变量

分类:

  1. 系统变量:

    ​ 全局变量

    ​ 会话变量

  2. 自定义变量:

    ​ 用户变量

    ​ 局部变量

系统变量

说明:变量由系统定义,不是用户定义,属于服务器层面

注意:全局变量需要添加global关键字,会话变量需要添加session关键字,如果不写,默认会话级别

-- 使用步骤:
-- 1、查看所有系统变量
SHOW GLOBAL|【SESSION】VARIABLES;
-- 2、查看满足条件的部分系统变量
SHOW GLOBAL|【SESSION】 VARIABLES LIKE '%char%';
-- 3、查看指定的系统变量的值
SELECT @@global|【SESSION】系统变量名;
-- 4、为某个系统变量赋值
-- 方式一:
SET GLOBAL|【SESSION】系统变量名=值;
-- 方式二:
SET @@global|【SESSION】系统变量名=值;
全局变量

作用域:针对于所有会话(连接)有效,但不能跨重启

-- ①查看所有全局变量
SHOW GLOBAL VARIABLES;

-- ②查看满足条件的部分系统变量
SHOW GLOBAL VARIABLES LIKE '%char%';

-- ③查看指定的系统变量的值
SELECT @@global.autocommit;

-- ④为某个系统变量赋值
SET @@global.autocommit=0;
SET GLOBAL autocommit=0;
会话变量

作用域:针对于当前会话(连接)有效

-- ①查看所有会话变量
SHOW SESSION VARIABLES;

-- ②查看满足条件的部分会话变量
SHOW SESSION VARIABLES LIKE '%char%';

-- ③查看指定的会话变量的值
SELECT @@autocommit;
SELECT @@session.tx_isolation;

-- ④为某个会话变量赋值
SET @@session.tx_isolation='read-uncommitted';
SET SESSION tx_isolation='read-committed';

自定义变量

说明:变量由用户自定义,而不是系统提供的

使用步骤

1、声明

2、赋值

3、使用(查看、比较、运算等)

用户变量

作用域:针对于当前会话(连接)有效,作用域同于会话变量

语法:

-- 赋值操作符:=或:=
-- ①声明并初始化
SET @变量名=值;
SET @变量名:=值;
SELECT @变量名:=值;

-- ②赋值(更新变量的值)
-- 方式一:
	SET @变量名=值;
	SET @变量名:=值;
	SELECT @变量名:=值;
-- 方式二:
	SELECT 字段 INTO @变量名
	FROM 表;
	
-- ③使用(查看变量的值)
SELECT @变量名;
局部变量

作用域:仅仅在定义它的begin end块中有效,应用在 begin end中的第一句话

语法:

-- ①声明
DECLARE 变量名 类型;
DECLARE 变量名 类型 【DEFAULT 值】;

-- ②赋值(更新变量的值)
-- 方式一:
	SET 局部变量名=值;
	SET 局部变量名:=值;
	SELECT 局部变量名:=值;
-- 方式二:
	SELECT 字段 INTO 具备变量名 FROM 表;
	
-- ③使用(查看变量的值)
SELECT 局部变量名;

-- 案例:声明两个变量,求和并打印
-- 用户变量
SET @m=1;
SET @n=1;
SET @sum=@m+@n;
SELECT @sum;

-- 局部变量
DECLARE m INT DEFAULT 1;
DECLARE n INT DEFAULT 1;
DECLARE SUM INT;
SET SUM=m+n;
SELECT SUM;

用户变量和局部变量对比

作用域 定义位置 语法
用户变量 当前会话 会话的任何地方 加@符号,不用指定类型
局部变量 定义它的BEGIN END中 BEGIN END的第一句话 一般不用加@,需要指定类型

存储过程和函数

含义:事先经过编译并存储在数据库中的一段sql语句的集合。可以理解成批处理语句

好处

  1. 简化应用开发人员的很多工作,提前封装好一组批处理逻辑语句
  2. 减少数据在数据库和应用服务器之间的传输,减少了编译次数并且减少了和数据库服务器的连接次数,提高了效率
  3. 提高了代码的重用性

存储过程

创建存储过程

语法:

CREATE PROCEDURE 存储过程名(参数列表)
BEGIN
	存储过程体(一组合法的SQL语句)
END

注意

  1. 参数列表包含三部分,参数模式 参数名 参数类型

    ​ 举例:in stuname varchar(20)

    ​ 参数模式:

    ​ in:该参数可以作为输入,也就是该参数需要调用方传入值

    ​ out:该参数可以作为输出,也就是该参数可以作为返回值

    ​ inout:该参数既可以作为输入又可以作为输出,也就是该参数既需要传入值,又可以返回值

  2. 如果存储过程体仅仅只有一句话,begin end可以省略,存储过程体中的每条sql语句的结尾要求必须加分号。存储过程的结尾可以使用 delimiter 重新设置

语法:
delimiter 结束标记
案例:
delimiter $
调用存储过程

语法:

CALL 存储过程名(实参列表);

案例:

-- 案例演示
-- 1.空参列表
-- 案例:插入到admin表中五条记录
SELECT * FROM admin;

DELIMITER $
CREATE PROCEDURE myp1()
BEGIN
	INSERT INTO admin(username,`password`) 
	VALUES('john1','0000'),('lily','0000'),('rose','0000'),('jack','0000'),('tom','0000');
END $

-- 调用
CALL myp1()$

-- 2.创建带in模式参数的存储过程
-- 案例1:创建存储过程实现 根据女神名,查询对应的男神信息
CREATE PROCEDURE myp2(IN beautyName VARCHAR(20))
BEGIN
	SELECT bo.*
	FROM boys bo
	RIGHT JOIN beauty b ON bo.id = b.boyfriend_id
	WHERE b.name = beautyName;
END $

-- 调用
CALL myp2('柳岩')$

-- 案例2 :创建存储过程实现,用户是否登录成功
CREATE PROCEDURE myp4(IN username VARCHAR(20),IN PASSWORD VARCHAR(20))
BEGIN
	DECLARE result INT DEFAULT 0;-- 声明并初始化
	
	SELECT COUNT(*) INTO result-- 赋值
	FROM admin
	WHERE admin.username = username
	AND admin.password = PASSWORD;
	
	SELECT IF(result>0,'成功','失败');-- 使用
END $

-- 调用
CALL myp3('张飞','8888')$

-- 3.创建out 模式参数的存储过程
-- 案例1:根据输入的女神名,返回对应的男神名
CREATE PROCEDURE myp6(IN beautyName VARCHAR(20),OUT boyName VARCHAR(20))
BEGIN
	SELECT bo.boyname INTO boyname
	FROM boys bo
	RIGHT JOIN
	beauty b ON b.boyfriend_id = bo.id
	WHERE b.name = beautyName ;
END $

-- 案例2:根据输入的女神名,返回对应的男神名和魅力值
CREATE PROCEDURE myp7(IN beautyName VARCHAR(20),OUT boyName VARCHAR(20),OUT usercp INT) 
BEGIN
	SELECT boys.boyname ,boys.usercp INTO boyname,usercp
	FROM boys 
	RIGHT JOIN
	beauty b ON b.boyfriend_id = boys.id
	WHERE b.name = beautyName ;
END $

-- 调用
CALL myp7('小昭',@name,@cp)$
SELECT @name,@cp$

-- 4.创建带inout模式参数的存储过程
-- 案例1:传入a和b两个值,最终a和b都翻倍并返回
CREATE PROCEDURE myp8(INOUT a INT ,INOUT b INT)
BEGIN
	SET a = a * 2;
	SET b = b * 2;
END $

-- 调用
SET @m = 10$
SET @n = 20$
CALL myp8(@m,@n)$
SELECT @m,@n$
删除存储过程

一次只能删除一个存储过程或者函数,并且要求有该过程或函数的alter routine 权限

语法:

DROP PROCEDURE  [IF EXISTS] p1;

案例:

DROP PROCEDURE p2,p3;
查看存储过程的定义信息

语法:

DESC 存储过程名;
SHOW CREATE PROCEDURE  存储过程名;

案例:

DESC myp2;
SHOW CREATE PROCEDURE  myp2;
修改存储过程

语法:

ALTER PROCEDURE 存储过程名 [charactristic…]
查看存储过程或函数的状态

语法:

SHOW {PROCEDURE|FUNCTION} STATUS LIKE 存储过程或函数名
通过查看information_schema.routines了解存储过程和函数的信息(了解)
SELECT * FROM rountines WHERE rounine_name = 存储过程名|函数名

函数

存储过程和函数的区别

存储过程:可以有0个返回,也可以有多个返回,适合做批量插入、批量更新

函数:有且仅有1 个返回,适合做处理数据后返回一个结果

创建函数

注意

  1. 参数列表 包含两部分:参数名 参数类型
  2. 函数体:肯定会有return语句,如果没有会报错,如果return语句没有放在函数体的最后也不报错,但不建议return 值
  3. 函数体中仅有一句话,则可以省略begin end
  4. 使用 delimiter语句设置结束标记

语法:

CREATE FUNCTION 函数名(参数列表) RETURNS 返回类型
BEGIN
	函数体
END
调用函数

语法:

SELECT 函数名(参数列表)

案例:

-- 1.无参有返回
-- 案例:返回公司的员工个数
CREATE FUNCTION myf1() RETURNS INT
BEGIN
	DECLARE c INT DEFAULT 0;-- 定义局部变量
	SELECT COUNT(*) INTO c-- 赋值
	FROM employees;
	RETURN c;
END $

SELECT myf1()$

-- 2.有参有返回
-- 案例1:根据员工名,返回它的工资
CREATE FUNCTION myf2(empName VARCHAR(20)) RETURNS DOUBLE
BEGIN
	SET @sal=0;-- 定义用户变量 
	SELECT salary INTO @sal   -- 赋值
	FROM employees
	WHERE last_name = empName;
	
	RETURN @sal;
END $

SELECT myf2('k_ing') $

-- 案例2:根据部门名,返回该部门的平均工资
CREATE FUNCTION myf3(deptName VARCHAR(20)) RETURNS DOUBLE
BEGIN
	DECLARE sal DOUBLE ;
	SELECT AVG(salary) INTO sal
	FROM employees e
	JOIN departments d ON e.department_id = d.department_id
	WHERE d.department_name=deptName;
	RETURN sal;
END $

SELECT myf3('IT')$

-- 案例2:创建函数,实现传入两个float,返回二者之和

CREATE FUNCTION test_fun1(num1 FLOAT,num2 FLOAT) RETURNS FLOAT
BEGIN
	DECLARE SUM FLOAT DEFAULT 0;
	SET SUM=num1+num2;
	RETURN SUM;
END $

SELECT test_fun1(1,2)$
查看函数

语法:

SHOW CREATE FUNCTION 函数名;

案例:

SHOW CREATE FUNCTION myf3;
删除函数

语法:

DROP FUNCTION 函数名;

案例:

DROP FUNCTION myf3;

流程控制语句

分支结构
if函数
语法:if(条件,值1,值2)
功能:实现双分支
应用在begin end中或外面
case结构
语法:
情况1:类似于switch
case 变量或表达式
when 值1 then 语句1;
when 值2 then 语句2;
...
else 语句n;
end 

情况2:
case 
when 条件1 then 语句1;
when 条件2 then 语句2;
...
else 语句n;
end 

应用在begin end 中或外面
if结构
语法:
if 条件1 then 语句1;
elseif 条件2 then 语句2;
....
else 语句n;
end if;
功能:类似于多重if

只能应用在begin end 中

案例:

-- 案例1:创建函数,实现传入成绩,如果成绩>90,返回A,如果成绩>80,返回B,如果成绩>60,返回C,否则返回D
CREATE FUNCTION test_if(score FLOAT) RETURNS CHAR
BEGIN
	DECLARE ch CHAR DEFAULT 'A';
	IF score > 90 THEN SET ch='A';
	ELSEIF score > 80 THEN SET ch='B';
	ELSEIF score > 60 THEN SET ch='C';
	ELSE SET ch='D';
	END IF;
	RETURN ch;
END $

SELECT test_if(87)$

-- 案例2:创建存储过程,如果工资<2000,则删除,如果5000>工资>2000,则涨工资1000,否则涨工资500
CREATE PROCEDURE test_if_pro(IN sal DOUBLE)
BEGIN
	IF sal < 2000 THEN DELETE FROM employees WHERE employees.salary = sal;
	ELSEIF sal >= 2000 AND sal < 5000 THEN UPDATE employees SET salary=salary + 1000 WHERE employees.`salary` = sal;
	ELSE UPDATE employees SET salary = salary + 500 WHERE employees.`salary` = sal;
	END IF;
END $

CALL test_if_pro(2100)$

-- 案例1:创建函数,实现传入成绩,如果成绩>90,返回A,如果成绩>80,返回B,如果成绩>60,返回C,否则返回D
CREATE FUNCTION test_case(score FLOAT) RETURNS CHAR
BEGIN 
	DECLARE ch CHAR DEFAULT 'A';
	CASE 
	WHEN score > 90 THEN SET ch='A';
	WHEN score > 80 THEN SET ch='B';
	WHEN score > 60 THEN SET ch='C';
	ELSE SET ch = 'D';
	END CASE;
	
	RETURN ch;
END $

SELECT test_case(56)$
循环结构

分类

while、loop、repeat

循环控制

iterate类似于 continue,继续,结束本次循环,继续下一次

leave 类似于 break,跳出,结束当前所在的循环

while

语法:

【标签:】while 循环条件 do
	循环体;
end while【 标签】;

联想:

while(循环条件){
	循环体;
}
loop

语法:

【标签:】loop
	循环体;
end loop 【标签】;

可以用来模拟简单的死循环
repeat
语法:
【标签:】repeat
	循环体;
until 结束循环的条件
end repeat 【标签】;

案例:

-- 1.没有添加循环控制语句
-- 案例:批量插入,根据次数插入到admin表中多条记录
DROP PROCEDURE pro_while1$
CREATE PROCEDURE pro_while1(IN insertCount INT)
BEGIN
	DECLARE i INT DEFAULT 1;
	WHILE i <= insertCount DO
		INSERT INTO admin(username,`password`) VALUES(CONCAT('Rose',i),'666');
		SET i=i+1;
	END WHILE;
END $

CALL pro_while1(100)$

/*
int i=1;
while(i<=insertcount){
	//插入	
	i++;
}
*/


-- 2.添加leave语句
-- 案例:批量插入,根据次数插入到admin表中多条记录,如果次数>20则停止
TRUNCATE TABLE admin$
DROP PROCEDURE test_while1$
CREATE PROCEDURE test_while1(IN insertCount INT)
BEGIN
	DECLARE i INT DEFAULT 1;
	a:WHILE i <= insertCount DO
		INSERT INTO admin(username,`password`) VALUES(CONCAT('xiaohua',i),'0000');
		IF i >= 20 THEN LEAVE a;
		END IF;
		SET i=i+1;
	END WHILE a;
END $

CALL test_while1(100)$

-- 3.添加iterate语句
-- 案例:批量插入,根据次数插入到admin表中多条记录,只插入偶数次
TRUNCATE TABLE admin$
DROP PROCEDURE test_while1$
CREATE PROCEDURE test_while1(IN insertCount INT)
BEGIN
	DECLARE i INT DEFAULT 0;
	a:WHILE i <= insertCount DO
		SET i = i + 1;
		IF MOD(i,2) != 0 THEN ITERATE a;
		END IF;
		
		INSERT INTO admin(username,`password`) VALUES(CONCAT('xiaohua',i),'0000');
	END WHILE a;
END $

CALL test_while1(100)$

数据库范式

什么是范式


一种规则,指导程序员创建表的规则

程序员在设计表的时候,只需要符合三大范式就可以了

有哪些范式


满足最低要求的范式是第一范式(1NF),在第一范式的基础上进一步满足更多规范要求的称为第二范式(2NF),其余范式以次类推。一般说来,数据库只需满足第三范式(3NF)就行了

满足这些规范的数据库是简洁的、结构明晰的,同时,不会发生插入(insert)、删除(delete)和更新(update)操作异常。

第一范式

特点

原子性:表中每一列都不可以再分割成更小的列。如果一列中包含的数据可以再拆分,不符合第一范式

案例


班级表

学号 姓名 班级
1000 张三 一年级3班
1001 李四 一年级2班
2001 王五 二年级1班

解决方案

学号 姓名 年级 班号
1000 张三 一年级 3
10001 李四 一年级 2
2001 王五 二年级 1

第二范式

概念


在满足第一范式的基础上,有更多的要求,才是第二范式。表中每一列都必须完全依赖于主键,而不是局部依赖。

如果主键是复合主键,即有多列做为主键时,表中部分列只依赖主键的一部分,则不符合第二范式。

第二范式的特点

  1. 不产生局部依赖
  2. 每张表只描述一件事情

案例


学生课程表中的主键是联合主键:学生id + 课程id

学生id 学生姓名 课程id 课程名字 课程周期 考试成绩
stu001 张三 course01 语文 16周 90
stu001 张三 course02 数学 14周 61
stu002 李四 course01 语文 16周 88
stu003 王五 course03 英语 18周 59

解决方案

学生id 学生姓名 课程id 考试成绩
stu001 张三 course01 90
stu001 张三 course02 61
stu002 李四 course01 88
stu003 王五 course03 59
课程id 课程名字 课程周期
course01 语文 16周
course02 数学 14周
course03 英语 18周

第三范式

概念


在满足第二范式的基础上,有更多的要求。 表中每列都直接依赖于主键,而不是通过其它列间接依赖于主键。

依赖关系


所谓传递依赖,指的是如果存在"A → B → C"的决定关系,则C传递依赖于A

满足第三范式的数据库表应该不存在如下依赖关系:主键列 → 非主键列X → 非主键列Y

案例


学生信息表

学号 姓名 年龄 所在学院 学院id 学院地点
1000 张三 20 江苏专修学院 1 江苏
2000 李四 19 广州美术学院 2 广州
1001 王五 21 江苏专修学院 1 江苏
2001 赵六 20 广州美术学院 2 广州
2002 小七 18 广州美术学院 2 广州

存在的传递关系:学号 --> 所在学院 --> 学院地点

大数据量时,会造成数据冗余

解决方案


从表:有外键 (多方)

学号 姓名 年龄 所在学院ID
1000 张三 20 1
2000 李四 19 2
1001 王五 21 1
2001 赵六 20 2
2002 小七 18 2

主表:有主键(1方)

学院ID 学院名字 学院地点
1 江苏专修学院 江苏
2 广州美术学院 广州

注意

  1. 表使用的范式越高级,被拆分的表就越多
  2. 如果性能与范式有冲突,优先考虑性能

表与表之间的关系(建表原则)

一对一

从表的外键指向主表的主键,外键需唯一约束

例如:A表和B表:A表中一条记录对应B表中一条记录,如:身份证 - 护照

建表原则:

一对一(1:1) 在实际的开发中应用不多,因为一对一可以创建成一张表


一对一的建表原则 说明
外键
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值