MySQL进阶学习

导读:本篇文章讲解 MySQL进阶学习,希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com


前言

本文内容主要是对MySQL基础学习的提升。对于刚学习MySQL的小伙伴可以先学习MySQL基础,然后再来看这篇文章。点击学习MySQL基础

一、数据完整性

作用:保证用户输入的数据保存到数据库中是正确的。确保数据的完整性就是在创建表时给表中添加约束。

完整性分类:实体完整性域完整性引用完整性

1.实体完整性

实体定义:即表中的一行(一条记录)代表一个实体(entity)。

实体完整性的作用:标识每一行数据都不重复

1.1.1 约束类型

  • 主键约束(primary key)
  • 唯一约束(unique)
  • 自动增长列(auto_increment)

1.1.1.1 主键约束

每个表中要有一个主键。特点:数据唯一,且不能为null

    -- 例:第一种添加方式: 
    CREATE TABLE student( 
        id int primary key, 
        name varchar(50) 
    );
    
    -- 第二种添加方式:此种方式优势在于,可以创建联合主键 
    CREATE TABLE student( 
        id int, name varchar(50), 
        primary key(id) 
    );
    
    CREATE TABLE student( 
        classid int, 
        stuid int, 
        name varchar(50), 
        primary key(classid,stuid) );
    
    -- 第三种添加方式:单独添加主键 
    CREATE TABLE student( 
        id int, 
        name varchar(50) 
    );
    
    ALTER TABLE student ADD PRIMARY KEY (id);

1.1.1.2 唯一约束

数据不能重复。但是null不算重复

    CREATE TABLE student( 
    Id int primary key, 
    Name varchar(50) unique 
    );

1.1.1.3 自动增长列

默认从最大值开始+1
作用:给主键添加自动增长的数值 列只能是整数类型

    CREATE TABLE student( 
    Id int primary key auto_increment, 
    Name varchar(50) 
    );
    INSERT INTO student(name) values('tom');

2.域完整性

作用:限制此单元格的数据正确,不与此列的其他单元格比较,域代表当前单元格

2.1 域完整性约束分类:

  • 非空约束(not null)
  • 默认值约束(default)
  • check约束(mysql不支持)

数据类型:数值类型、日期类型、字符串类型

2.2 非空约束

关键字: not null

    CREATE TABLE student( 
    Id int primary key, 
    Name varchar(50) not null, 
    Sex varchar(10) );
    
    INSERT INTO student values(1,'tom',null);

2.3 默认值约束

关键字:defult

    CREATE TABLE student( 
    	Id int primary key, 
    	Name varchar(50) not null, 
    	Sex varchar(10) default '男' );
    	
    insert into student values(1,'tom','女'); 
    insert into student values(2,'jerry',default);

3.引用完整性(参照完整性)

外键约束(foreign key

    例:CREATE TABLE stu( 
    	sid int primary key, 
    	name varchar(50) not null, 
    	sex varchar(10) default '男' 
    );
    
    create table score( 
    	id int primary key, 
    	score int, sid int , -- 外键列的数据类型一定要与主键的类型一致 
    	foreign key (sid) references stu(sid) 
    );
   
    -- 撤销外键 先选中外键所在的表,在右下角找到info选项,拉到最后,找到创建score表的信息,我们可以发现主外键关联的标识 score_ibfk_1 
    ALTER TABLE score DROP FOREIGN KEY score_ibfk_1 
    
    -- 第二种添加外键方式。 
    ALTER TABLE score ADD CONSTRAINT fk_stu_score FOREIGN KEY(sid) REFERENCES stu(sid);

二、多表查询

1.多表分类查询

合并结果集:UNIONUNION ALL

连接查询内连接:[INNER] JOIN ON

外连接:OUTER JOIN ON

左外连接:LEFT [OUTER] JOIN

右外连接:RIGHT [OUTER] JOIN

圈外连接(MySQL不支持):FULL JOIN

自然连接:NATURAL JOIN

2.合并结果集

作用:合并结果集就是把俩个select语句的查询结果合并到一起

要求:被合并的俩个结果列数、类型必须一致

3.连接查询

3.1内连接

    -- 连接student和scores俩个表
    -- 被连接的俩个表需要有至少一个相同的字段,否则无法进行内连接
    SELECT * FROM 
    	student stu 
    	INNER JOIN scores sco 
    	ON stu.id=sco.id;

3.2 外连接

外连接:查询出的结果存在不满足条件的可能

3.2.1 左外连接

使用LEFT OUTER JOIN … ON

写法:SELECT FROM 表一 LEFT OUTER(可省略) JOIN 表二 ON 表一.id = 表二.id

特点:以左表为主,左表的信息会全部查出来。右边只能查出与左表中id相同的记录。其他的不显示,左表有数据的,右表没有对应数据的显示NULL

    -- 左外连接
    -- 先查询出坐标,然后再查询右表。右表满足条件的记录就显示出来,不满足条件的显示为NULL
    SELECT * FROM emp e 
    LEFT OUTER JOIN dept d 
    ON e.deptno=d.deptno;

3.2.2 右外连接

使用RIGHT OUTER JOIN … ON

写法:SELECT FROM 表一 RIGHTOUTER(可省略) JOIN 表二 ON 表一.id = 表二.id

特点:以右表为主,右表的信息会全部查出来。左边只能查出与右表中id相同的记录。其他的不显示,右表有数据的,左表没有对应数据的显示NULL

    -- 右外连接
    SELECT * FROM student stu 
    RIGHT OUTER JOIN scores sco 
    ON stu.id=sco.id

3.2.3 总结

连接可以是多张表,连接查询也可以是多张表。这种情况需要使用条件去除不需要的记录。大部分情况下使用的是主外键关系进去去除。如果俩张表进行连接查询的话,那么至少需要一个主外键条件;三张表进行连接查询话,至少需要俩个主外键条件

3.2.4 自然连接

自然连接无需显式给出主外键关系,系统自动找到这一关系。

    -- 注意:1.要有主外键,而且主外键的的名字要相同.如果没有主外键,他默认会找字段相同的所有字段进行比较,如果 没有字段相同的字段报错 
    -- 2.自然连接时,会将相同的字段合并
    -- 3.如果只写natural 默认当作内连接 
    SELECT * FROM student stu NATURAL JOIN scores sco SELECT * FROM student stu NATURAL LEFT JOIN scores sco 
    SELECT * FROM student stu NATURAL RIGHT JOIN scores sco

4.子查询

定义:一个select语句包含另外一个完整的select语句子。查询就是嵌套查询。

子查询出现的位置:

  • where后:作为查询条件的一部分。
  • from后:作为一张

注意:当子查询出现在where后作为条件时,可以使用any all 关键字

    -- 子查询示例
    SELECT * FROM emp 
    WHERE sal > (SELECT sal FROM emp WHERE ename='JONES')

4.1 自连接

本表连接本表,需要给表起别名

    -- 自连接示例
    SELECT e1.empno , e1.ename,e1.mgr,e2.ename FROM emp e1, emp e2 
    WHERE e1.mgr = e2.empno AND e1.empno = 7369;

4.2合并结果集

合并结果集就是将两次或者多次的查询结果,合并到一起,存入一张查询结果虚拟表中。进行结果集合并的多张表,要求字段的数量是完全相同的。

语法:

union:对两次的查询结果进行合并,对最终的合并结果会进行去重处理

union all:对两次的查询结果进行合并,不会进行去重处理

三、MySQL中的函数

1.功能性函数

1.1 IFNULL

函数形式:IFNULL(field,value)

逻辑:如果第一个参数field是NULL,则返回第二个参数value的值,否则返回field本身的值。

     -- 查询结果是11
    select ifnull(null, 11);
    -- 查询结果是12
    select ifnull(12, 20); 
    -- 如果id字段的值是NULL,就返回0,否则就返回id字段的值
    select ifnull(`id`, 0); 

1.2 IF

类似Java中三目运算符

形式:IF(condition,value1,value2)

逻辑:如果第一个参数condition条件成立,返回value1的值,否则返回value2的值

    -- 10>20不成立,返回20
    select if(10>20,10,20)-- 10<20成立,返回10
    select if(10<20,10,20)-- 如果math字段的值大于english的值,返回math;否则返回english的值
    select if(math>english,math,english)

1.3 CASE

实现分支结构。

case…when有俩种写法

写法1:

    -- 需求: 已知sc表中有⼀个字段名为`score`表示⼀个学⽣的成绩。通过这个成绩字段的不同范围,查询出不同
    的结果:
    -- < 0 或者 > 100, 等级为"错误成绩"
    -- [0, 60), 等级为"不及格"
    -- [60, 80), 等级为"良"
    -- [80, 100], 等级为"优"
    select `sid`, `score`,
     case
     when `score` < 0 or `score` > 100 then '错误成绩'
     when `score` < 60 then '不及格'
     when `score` < 80 then '良'
     else '优'
     end as 'level'
    from `sc`;

写法2:

    -- 需求: 已知sc表中有⼀个字段名为`subject`表示成绩的科⽬。通过这个字段的不同的值,查询出不同的描述
    信息:
    -- 如果是chinese,查询出"语⽂"
    -- 如果是math,查询出"数学"
    -- 如果是english,查询出"英语"
    -- 其他的保持原样
    select `subject`,
     case `subject`
     when 'chinese' then '语⽂'
     when 'math' then '数学'
     when 'english' then '英语'
     else `subject`
     end as '翻译'
    from `sc`

1.4 行转列

将行信息转为列信息

    -- if实现版本
    select `sname` as '姓名',
     sum(if(`subject` = '语⽂', `score`, 0)) as '语⽂',
     sum(if(`subject` = '数学', `score`, 0)) as '数学',
     sum(if(`subject` = '英语', `score`, 0)) as '英语',
     sum(if(`subject` = '历史', `score`, 0)) as '历史',
     sum(if(`subject` = '政治', `score`, 0)) as '政治',
     sum(if(`subject` = '体育', `score`, 0)) as '体育'
    from `sc` group by `sname`;
    -- case实现版本
    select `sname` as '姓名',
     sum(case `subject` when '语⽂' then `score` else 0 end) as '语⽂',
     sum(case `subject` when '数学' then `score` else 0 end) as '数学',
     sum(case `subject` when '英语' then `score` else 0 end) as '英语',
     sum(case `subject` when '历史' then `score` else 0 end) as '历史',
     sum(case `subject` when '政治' then `score` else 0 end) as '政治',
     sum(case `subject` when '体育' then `score` else 0 end) as '体育'
    from `sc` group by `sname`;

1.5 exists

exists:判断一个表中的数据是否在另外一张表中查询到与之对应的数据。效率比连接查询和子查询要高。

    -- 案例: 查询有员⼯的部⻔
    select distinct dept.* from dept left join emp on dept.deptno = emp.deptno where empno is
    not null;
    select * from dept where exists(
     select 1 from emp where dept.deptno = emp.deptno
    );

2.常用系统函数

2.1 日期函数

函数名 作用
ADDTIME(date2,time_interval) 将time_interval加到date2
CURRENT_DATE() 当前日期
CURRENT_TIME() 当前时间
CURRENT_TIMESTAMP() 当前时间戳
DATE(datetime) 返回datetime的日期部分
DATE_ADD(date2,INTERVAL d_value d_type) 在date2中加上日期或时间
DATE_SUB(date2,INTERVAL d_value d_type) 在date2上减去一个时间
DATEDIFF(date1,date2) 俩个日期差
NOW() 当前时间
YEAR|MONTH|DAY(datetime) 年月日

2.2 字符串函数

函数名 作用
CHARSET(str) 返回字串字符集
CONCAT (string2 [… ]) 连接字串
INSTR (string ,substring ) 返回substring在string中出现的位置,没有返0
UCASE (string2 ) 转换成大写
LCASE (string2 ) 转换成小写
LEFT (string2 ,length ) 从string2中的左边起取length个字符
LENGTH (string ) string长度
REPLACE (str ,search_str ,replace_str ) 在str中用replace_str替换search_str
STRCMP (string1 ,string2 ) 逐字符比较两字串大小,
SUBSTRING (str , position [,length ]) 从str的position开始,取length个字符
LTRIM (string2 ) RTRIM (string2 ) trim 去除前端空格或后端空格

2.3 常规函数

函数名 作用
ABS (number2 ) 绝对值
BIN (decimal_number ) 十进制转二进制
CEILING (number2 ) 向上取整
CONV(number2,from_base,to_base) 进制转换
FLOOR (number2 ) 向下取整
FORMAT (number,decimal_places ) 保留小数位数
HEX (DecimalNumber ) 转十六进制
LEAST (number , number2 […]) 求最小值
MOD (numerator ,denominator ) 求余

3.自定义函数

定义:mysql中的函数与存储过程类似,都是一组SQL集

与存储过程的区别:

  1. 函数可以有return值,存储过程不能直接return,但是有输出参数可以输出多个返回值;
  2. 函数可以嵌入到sql语句中使用,但是存储过程不能;
  3. 函数一般用于实现简单的有针对性的功能(如求绝对值、返回当前时间等),存储过程用于实现复杂的功能
  4. 函数的关键字是function,存储 过程的关键字是procedure

3.1代码示例

    DROP FUNCTION IF EXISTS func_compare; -- 丢掉已经存在的函数 
    DELIMITER ;; -- 自定义分隔符,这里定义的分隔符是;;,定义好后,只有遇到;;才会结束 
    -- 这里是在连接数据库 + 创建函数 
    CREATE DEFINER='root'@'localhost' FUNCTION func_compare(a INT) RETURNS VARCHAR(200) CHARSET utf8 
    BEGIN -- 函数开始 
    String temp = ""; 
    if(a>=10){temp = "大于等于10";}else{} 
    -- 这里写的是if语句 
    IF a >= 10 THEN RETURN '大于等于10'; 
    ELSE 
    RETURN '小于10'; 
    END IF; 
    END -- 函数结束 ;;
    DELIMITER ; -- 重新将分隔符定义成; 
    -- 使用函数 
    select func_compare(4) 
    结果:小于10

4.窗口函数

窗口函数又称为开窗函数,属于分析函数的一种。用于解决复杂报表统计需求的函数。常用于计算基于组的某种值。与聚合函数区别在于:对于每个组返回多行,而聚合函数对于每个组只返回一行。简单来说窗口函数对每条详细记录开一个窗口,进行聚合统计的查询。开窗函数指定了分析函数工作的数据窗口大小,这个数据窗口大小可能会随着行的变化而变化,同时窗口函数一般不会单独使用。窗口函数内也可以进行分组和排序。

4.1 over()函数

    -- 需求: 查询每⼀个员⼯的基本信息,及所有的员⼯的数量
    select *, count(*) over() from `emp`;
    -- 需求: 查询每⼀个员⼯的基本信息,及所有员⼯的⼯资和
    select *, sum(`sal`) over() from `emp`;
    -- 需求: 查询每⼀个员⼯的基本信息,及所有员⼯的平均奖⾦
    select *, avg(ifnull(`comm`, 0)) over() from `emp`;
    -- 需求: 查询每⼀个员⼯的基本信息,及所有员⼯的平均⼯龄
    select *, avg(round(datediff(now(), `hiredate`)/365, 1)) over() from `emp`;

4.2 窗口分组

通过指定的字段,对数据进行分组,此时窗口内的数据为指定分组的数据。

例如: count(*) over(partition by deptno), 此时将数据通过deptno字段进⾏了分组,窗口内的数据是与本行的deptno相同的数据。

    -- 需求: 查询每⼀个员⼯的基本信息,及其部⻔的⼈数
    select *, count(*) over(partition by `deptno`) from `emp`;
    -- 需求: 查询每⼀个员⼯的基本信息,及其部⻔的最⾼⼯资
    select *, max(`sal`) over(partition by `deptno`) from `emp`;
    -- 需求: 查询每⼀个员⼯的基本信息,及其部⻔的平均薪资
    select *, avg(ifnull(`sal`, 0)) over(partition by `deptno`) from `emp`;
    -- 需求: 查询每⼀个员⼯的基本信息,及部⻔的平均⼯龄
    select *, avg(round(datediff(now(), `hiredate`)/365, 1)) over(partition by `deptno`) from
    `emp`;
    -- 需求: 查询每⼀个员⼯的基本信息,及当前岗位的⼈数
    select *, count(*) over(partition by `job`) from `emp`;

4.3 窗口数据排序

使用order by子句,实现窗口内的数据按照指定的条件进行升序或者降序排列。注意:窗口内的数据会逐行递增。

    select *, sum(`sal`) over(partition by `deptno` order by `sal` desc) from `emp`;

4.4 排名函数

对数据进行名次排序。常见排名函数有三种:row_number()、rank()、dense_rank()

row_number():对每一行的数据进行编号,不会出现相同的名次

rank():会出现并列的名次,同时会出现名次跳跃情况

dense_rank():会出现并列的名次,不会出现名次跳跃情况

    -- 查询每⼀个员⼯的基本信息,及员⼯在⾃⼰部⻔内的⼯资排名
    select *, rank() over(partition by `deptno` order by `sal` desc) from `emp`;
    -- 查询每⼀个员⼯的基本信息,及员⼯在所有⼈中的⼯资排名
    select *, dense_rank() over(order by `sal` desc) from `emp`;
    -- 查询每⼀个员⼯的基本信息,及员⼯在同⼀个⼯种内的⼯资排名
    select *, rank() over(partition by `job` order by `sal` desc) from `emp`;
    -- 查询每⼀个员⼯的基本信息,及员⼯在所有⼈中的⼯龄排名
    select *, rank() over(order by `hiredate`) from `emp`;
    -- 查询每⼀个员⼯的基本信息,及员⼯在当前部⻔中的⼯龄排名
    select *, rank() over(partition by `deptno` order by `hiredate`) from `emp`;

四、MySQL中的存储过程

1.简介

MySQL从5.0开始支持procedure

存储过程简单来说就是为以后的使用而保存的一条或多条的MySQL语句的集合。可以视为批件,但是它们的作用不仅限于批处理。存储过程就是有业务逻辑和流程的集合。可以在存储过程中的创建表,更新数据,删除数据等等

通过吧处理封装在容易使用的单元中,简化复杂的操作。由于不要求反复建立一系列处理步骤,保证了数据的完整性,如果所有开发人员和应用程序都使用同一存储过程,则所使用的代码都是相同的,这样就能防止错误。需要执行的步骤越多出错的可能性就越大。防止错误保证了数据一致性。简化对变动的管理。如果表名、列名或逻辑有变化,只需要更改存储过程的代码就可以。对于使用存储过程的人员不需要知道其实现过程。

2.过程说明

    DROP PROCEDURE IF EXISTS math1; -- 丢掉存储过程
    math1 DELIMITER ; -- 重新设置分隔符为;
    CREATE PROCEDURE math1 -- 创建存储过程 math1 
    (IN a INT,IN b INT) -- 传入参数 a,b IN的意思是传入参数 OUT的意思是传出参数 INOUT是既可 以传入又可以传出 
    
    BEGIN
    	declare c int default 0; -- 定义局部变量,只能在存储过程中使用 
    	set c = 3; 
    	SET @var1 = 1; -- 设置用户变量,全局使用 
    	SET @var2 = 2; 
    	SELECT @SUM:=(a + b) AS SUM, @dif:=(a - b) AS dif; 
    END; -- 结束 
    
    DELIMITER ;-- 重新设置分隔符为; 
    CALL math1(1,2) -- 调用存储过程 
    SELECT @var1; -- 调用用户变量

3.参数说明

3.1 参数in的使用

in代表输入,表示要将参数传到存储过程的过程里面去

为了避免存储过程中分号结束语句,我们使用分隔符告诉mysql解释器,该段命令已经结束了。

    -- in的使用 示例:求1-n的和
    delimiter $ 
    create procedure p1(in n int) 
    begin 
        declare total int default 0; 
        declare num int default 0; 
        while num < n do 
        set num:=num+1; 
        set total:=total+num; 
        end while; 
        select total; 
    end$
    call p1(10)$

3.2 参数out的使用

out代表输出,将存储过程中得到的数据输出出来

注意:输出参数一定要设置初始类型,否则输出的结果都为NULL值

    -- out的使用 示例:求1-n的和
    create procedure p2(in n int,out total int) 
    begin declare num int default 0; 
        set total:=0; 
        while num < n do 
        set num:=num+1; 
        set total:=total+num; 
        end while;
    end$

总结in、out区别: in:表示输入一个值,需要一个值,就给一个值 out:往外输出一个值,输出的那个值就拿一个变量来接收输出的那个值

3.3 参数inout的使用

inout既能输入一个值又能输出一个值

    -- inout的使用 示例:传一个年龄,自动让年龄增长10岁
    create procedure p3(inout age int) 
    begin 
        set age:=age+10; 
    end$ 
    -- 注意:调用的时候,inout型的参数值既是输入类型又是输出类型,给它一个值,但值不是变量,我们需要先设置一个变量并初始化这个值,调用的时候直接传这个变量即可。 
    set @currentAge=8$ 
    call p3(@currentAge)$ 
    select @currentAge$

3.4 变量说明

MySQL的变量分俩种:系统变量用户变量,但在实际的使用中还会有局部变量会话变量

3.4.1 局部变量

局部变量一般用于sql语句块中,比如存储过程的begin/end中。其作用域仅限于该语句块。在这语句块执行完毕后,局部变量就消失了。

局部变量用declare来声明,可以使用default来设置默认值。

3.4.2 用户变量

用户变量的作用域比局域变量的作用域广,可以作用于当前整个连接,但当当前的连接断开之后,所定义的用户变量都会小时。

用户变量定义:select @变量名

对用户变量赋值方式:

  1. 直接用“=”号
  2. 用“:=”号

区别:使用set命令对用户变量进行赋值时,俩种方式都可以使用。当使用select语句对用户变量进行赋值时,只能使用“:=”方式,因为在select语句中“=”被认为是比较操作符。

3.4.3 会话变量

服务器会为每个连接的客户端维护一系列会话变量。在客户端连接时,使用相应全局变量的当前值对客户端的会话变量进行初始化。设置会话变量不需要额外的特殊权限,但客户端只能更改自己的会话变量,而不能更改其他客户端的会话变量。会话变量的作用域与用户变量一样,仅限于当前连接,当前连接断开之后,设置的会话变量会失效。

设置会话变量的三种方式:

    -- 设置会话变量有如下三种方式: 
    set session var_name = value; 
    set @@session.var_name = value; 
    set var_name = value;

查看会话变量的三种方式:

    select @@var_name; 
    select @@session.var_name; 
    show session variables like "%var%"; 
    mysql> show session variables;

3.4.4 全局变量

全局变量影响服务器的整体操作。当服务器启动时,他会将所有的全局变量初始化为默认值。这些默认值可以在选项文件中或者命令行中指定的选项进行修改。要想更改全局变量,必须具有SUPER的权限。全局变量作用于server的整个生命周期。但是重启后所有设置的全局变量会全部失效。想让全局变量在重启后继续生效的话,需要更改相应的配置文件。

    -- 要设置一个全局变量,有如下两种方式: 
    set global var_name = value; -- 注意:此处的global不能省略。根据手册,set命令设置变量时若不指定 GLOBAL、SESSION或者LOCAL,默认使用SESSION 
    set @@global.var_name = value; -- 同上 
    
    -- 要想查看一个全局变量,有如下两种方式: 
    select @@global.var_name; 
    show global variables like "%var%"; 
    mysql> show global variables;

总结

以上就是有关MySQL进阶的知识部分了,不足的地方敬请指出。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由半码博客整理,本文链接:https://www.bmabk.com/index.php/post/116590.html

(0)
seven_的头像seven_bm

相关推荐

发表回复

登录后才能评论
半码博客——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!