MySQL 16 章——变量、流程控制和游标

一、变量

在MySQL数据库的存储过程和存储函数中,可以使用变量来存储查询或计算的中间结果数据,或者输出最终的结果数据

在MySQL数据库中,变量分为系统变量用户自定义变量

(1)系统变量

1.1.1系统变量分类

  1. 变量由系统定义,不是用户定义,属于服务器层面。启动MySQL服务,生成MySQL服务实例期间。MySQL将为MySQL服务器内存中的系统变量赋值,这些系统变量定义了当前MySQL服务实例的属性,特征。这些系统变量要么是编译MySQL时参数的默认值,要么是配置文件(例如my.ini等)中的参数值。大家可以通过网址MySQL :: MySQL 8.0 Reference Manual :: 7.1.8 Server System Variables查看MySQL文档的系统变量
  2. 系统变量分为全局系统变量(需要添加global关键字)以及会话系统变量(需要添加session 关键字),有时也把全局系统变量简称为全局变量,有时也把会话系统变量称为local变量。

    1. 如果不写,默认会话级别

    2. 静态变量(在 MySQL 服务实例运行期间它们的值不能使用set动态修改)属于特殊的全局系统变量

  3. 每一个MySQL客户机成功连接MySQL服务器后,都会产生与之对应的会话。会话期间,MySQL服务实例会在MySQL服务器内存中生成与该会话对应的会话系统变量,这些会话系统变量的初始值是全局系统变量值的复制:

  4. 全局系统变量针对于所有会话(连接)有效,但不能跨重启

  5. 会话系统变量仅针对于当前会话(连接)有效

  6. 会话1对某个全局系统变量值的修改会导致会话2中同一个全局系统变量值的修改

  7. 在MySQL中有些系统变量只能是全局的,例如max_connections用于限制服务器的最大连接数;有些系统变量作用域既可以是全局,也可以是会话,例如:character_set_client用于设置客户端的字符集;有些系统变量的作用域只能是当前会话,例如pseudo_thread_id用于标记当前会话的MySQL连接ID

1.1.2查看系统变量

  1. 查看所有全局变量(版本不同,全局系统变量个数不同):
    #查看所有全局变量
    SHOW GLOBAL VARIABLES;
    
  2. 查看所有会话变量(不加关键字,默认查询的是会话系统变量):
    #查看所有会话变量
    SHOW SESSION VARIABLES;
    或
    SHOW VARIABLES;
  3. 查看满足条件的部分全局变量:
    #查看满足条件的部分系统变量。
    SHOW GLOBAL VARIABLES LIKE '%标识符%';
  4. 查看满足条件的部分会话变量:
    #查看满足条件的部分会话变量
    SHOW SESSION VARIABLES LIKE '%标识符%';
    
  5. 查看指定的系统变量:
    1. 作为MySQL编码规范,MySQL中的系统变量以两个@开头,其中“@@global”仅用于标记全局系统变量,“@@session”仅用于标记会话系统变量。@@首先标记会话系统变量,如果会话系统变量不存在,则标记全局系统变量
    2. 格式:
      #查看指定的系统变量的值
      SELECT @@global.变量名;
      
      #查看指定的会话变量的值
      SELECT @@session.变量名;
      #或者
      SELECT @@变量名;
    3. 演示:
  6.  修改系统变量的值
    1. 有些时候,数据库管理员需要修改系统变量的默认值,以便修改当前会话或者MySQL服务实例的属性、特征。具体方法:
    2. 方式一:修改MySQL配置文件,继而修改MySQL系统变量的值(该方法需要重启MySQL服务)
    3. 方式二:在MySQL服务运行期间,使用“set”命令重新设置系统变量的值
      #为某个系统变量赋值
      #方式1:
      SET @@global.变量名=变量值;
      #方式2:
      SET GLOBAL 变量名=变量值;
      
      
      #为某个会话变量赋值
      #方式1:
      SET @@session.变量名=变量值;
      #方式2:
      SET SESSION 变量名=变量值;

  7. 用方式二修改全局系统变量,针对于当前数据库实例是有效的,一旦重启MySQL服务,就失效了
  8. 用方式二修改会话系统变量,针对于当前会话是有效的,一旦结束会话,重新建立起新的会话,就失效了 

(2)用户变量

1.2.1用户变量分类

  1. 用户变量是用户自己定义的。作为MySQL编码规范,MySQL中的用户变量以一个@开头。根据作用范围不同,又分为会话用户变量和局部变量
  2. 会话用户变量:作用域和会话变量一样,只对当前连接会话有效
  3. 局部变量:只在BEGIN和END语句块中有效。局部变量只能在存储过程和存储函数中使用

1.2.2会话用户变量

  1. 变量的定义:
    #方式1:“=”或“:=”
    SET @用户变量 = 值;
    SET @用户变量 := 值;
    
    #方式2:“:=” 或 INTO关键字
    SELECT @用户变量 := 表达式 [FROM 等子句];
    SELECT 表达式 INTO @用户变量  [FROM 等子句];
  2. 查看用户变量的值:
    SELECT @用户变量
  3. 代码演示:
    SET @m1 = 1;
    SET @m2 := 2;
    SET @sum := @m1 + @m2;
    SELECT @sum;
    
    CREATE DATABASE dbtest16;
    
    USE dbtest16;
    
    CREATE TABLE employees
    AS
    SELECT *
    FROM atguigudb.employees;
    
    CREATE TABLE departments
    AS
    SELECT *
    FROM atguigudb.departments;
    
    SELECT * FROM employees;
    SELECT * FROM departments;
    
    SELECT @count := COUNT(*) FROM employees;
    
    SELECT @count;
    
    SELECT AVG(salary) INTO @avg_sal FROM employees;
    
    SELECT @avg_sal;

1.2.3局部变量

  1. 定义:可以使用DECLARE语句定义一个局部变量
  2. 作用域:仅仅在定义它的BEGIN...END中有效
  3. 位置:DECLARE语句只能放在BEGIN...END中,而且只能放在第一句
  4. 格式:
    BEGIN
    	#声明局部变量
    	DECLARE 变量名1 变量数据类型 [DEFAULT 变量默认值];
    	DECLARE 变量名2,变量名3,... 变量数据类型 [DEFAULT 变量默认值];
    
    	#为局部变量赋值
    	SET 变量名1 = 值;
    	SELECT 值 INTO 变量名2 [FROM 子句];
    
    	#查看局部变量的值
    	SELECT 变量1,变量2,变量3;
    END
  5. 如果没有DEFAULT子句,初始值为NULL
  6. 代码演示:
    DELIMITER //
    
    CREATE PROCEDURE test_var()
    
    BEGIN
          DECLARE a INT DEFAULT 0;
          DECLARE b INT;
          #DECLARE a,b INT DEFAULT 0;
          DECLARE emp_name VARCHAR(25);
          
          SET a = 1;
          SET b := 2;
          
          SELECT last_name INTO emp_name FROM employees WHERE employee_id = 101;
          
          SELECT a,b,emp_name;
    END //
    
    DELIMITER ;
    
    CALL test_var();
    #举例1:声明局部变量,并分别赋值为employees表中employee_id为102的last_name和salary
    DELIMITER //
    
    CREATE PROCEDURE set_value()
    BEGIN
          DECLARE emp_name VARCHAR(25);
          DECLARE sal DOUBLE(10,2);
          
          SELECT last_name,salary INTO emp_name,sal FROM employees WHERE employee_id = 102;
          
          SELECT emp_name,sal;
    END //
    
    DELIMITER ;
    
    CALL set_value();
    #举例2:声明两个变量,求和并打印 (分别使用会话用户变量、局部变量的方式实现)
    #会话用户变量的方式:
    SET @m = 1;
    SET @n = 1;
    
    SET @sum = @m + @n;
    SELECT @sum;
    
    #局部变量的方式:
    DELIMITER //
    
    CREATE PROCEDURE add_value()
    BEGIN
          DECLARE m INT DEFAULT 1;
          DECLARE n INT DEFAULT 3;
          DECLARE sum INT;
          
          SET sum = m + n;
          SELECT sum;
    END // 
    
    DELIMITER ;
    
    CALL add_value();
    #举例3:创建存储过程“different_salary”查询某员工和他领导的薪资差距,并用IN参数emp_id接收员工id,用OUT参数dif_salary输出薪资差距结果
    DELIMITER //
    
    CREATE PROCEDURE different_salary(IN emp_id INT,OUT dif_salary DOUBLE(8,2))
    BEGIN
          DECLARE mgr_id INT;
          DECLARE emp_sal,mgr_sal DOUBLE(8,2) DEFAULT 0.0;
          
          SELECT manager_id,salary INTO mgr_id,emp_sal FROM employees WHERE employee_id = emp_id;
          SELECT salary INTO mgr_sal FROM employees WHERE employee_id = mgr_id;
          SELECT mgr_sal - emp_sal INTO dif_salary;
    END //
    
    DELIMITER ;
    
    SET @emp_id = 102;
    CALL different_salary(@emp_id,@dif_salary);
    SELECT @dif_salary;

1.2.4对比会话用户变量和局部变量

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

二、定义条件与处理程序

定义条件是事先定义程序执行过程中可能遇到的问题,处理程序定义了在遇到问题时应当采取的处理方式,并且保证存储过程或函数在遇到警告或错误时能继续执行。这样可以增强存储程序处理问题的能力,避免程序异常停止运行

说明:定义条件和处理程序在存储过程和存储函数中都是支持的

(1)案例分析

  1. 案例分析:创建一个名称为“UpdateDataNoCondition”的存储过程
    DELIMITER //
    
    CREATE PROCEDURE UpdateDataNoCondition()
    	BEGIN
    		SET @x = 1;
    		UPDATE employees SET email = NULL WHERE last_name = 'Abel';
    		SET @x = 2;
    		UPDATE employees SET email = 'aabbel' WHERE last_name = 'Abel';
    		SET @x = 3;
    	END //
    
    DELIMITER ;
  2. 调用存储过程:
  3. 可以看到,此时@x变量的值为1.结合创建存储过程的SQL语句代码可以得出:当存储过程中未定义条件和处理程序,且当存储过程中执行的SQL语句报错时,MySQL数据库会抛出错误,并退出当前SQL逻辑,不再继续向下执行

(2)定义条件

  1. 定义条件就是给MySQL中的错误码命名,这有助于存储的程序代码更清晰。它将一个错误名字和指定的错误条件关联起来。这个名字可以随后被用在定义处理程序的DECLARE HANDLER语句中
  2. 定义条件使用DECLARE语句,语法格式如下:
    DECLARE 错误名称 CONDITION FOR 错误码(或错误条件)
  3. 错误码的说明:MySQL_error_code和sqlstate_value都可以表示MySQL的错误
    1. MySQL_error_code是数值类型的错误代码
    2. sqlstate_value是长度为5的字符串类型错误代码
    3. 例如:在ERROR 1418 (HY000)中,1418是MySQL_error_code,'HY000’是sqlstate_value
    4. 例如:在ERROR 1142(42000)中,1142是MySQL_error_code,'42000’是sqlstate_value
  4. 举例:
    #定义“Field_Not_Be_NULL”错误名与MySQL中违反非空约束的错误类型是“ERROR 1048 (23000)”对应
    DECLARE Field_Not_Be_NULL CONDITION FOR 1048;
    或者
    DECLARE Field_Not_Be_NULL CONDITION FOR SQLSTATE '23000';
    #定义"ERROR 1148(42000)"错误,名称为command_not_allowed
    DECLARE command_not_allowed CONDITION FOR 1148;
    
    DECLARE command_not_allowed CONDITION FOR SQLSTATE '42000';

(3)定义处理程序

  1. 格式:
    DECLARE 处理方式 HANDLER FOR 错误类型 处理语句
  2. 处理方式:处理方式有三个取值,CONTINUE、EXIT、UNDO
    1. CONTINUE:表示遇到错误不处理,继续执行
    2. EXIT:表示遇到错误,马上退出
    3. UNDO:表示遇到错误后撤回之前的操作,MySQL中暂时不支持这样的操作
  3. 错误类型(即条件),可以有如下取值:
    1. SQLSTATE '字符串错误码':表示长度为5的sqlstate_value类型的错误代码
    2. MySQL_error_code:匹配数值类型错误代码
    3. 错误名称:表示DECLARE...CONDITION定义的错误条件名称
    4. SQLWARNING:匹配所有以01开头的SQLSTATE错误代码
    5. NOT FOUND:匹配所有以02开头的SQLSTATE错误代码
    6. SQLEXCEPTION:匹配所有没有被SQLWARNING或NOT FOUND捕获的SQLSTATE错误代码
  4. 处理语句:如果出现上述条件之一,则采用对应的处理方式,并执行指定的处理语句,语句可以是像“SET 变量 = 值”这样的简单语句,也可以是使用BEGIN...END编写的复合语句
  5. 案例:
    #方法1:捕获sqlstate_value
    DECLARE CONTINUE HANDLER FOR SQLSTATE '42S02' SET @info = 'NO_SUCH_TABLE';
    
    #方法2:捕获mysql_error_value
    DECLARE CONTINUE HANDLER FOR 1146 SET @info = 'NO_SUCH_TABLE';
    
    #方法3:先定义条件,再调用
    DECLARE no_such_table CONDITION FOR 1146;
    DECLARE CONTINUE HANDLER FOR NO_SUCH_TABLE SET @info = 'NO_SUCH_TABLE';
    
    #方法4:使用SQLWARNING
    DECLARE EXIT HANDLER FOR SQLWARNING SET @info = 'ERROR';
    
    #方法5:使用NOT FOUND
    DECLARE EXIT HANDLER FOR NOT FOUND SET @info = 'NO_SUCH_TABLE';
    
    #方法6:使用SQLEXCEPTION
    DECLARE EXIT HANDLER FOR SQLEXCEPTION SET @info = 'ERROR';

(2)案例解决

  1. 在存储过程中,定义处理程序,捕获sqlstate_value值,当遇到MySQL_error_code值为1048时,执行CONTINUE操作,并且将@proc_value的值设置为-1
    #在存储过程中,定义处理程序,捕获sqlstate_value值,当遇到MySQL_error_code值为1048时,执行CONTINUE操作,并且将@proc_value的值设置为-1
    DELIMITER //
    
    CREATE PROCEDURE UpdateDataNoCondition()
    	BEGIN
            #处理方式1
            DECLARE CONTINUE HANDLER FOR 1048 SET @proc_value = -1;
            #处理方式2
            DECLARE CONTINUE HANDLER FOR SQLSTATE '23000' SET @proc_value = -1;
      
            SET @x = 1;
            UPDATE employees SET email = NULL WHERE last_name = 'Abel';
            SET @x = 2;
            UPDATE employees SET email = 'aabbel' WHERE last_name = 'Abel';
            SET @x = 3;
    	END //
    
    DELIMITER ;
    
    CALL UpdateDataNoCondition();
    
    SELECT @x;
  2. 创建一个名称为“InsertDataWithCondition”的存储过程,在存储过程中,定义处理程序,捕获sqlstate_value值,当遇到sqlstate_value值为23000时,执行EXIT操作,并且将@proc_value的值设置为-1
    #在存储过程中,定义处理程序,捕获sqlstate_value值,当遇到sqlstate_value值为23000时,执行EXIT操作,并且将@proc_value的值设置为-1
    
    #准备工作
    ALTER TABLE departments
    ADD CONSTRAINT uk_dept_id UNIQUE(department_id);
    
    DELIMITER //
    
    CREATE PROCEDURE InsertDataWithCondition()
    	BEGIN
    		DECLARE duplicate_entry CONDITION FOR SQLSTATE '23000' ;
    		DECLARE EXIT HANDLER FOR duplicate_entry SET @proc_value = -1;
    		SET @x = 1;
    		INSERT INTO departments(department_name) VALUES('测试');
    		SET @x = 2;
    		INSERT INTO departments(department_name) VALUES('测试');
    		SET @x = 3;
    	END //
    
    DELIMITER ;
    
    CALL InsertDataWithCondition();
    
    SELECT @x;

三、流程控制

流程控制语句的作用就是控制存储过程中SQL语句的执行顺序,是我们完成复杂操作必不可少的一部分。只要是执行的程序,流程就分为三大类:

  1. 顺序结构:程序从上往下依次执行
  2. 分支结构:程序按条件进行选择执行,从两条或多条路径中选择一条执行
  3. 循环结构:程序满足一定条件下,重复执行一组语句

针对于MySQL的流程控制语句主要有三类,注意:只用于存储程序

  1. 条件判断语句:IF 语句和 CASE 语句
  2. 循环语句:LOOP、WHILE 和 REPEAT 语句
  3. 跳转语句:ITERATE 和 LEAVE 语句

(1)分支结构之IF

  1. 语法结构:
    IF 表达式1 THEN 操作1
    [ELSEIF 表达式2 THEN 操作2]……
    [ELSE 操作N]
    END IF
  2. IF的特点:
    1. 不同的表达式对应不同的操作
    2. 使用在BEGIN...END中
  3. 举例1:声明存储过程“update_salary_by_eid1”,定义IN参数emp_id,输入员工编号。判断该员工薪资如果低于8000元并且入职时间超过5年,就涨薪500元;否则就不变
    #声明存储过程“update_salary_by_eid1”,定义IN参数emp_id,输入员工编号。判断该员工薪资如果低于8000元并且入职时间超过5年,就涨薪500元;否则就不变
    DELIMITER //
    
    CREATE PROCEDURE update_salary_by_eid1(IN emp_id INT)
    BEGIN
          DECLARE emp_sal DOUBLE(8,2);
          DECLARE hire_year DOUBLE(8,2);
          
          SELECT salary INTO emp_sal FROM employees WHERE employee_id = emp_id;
          SELECT DATEDIFF(CURDATE(),hire_date) / 365 INTO hire_year FROM employees WHERE employee_id = emp_id;
          
          IF emp_sal < 8000 AND hire_year > 5 THEN UPDATE employees SET salary = salary + 500 WHERE employee_id = emp_id;
          END IF;
    END //
    
    DELIMITER ;
  4. 举例2:声明存储过程“update_salary_by_eid2”,定义IN参数emp_id,输入员工编号。判断该员工薪资如果低于9000元并且入职时间超过5年,就涨薪500元;否则就涨薪100元
    #声明存储过程“update_salary_by_eid2”,定义IN参数emp_id,输入员工编号。判断该员工薪资如果低于9000元并且入职时间超过5年,就涨薪500元;否则就涨薪100元
    DELIMITER //
    
    CREATE PROCEDURE update_salary_by_eid2(IN emp_id INT)
    BEGIN
          DECLARE emp_sal DOUBLE(8,2);
          DECLARE hire_year DOUBLE(8,2);
          
          SELECT salary INTO emp_sal FROM employees WHERE employee_id = emp_id;
          SELECT DATEDIFF(CURDATE(),hire_date) / 365 INTO hire_year FROM employees WHERE employee_id = emp_id;
          
          IF emp_sal < 9000 AND hire_year > 5 THEN UPDATE employees SET salary = salary + 500 WHERE employee_id = emp_id;
          ELSE UPDATE employees SET salary = salary + 100 WHERE employee_id = emp_id;
          END IF;
    END //
    
    DELIMITER ;
  5. 举例3:声明存储过程“update_salary_by_eid3”,定义IN参数emp_id,输入员工编号。判断该员工薪资如果低于9000元,就更新薪资为9000元;薪资如果大于等于9000元且低于10000的,但是奖金比例为NULL的,就更新奖金比例为0.01;其他的涨薪100元
    #声明存储过程“update_salary_by_eid3”,定义IN参数emp_id,输入员工编号。判断该员工薪资如果低于9000元,就更新薪资为9000元;薪资如果大于等于9000元且低于10000的,但是奖金比例为NULL的,就更新奖金比例为0.01;其他的涨薪100元
    
    DELIMITER //
    
    CREATE PROCEDURE update_salary_by_eid3(IN emp_id INT)
    BEGIN
          DECLARE emp_sal DOUBLE(8,2);
          DECLARE bonus DOUBLE(2,2);
          
          SELECT salary,commission_pct INTO emp_sal,bonus FROM employees WHERE employee_id = emp_id;
          IF emp_sal < 9000 THEN UPDATE employees SET salary = 9000 WHERE employee_id = emp_id;
          ELSEIF emp_sal >= 9000 AND emp_sal < 10000 AND bonus IS NULL 
          THEN UPDATE employees SET commission_pct = 0.01 WHERE employee_id = emp_id;
          ELSE UPDATE employees SET salary = salary + 100 WHERE employee_id = emp_id;
          END IF;
    END //
    
    DELIMITER ;

(2)分支结构之CASE

  1. CASE语句的语法结构一:
    #情况一:类似于switch
    CASE 表达式
    WHEN 值1 THEN 结果1或语句1(如果是语句,需要加分号) 
    WHEN 值2 THEN 结果2或语句2(如果是语句,需要加分号)
    ...
    ELSE 结果n或语句n(如果是语句,需要加分号)
    END [case](如果是放在begin end中需要加上case,如果放在select后面不需要)
  2. CASE语句的语法结构二:
    #情况二:类似于多重if
    CASE 
    WHEN 条件1 THEN 结果1或语句1(如果是语句,需要加分号) 
    WHEN 条件2 THEN 结果2或语句2(如果是语句,需要加分号)
    ...
    ELSE 结果n或语句n(如果是语句,需要加分号)
    END [case](如果是放在begin end中需要加上case,如果放在select后面不需要)
  3. 举例1:声明存储过程“update_salary_by_eid4”,定义IN参数emp_id,输入员工编号。判断该员工薪资如果低于9000元,就更新薪资为9000元;薪资大于等于9000元且低于10000的,但是奖金比例为NULL的,就更新奖金比例为0.01;其他的涨薪100元
    #声明存储过程“update_salary_by_eid4”,定义IN参数emp_id,输入员工编号。判断该员工薪资如果低于9000元,就更新薪资为9000元;薪资大于等于9000元且低于10000的,但是奖金比例为NULL的,就更新奖金比例为0.01;其他的涨薪100元
    DELIMITER //
    
    CREATE PROCEDURE update_salary_by_eid4(IN emp_id INT)
    BEGIN
          DECLARE emp_sal DOUBLE;
          DECLARE bonus DOUBLE(2,2);
          
          SELECT salary,commission_pct INTO emp_sal,bonus FROM employees WHERE employee_id = emp_id;
          
          CASE 
          WHEN emp_sal < 9000 
              THEN UPDATE employees SET salary = 9000 WHERE employee_id = emp_id;
          WHEN emp_sal >= 9000 AND emp_sal < 10000 AND bonus IS NULL
              THEN UPDATE employees SET commission_pct = 0.01 WHERE employee_id = emp_id;
          ELSE 
              UPDATE employees SET salary = salary + 100 WHERE employee_id = emp_id;
          END CASE;
    END //
    
    DELIMITER ;
  4. 举例2:声明存储过程update_salary_by_eid5,定义IN参数emp_id,输入员工编号。判断该员工的入职年限,如果是0年,薪资涨50;如果是1年,薪资涨100;如果是2年,薪资涨200;如果是3年,薪资涨300;如果是4年,薪资涨400;其他的涨薪500
    #声明存储过程update_salary_by_eid5,定义IN参数emp_id,输入员工编号。判断该员工的入职年限,如果是0年,薪资涨50;如果是1年,薪资涨100;如果是2年,薪资涨200;如果是3年,薪资涨300;如果是4年,薪资涨400;其他的涨薪500
    
    DELIMITER //
    
    CREATE PROCEDURE update_salary_by_eid5(IN emp_id INT)
    BEGIN
          DECLARE hire_year INT;
          
          SELECT ROUND(DATEDIFF(CURDATE(),hire_date) / 365) INTO hire_year FROM employees WHERE employee_id = emp_id;
          
          CASE hire_year 
          WHEN 0 
          THEN UPDATE employees SET salary = salary + 50 WHERE employee_id = emp_id;
          WHEN 1 
          THEN UPDATE employees SET salary = salary + 100 WHERE employee_id = emp_id;
          WHEN 2 
          THEN UPDATE employees SET salary = salary + 200 WHERE employee_id = emp_id;
          WHEN 3 
          THEN UPDATE employees SET salary = salary + 300 WHERE employee_id = emp_id;
          WHEN 4 
          THEN UPDATE employees SET salary = salary + 400 WHERE employee_id = emp_id;
          ELSE
          UPDATE employees SET salary = salary + 500 WHERE employee_id = emp_id;
          END CASE;                    
    END //
    DELIMITER ;

(3)循环结构之LOOP

  1. LOOP循环语句用来重复执行某些语句。LOOP内的语句一直重复执行,直到循环被退出(使用LEAVE子句),跳出循环过程
  2. LOOP语句的基本格式如下:
    [loop_label:] LOOP
    	循环执行的语句
    END LOOP [loop_label]
  3. 当市场环境变好时,公司为了奖励大家,决定给大家涨工资。声明存储过程“update_salary_loop()”,声明OUT参数num,输出循环次数。存储过程中实现循环给大家涨薪,薪资涨为原来的1.1倍。直到全公司的平均薪资达到12000结束。并统计循环次数
    #当市场环境变好时,公司为了奖励大家,决定给大家涨工资。声明存储过程“update_salary_loop()”,声明OUT参数num,输出循环次数。存储过程中实现循环给大家涨薪,薪资涨为原来的1.1倍。直到全公司的平均薪资达到12000结束。并统计循环次数
    
    DELIMITER //
    
    CREATE PROCEDURE update_salary_loop(OUT num INT)
    BEGIN
          DECLARE avg_sal DOUBLE;
          DECLARE loop_count INT DEFAULT 0;
          
          SELECT AVG(salary) INTO avg_sal FROM employees;
          
          label_loop:LOOP
              IF avg_sal >= 12000 THEN LEAVE label_loop;
              END IF;
              
              UPDATE employees SET salary = salary * 1.1;
              SET loop_count = loop_count + 1;
              SELECT AVG(salary) INTO avg_sal FROM employees;
          END LOOP label_loop;
          
          SET num = loop_count;
    END //
    
    DELIMITER ;
    
    CALL update_salary_loop(@num);
    
    SELECT @num;
  4. 凡是循环条件,一定具备这四个要素:
    1. 初始化条件
    2. 循环条件
    3. 循环体
    4. 迭代条件 

(4)循环结构之WHILE

  1. WHILE语句创建一个带条件判断的循环过程。WHILE在执行语句时,先对指定的表达式进行判断,如果为真,就执行循环内的语句,否则退出循环
  2. WHILE语句的基本格式如下:
    [while_label:] WHILE 循环条件  DO
    	循环体
    END WHILE [while_label];
  3. 市场环境不好时,公司为了渡过难关,决定暂时降低大家的薪资。声明存储过程“update_salary_while()”,声明OUT参数num,输出循环次数。存储过程中实现循环给大家降薪,薪资降为原来的90%。直到全公司的平均薪资达到5000结束。并统计循环次数
    #市场环境不好时,公司为了渡过难关,决定暂时降低大家的薪资。声明存储过程“update_salary_while()”,声明OUT参数num,输出循环次数。存储过程中实现循环给大家降薪,薪资降为原来的90%。直到全公司的平均薪资达到5000结束。并统计循环次数
    
    DELIMITER //
    
    CREATE PROCEDURE update_salary_while(OUT num INT)
    BEGIN
          DECLARE avg_sal DOUBLE;
          DECLARE while_count INT DEFAULT 0;
          
          SELECT AVG(salary) INTO avg_sal FROM employees;#初始化条件
          
          WHILE avg_sal > 5000 DO#循环条件
              UPDATE employees SET salary = salary * 0.9;#循环体
              SET while_count = while_count + 1;#循环体
              SELECT AVG(salary) INTO avg_sal FROM employees;#迭代条件
          END WHILE;
          
          SET num = while_count;
    END //
    
    DELIMITER ;
    
    CALL update_salary_while(@num);
    
    SELECT @num;
    
    SELECT AVG(salary) FROM employees;

(5)循环结构之REPEAT

  1. REPEAT语句创建一个带条件判断的循环过程。与WHILE循环不同的是,REPEAT循环首先会执行一次循环,然后在 UNTIL 中进行表达式的判断,如果满足条件就退出,即 END REPEAT;如果条件不满足,则会就继续执行循环,直到满足退出条件为止
  2. REPEAT语句的基本格式如下:
    [repeat_label:] REPEAT
        循环体的语句
    UNTIL 结束循环的条件表达式
    END REPEAT [repeat_label]
  3. 当市场环境变好时,公司为了奖励大家,决定给大家涨工资。声明存储过程“update_salary_repeat()”,声明OUT参数num,输出循环次数。存储过程中实现循环给大家涨薪,薪资涨为原来的1.15倍。直到全公司的平均薪资达到13000结束。并统计循环次数
    #当市场环境变好时,公司为了奖励大家,决定给大家涨工资。声明存储过程“update_salary_repeat()”,声明OUT参数num,输出循环次数。存储过程中实现循环给大家涨薪,薪资涨为原来的1.15倍。直到全公司的平均薪资达到13000结束。并统计循环次数
    
    DELIMITER //
    
    CREATE PROCEDURE update_salary_repeat(OUT num INT)
    BEGIN
          DECLARE avg_sal DOUBLE;
          DECLARE repeat_count INT DEFAULT 0;
          
          SELECT AVG(salary) INTO avg_sal FROM employees;
          
          label_repeat:REPEAT
              UPDATE employees SET salary = salary * 1.15;
              SET repeat_count = repeat_count + 1;
              SELECT AVG(salary) INTO avg_sal FROM employees;
              
              UNTIL avg_sal >= 13000
          END REPEAT label_repeat;
          
          SET num = repeat_count;
    END //
    
    DELIMITER ;
    
    CALL update_salary_repeat(@num);
    
    SELECT @num;
    
    SELECT AVG(salary) FROM employees;
  4. 对比三种循环结构:
    1. 这三种循环都可以省略名称,但如果循环中添加了循环控制语句(LEAVE或ITERATE)则必须添加名称
    2. LOOP:一般用于实现简单的"死"循环
    3. WHILE:先判断后执行
    4. REPEAT:先执行后判断,无条件至少执行一次 

(6)跳转语句之LEAVE语句

  1. LEAVE语句:可以用在循环语句内,或者以 BEGIN 和 END 包裹起来的程序体内,表示跳出循环或者跳出程序体的操作。如果你有面向过程的编程语言的使用经验,你可以把 LEAVE 理解为 break
  2. 基本格式如下:
    LEAVE 标记名
  3. 当市场环境不好时,公司为了渡过难关,决定暂时降低大家的薪资。声明存储过程“leave_while()”,声明OUT参数num,输出循环次数,存储过程中使用WHILE循环给大家降低薪资为原来薪资的90%,直到全公司的平均薪资小于等于10000,并统计循环次数
    #当市场环境不好时,公司为了渡过难关,决定暂时降低大家的薪资。声明存储过程“leave_while()”,声明OUT参数num,输出循环次数,存储过程中使用WHILE循环给大家降低薪资为原来薪资的90%,直到全公司的平均薪资小于等于10000,并统计循环次数
    
    DELIMITER //
    
    CREATE PROCEDURE leave_while(OUT num INT)
    BEGIN
          DECLARE avg_sal DOUBLE;
          DECLARE while_count INT DEFAULT 0;
          
          SELECT AVG(salary) INTO avg_sal FROM employees;#初始化语句
          
          label_while:WHILE TRUE DO#循环条件
              IF avg_sal <= 10000 THEN LEAVE label_while;
              END IF;
              UPDATE employees SET salary = salary * 0.9;#循环体
              SET while_count = while_count + 1;#循环体
              SELECT AVG(salary) INTO avg_sal FROM employees;#迭代条件     
          END WHILE label_while;
          
          SET num = while_count;
    END //
    
    DELIMITER ;
    
    CALL leave_while(@num);
    SELECT @num;
    SELECT AVG(salary) FROM employees;

(7)跳转语句之ITERATE语句

  1. ITERATE语句:只能用在循环语句(LOOP、REPEAT和WHILE语句)内,表示重新开始循环,将执行顺序转到语句段开头处。如果你有面向过程的编程语言的使用经验,你可以把 ITERATE 理解为 continue,意思为“再次循环”
  2. 基本格式如下:
    ITERATE label
  3. 定义局部变量num,初始值为0。循环结构中执行num + 1操作(1)如果num < 10,则继续执行循环(2)如果num > 15,则退出循环结构
    #定义局部变量num,初始值为0。循环结构中执行num + 1操作(1)如果num < 10,则继续执行循环(2)如果num > 15,则退出循环结构
    
    DELIMITER //
    
    CREATE PROCEDURE test_iterate()
    BEGIN
          DECLARE num INT DEFAULT 0;
          
          label_loop:LOOP
              SET num = num + 1;
              IF num < 10 THEN ITERATE label_loop;
              ELSEIF num > 15 THEN LEAVE label_loop;
              END IF;
              
              SELECT '尚硅谷:让天下没有难学的技术';
          END LOOP label_loop;
    END //
    
    DELIMITER ;
    
    CALL test_iterate();

四、游标

(1)什么是游标(或光标)

  1. 虽然我们也可以通过筛选条件WHERE和HAVING,或者是限定返回记录的关键字LIMIT返回一条记录,但是却无法在结果集中像指针一样,向前定位一条记录,向后定位一条记录,或者是随意定位到某一条记录,并对记录的数据进行处理
  2. 这个时候就可以用到游标。游标,提供了一种灵活的操作方式。让我们能够对结果集中的每一条记录进行定位,并对指向的记录中的数据进行操作的数据结构。游标让SQL这种面向集合的语言有了面向过程开发的能力
  3. 在SQL中,游标是一种临时的数据库对象,可以指向存储在数据库表中的数据行。这里,游标充当了指针的作用,我们可以通过操作游标来对数据行进行操作
  4. MySQL中,游标可以在存储过程和函数中使用

(2)使用游标步骤

  1. 游标必须在声明处理程序之前被声明,并且变量和条件还必须在声明游标或处理程序之前被声明
  2. 如果我们想要使用游标,一般需要经历四个步骤。不同的DBMS中,使用游标的语法可能不同
  3. 第一步:声明游标(在MySQL中)
    DECLARE cursor_name CURSOR FOR select_statement; 
  4. 要使用 SELECT 语句来获取数据结果集,而此时还没有开始遍历数据,这里 select_statement 代表的是 SELECT 语句,返回一个用于创建游标的结果集
  5. 第二步:打开游标
    OPEN cursor_name;
  6. 第三步:使用游标
    FETCH cursor_name INTO var_name [, var_name] ...
  7. 这句的作用是使用 cursor_name 这个游标来读取当前行,并且将数据保存到 var_name 这个变量中,游标指针指到下一行。如果游标读取的数据行有多个列名,则在 INTO 关键字后面赋值给多个变量名即可
  8. 注意:游标的查询结果集中的字段数,必须跟INTO后面的变量数一致。否则,在存储过程执行的时候,MySQL 会提示错误
  9. 第四步:关闭游标
    CLOSE cursor_name;
  10. 有OPEN就会有CLOSE,也就是打开游标和关闭游标。当我们使用完游标后需要关闭掉该游标。因为游标会占用系统资源,如果不及时关闭,游标会一直保持到存储过程结束,影响系统运行的效率。而关闭游标的操作,会释放游标占用的系统资源
  11. 关闭游标之后,我们就不能再检索查询结果中的数据行,如果需要检索只能再次打开游标

(3)举例

  1. 创建存储过程“get_count_by_limit_total_salary()”,声明IN参数 limit_total_salary,DOUBLE类型;声明OUT参数total_count,INT类型。函数的功能可以实现累加薪资最高的几个员工的薪资值,直到薪资总和达到limit_total_salary参数的值,返回累加的人数给total_count

    #创建存储过程“get_count_by_limit_total_salary()”,声明IN参数 limit_total_salary,DOUBLE类型;声明OUT参数total_count,INT类型。函数的功能可以实现累加薪资最高的几个员工的薪资值,直到薪资总和达到limit_total_salary参数的值,返回累加的人数给total_count
    
    DELIMITER //
    
    CREATE PROCEDURE get_count_by_limit_total_salary(IN limit_total_salary DOUBLE,OUT total_count INT)
    BEGIN
          DECLARE sum_salary DOUBLE DEFAULT 0.0;
          DECLARE cursor_salary DOUBLE DEFAULT 0.0;
          DECLARE emp_count INT DEFAULT 0;
          
          #定义游标
          DECLARE emp_cursor CURSOR FOR SELECT salary FROM employees ORDER BY salary DESC;
          #打开游标
          OPEN emp_cursor;
          
          REPEAT
              #使用游标,从游标中获取数据
              FETCH emp_cursor INTO cursor_salary;
              
              SET emp_count = emp_count + 1;
              SET sum_salary = sum_salary + cursor_salary;
              
              UNTIL sum_salary >= limit_total_salary
          END REPEAT;
          
          SET total_count = emp_count;
          
          #关闭游标
          CLOSE emp_cursor;
    END//
    
    DELIMITER ;

(4)小结

  1. 游标是MySQL的一个重要功能,为逐条读取结果集中的数据,提供了完美的解决方案。跟在应用层面实现相同的功能相比,游标可以在存储程序中使用,效率高,程序也更加简洁
  2. 但同时也会带来一些性能问题,比如在使用游标的过程中,会对数据行进行加锁。这样在业务并发量大的时候,不仅会影响业务之间的效率,还会消耗系统资源,造成内存不足,这是因为游标是在内存中进行的处理
  3. 建议:养成用完之后就关闭的习惯,这样才能提高系统的整体效率

(5)补充:MySQL8.0的新特性——全局变量的持久化

  1. 在MySQL数据库中,全局变量可以通过SET GLOBAL语句来设置。例如设置服务器语句超时的限制,可以通过设置系统变量max_execution_time来实现
    SET GLOBAL MAX_EXECUTION_TIME=2000;
  2. 使用SET GLOBAL语句设置的变量值只会临时生效。数据库重启后,服务器又会从MySQL配置文件中读取变量的默认值
  3. MySQL8.0版本新增了SET PERSIST命令。例如,设置服务器的最大连接数为1000
    SET PERSIST global max_connections = 1000;
  4. MySQL会将该命令的配置保存到数据目录下的mysqld_auto.cnf文件中,下次启动时会读取该文件,用其中的配置来覆盖默认的配置文件

五、课后练习一

  1. 准备工作
    CREATE DATABASE IF NOT EXISTS test16_var_cur;
    
    USE test16_var_cur;
    
    CREATE TABLE employees
    AS
    SELECT * FROM atguigudb.`employees`;
    
    
    CREATE TABLE departments
    AS
    SELECT * FROM atguigudb.`departments`;
    
    SET GLOBAL log_bin_trust_function_creators=1;
  2. 创建函数get_count(),返回公司的员工个数
    DELIMITER //
    
    CREATE FUNCTION get_count()
    RETURNS INT
    BEGIN
          DECLARE num INT;#公司的员工个数
          SELECT COUNT(*)   INTO num FROM employees;
          RETURN num;
    END //
    
    DELIMITER ;
    
    SELECT get_count();
  3. 创建函数ename_salary(),根据员工姓名,返回它的工资
    DELIMITER //
    
    CREATE FUNCTION ename_salary(ename VARCHAR(25))
    RETURNS DOUBLE(8,2)
    BEGIN
          DECLARE esal DOUBLE(8,2);
          SELECT salary INTO esal FROM employees WHERE last_name = ename;
          RETURN esal;
    END //
    
    DELIMITER ;
    
    SELECT ename_salary('Abel');
  4. 创建函数dept_sal() ,根据部门名,返回该部门的平均工资
    DELIMITER //
    
    CREATE FUNCTION dept_sal(dept_name VARCHAR(30))
    RETURNS DOUBLE(8,2)
    BEGIN
          DECLARE dept_id INT;#部门id
          DECLARE dept_avg_sal DOUBLE;#部门平均工资
          
          SELECT department_id INTO dept_id FROM departments WHERE department_name = dept_name;
          SELECT AVG(salary) INTO dept_avg_sal 
          FROM employees
          WHERE department_id = dept_id;
          
          RETURN dept_avg_sal;
          
    END //
    
    DELIMITER ;
  5. 创建函数add_float(),实现传入两个float,返回二者之和
    DELIMITER //
    
    CREATE FUNCTION add_float(m FLOAT,n FLOAT)
    RETURNS FLOAT
    BEGIN
          DECLARE sum FLOAT;
          SET sum = m + n;
          RETURN sum;
    END //
    
    DELIMITER ;
    
    SELECT add_float(5.12,13.14);

六、课后练习二

  1. 创建函数test_if_case(),实现传入成绩,如果成绩>90,返回A,如果成绩>80,返回B,如果成绩>60,返回C,否则返回D,要求:分别使用if结构和case结构实现
    #方式一:if结构
    DELIMITER //
    
    CREATE FUNCTION test_if_case1(score DOUBLE)
    RETURNS CHAR
    BEGIN
          DECLARE grade CHAR;
          
          IF score > 90 THEN SET grade = 'A';
          ELSEIF score > 80 THEN SET grade = 'B';
          ELSEIF score > 60 THEN SET grade = 'C';
          ELSE SET grade = 'D';
          END IF;
          
          RETURN grade;
    END //
    
    DELIMITER ;
    
    SELECT test_if_case1(55);
    #方式二:case结构
    DELIMITER //
    
    CREATE FUNCTION test_if_case2(score DOUBLE)
    RETURNS CHAR
    BEGIN
          DECLARE grade CHAR;
          
          CASE 
          WHEN score > 90 THEN SET grade = 'A';
          WHEN score > 80 THEN SET grade = 'B';
          WHEN score > 60 THEN SET grade = 'C';
          ELSE SET grade = 'D';
          END CASE;
          
          RETURN grade;
    END //
    
    DELIMITER ;
    
    SELECT test_if_case2(45);
  2. 创建存储过程test_if_pro(),传入工资值,如果工资值<3000,则删除工资为此值的员工,如果3000 <= 工资值 <= 5000,则修改此工资值的员工薪资涨1000,否则涨工资500
    DELIMITER //
    
    CREATE PROCEDURE test_if_pro(IN emp_sal DOUBLE(8,2))
    BEGIN
          IF emp_sal < 3000 
          THEN DELETE FROM employees WHERE salary = emp_sal;
          ELSEIF emp_sal >= 3000 AND emp_sal <= 5000
          THEN UPDATE employees SET salary = salary + 1000 WHERE salary = emp_sal;
          ELSE UPDATE employees SET salary = salary + 500 WHERE salary = emp_sal;
          END IF;
    END //
    
    DELIMITER ;
  3. 创建存储过程insert_data(),传入参数为 IN 的 INT 类型变量 insert_count,实现向admin表中批量插入insert_count条记录
    CREATE TABLE admin(
    id INT PRIMARY KEY AUTO_INCREMENT,
    user_name VARCHAR(25) NOT NULL,
    user_pwd VARCHAR(35) NOT NULL
    );
    
    SELECT * FROM admin;
    
    DELIMITER //
    
    CREATE PROCEDURE insert_data(IN insert_count INT)
    BEGIN
          DECLARE while_count INT DEFAULT 0;
          
          WHILE while_count < insert_count DO
              INSERT INTO admin(user_name,user_pwd)
              VALUES(CONCAT('atguigu-',while_count),ROUND(RAND()*1000000));
              
              SET while_count = while_count + 1;
          END WHILE;
    END //
    
    DELIMITER ;

七、课后练习三 

  1. 题目描述:
    创建存储过程update_salary(),参数1为 IN 的INT型变量dept_id,表示部门id;
    参数2为 IN的INT型变量change_sal_count,表示要调整薪资的员工个数。
    查询指定id部门的员工信息,按照salary升序排列,根据hire_date的情况,
    调整前change_sal_count个员工的薪资,详情如下。
    
    hire_date 				                salary
    hire_date < 1995 			            salary = salary*1.2
    hire_date >=1995 and hire_date <= 1998 	salary = salary*1.15
    hire_date > 1998 and hire_date <= 2001 	salary = salary *1.10
    hire_date > 2001 			            salary = salary * 1.05
  2. 代码:
    DELIMITER //
    
    CREATE PROCEDURE update_salary(IN dept_id INT,IN change_sal_count)
    BEGIN
          DECLARE emp_id INT;
          DECLARE emp_hire_date DATE;
          DECLARE while_count INT DEFAULT 0;
          
          #定义游标
          DECLARE emp_cursor CURSOR FOR 
          SELECT employee_id,hire_date FROM employees WHERE department_id = dept_id ORDER BY salary ASC;
          
          #打开游标
          OPEN emp_cursor;
          
          #使用游标
          WHILE while_count < change_sal_count DO
              FETCH emp_cursor INTO emp_id,emp_hire_date;
              
              IF YEAR(hire_date) < 1995 
                THEN UPDATE employees SET salary = salary * 1.2 WHERE employee_id = emp_id;
              ELSEIF YEAR(hire_date) >= 1995 AND YEAR(hire_date) <= 1998
                THEN UPDATE employees SET salary = salary * 1.15 WHERE employee_id = emp_id;
              ELSEIF YEAR(hire_date) > 1998 AND YEAR(hire_date) <= 2001
                THEN UPDATE employees SET salary = salary * 1.10 WHERE employee_id = emp_id;
              ELSE 
                UPDATE employees SET salary = salary * 1.05 WHERE employee_id = emp_id;
              END IF;
              
              SET while_count = while_count + 1;
          END WHILE;
          
          #关闭游标
          CLOSE emp_cursor;
          
    END //
    
    DELIMITER ;

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/953675.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

T-SQL编程

目录 1、T-SQL的元素 1.1 标识符 1. 常规标识符 2. 分隔标识符 1.2 变量 1. 全局变量 2. 局部变量 1.3 运算符 1. 算数运算符 2. 赋值运算符 3. 位运算符 4. 比较运算符 5. 逻辑运算符 6. 字符串连接运算符 7. 一元运算符 8. 运算符的优先级和结合性 1.4 批处…

2024 China Collegiate Programming Contest (CCPC) Zhengzhou Onsite 基础题题解

L. Z-order Curve 思路&#xff1a;这题目说了&#xff0c;上面那一行&#xff0c;只有在偶数位才有可能存在1&#xff0c;那么一定存在这样的数&#xff0c;0 ,1,100, 10000,那么反之&#xff0c;我们的数列是行的二倍&#xff0c;因此会出现10,1000,100000这样的数&#xff0…

Unity2D初级背包设计后篇 拓展举例与不足分析

Unity2D初级背包设计中篇 MVC分层撰写(万字详解)-CSDN博客、 如果你已经搞懂了中篇&#xff0c;那么对这个背包的拓展将极为简单&#xff0c;我就在这里举个例子吧 目录 1.添加物品描述信息 2.拓展思路与不足分析 1.没有删除只有丢弃功能&#xff0c;所以可以添加垃圾桶 2.格…

vue(七) vue进阶

目录 第一课&#xff1a;Vue方法、计算机属性及侦听器 一、数组变化侦测 方法1&#xff1a;变更方法 方法2&#xff1a;替换一个数组 例子&#xff1a;小Demo:合并两个数组 二、计算属性 1.基础&#xff08;不推荐&#xff09; 2.使用计算属性来完成案例 3.使用函数的方…

Spring Boot 2 学习指南与资料分享

Spring Boot 2 学习资料 Spring Boot 2 学习资料 Spring Boot 2 学习资料 在当今竞争激烈的 Java 后端开发领域&#xff0c;Spring Boot 2 凭借其卓越的特性&#xff0c;为开发者们开辟了一条高效、便捷的开发之路。如果你渴望深入学习 Spring Boot 2&#xff0c;以下这份精心…

YangQG 面试题汇总

一、交叉链表 问题&#xff1a; 给你两个单链表的头节点 headA 和 headB &#xff0c;请你找出并返回两个单链表相交的起始节点。如果两个链表不存在相交节点&#xff0c;返回 null 。 解题思想&#xff1a; 双指针 备注&#xff1a;不是快慢指针&#xff0c;如果两个长度相…

fastapi 使用

参考&#xff1a; https://fastapi.tiangolo.com/zh/tutorial/first-steps/https://fastapi.tiangolo.com/zh/tutorial/first-steps/ FastAPI 用于基于标准 Python 类型提示使用 Python 构建 API&#xff0c;使用 ASGI 的标准来构建 Python Web 框架和服务器。所有简单理解&a…

2024年度漏洞态势分析报告,需要访问自取即可!(PDF版本)

2024年度漏洞态势分析报告&#xff0c;需要访问自取即可!(PDF版本),大家有什么好的也可以发一下看看

泛目录和泛站有什么差别

啥是 SEO 泛目录&#xff1f; 咱先来说说 SEO 泛目录是啥。想象一下&#xff0c;你有一个巨大的图书馆&#xff0c;里面的书架上摆满了各种各样的书&#xff0c;每一本书都代表着一个网页。而 SEO 泛目录呢&#xff0c;就像是一个超级图书管理员&#xff0c;它的任务就是把这些…

k8s基础(6)—Kubernetes-存储

Kubernetes-存储概述 k8s的持久券简介 Kubernetes的持久卷&#xff08;PersistentVolume, PV&#xff09;和持久卷声明&#xff08;PersistentVolumeClaim, PVC&#xff09;为用户在Kubernetes中使用卷提供了抽象。PV是集群中的一块存储&#xff0c;PVC是对这部分存储的请求。…

深度学习-卷积神经网络反向传播梯度公式推导

这篇文章非常棒&#xff0c;单样本单通道的反向传播梯度公式推导我都理解了。为了防止找不到原网页&#xff0c;所以特复制于此 参考&#xff1a; https://zhuanlan.zhihu.com/p/640697443

论文笔记(四十七)Diffusion policy: Visuomotor policy learning via action diffusion(下)

Diffusion policy: Visuomotor policy learning via action diffusion&#xff08;下&#xff09; 文章概括5. 评估5.1 模拟环境和数据集5.2 评估方法论5.3 关键发现5.4 消融研究 6 真实世界评估6.1 真实世界Push-T任务6.2 杯子翻转任务6.3 酱汁倒入和涂抹任务 7. 实际双臂任务…

C#学习笔记 --- 简单应用

1.operator 运算符重载&#xff1a;使自定义类可以当做操作数一样进行使用。规则自己定。 2.partial 分部类&#xff1a; 同名方法写在不同位置&#xff0c;可以当成一个类使用。 3.索引器&#xff1a;使自定义类可以像数组一样通过索引值 访问到对应的数据。 4.params 数…

汽车基础软件AutoSAR自学攻略(四)-AutoSAR CP分层架构(3) (万字长文-配21张彩图)

汽车基础软件AutoSAR自学攻略(四)-AutoSAR CP分层架构(3) (万字长文-配21张彩图) 前面的两篇博文简述了AutoSAR CP分层架构的概念&#xff0c;下面我们来具体到每一层的具体内容进行讲解&#xff0c;每一层的每一个功能块力求用一个总览图&#xff0c;外加一个例子的图给大家进…

【2024年华为OD机试】 (CD卷,100分)- 最大N个数与最小N个数的和(Java JS PythonC/C++)

一、问题描述 题目描述 给定一个数组&#xff0c;编写一个函数来计算它的最大N个数与最小N个数的和。你需要对数组进行去重。 说明&#xff1a; 数组中数字范围 [0, 1000]最大N个数与最小N个数不能有重叠&#xff0c;如有重叠&#xff0c;输入非法返回 -1输入非法返回 -1 …

WINFORM - DevExpress -> DevExpress总结[安装、案例]

安装devexpress软件 路径尽量不换&#xff0c;后面破解不容易出问题 vs工具箱添加控件例如: ①使用控制台进入DevExpress安装目录: cd C:\Program Files (x86)\DevExpress 20.1\Components\Tools ②添加DevExpress控件&#xff1a; ToolboxCreator.exe/ini:toolboxcreator…

cursor+deepseek构建自己的AI编程助手

文章目录 准备工作在Cursor中添加deepseek 准备工作 下载安装Cursor &#xff08;默认安装在C盘&#xff09; 注册deepseek获取API key 在Cursor中添加deepseek 1、打开cursor&#xff0c;选择设置 选择Model&#xff0c;添加deepseek-chat 注意这里去掉其他的勾选项&…

《零基础Go语言算法实战》【题目 2-7】defer 关键字特性

《零基础Go语言算法实战》 【题目 2-7】defer 关键字特性 下面代码的输出是什么&#xff1f;请说明原因。 package main import ( "fmt" ) func main() { deferFunc() func deferFunc() { defer func() { fmt.Println("value1") }() defer func() {…

如何规模化实现完全自动驾驶?Mobileye提出解题“新”思路

在CES 2025上&#xff0c;Mobileye展示了端到端自动驾驶系统Mobileye Drive™&#xff0c;通过高度集成的传感器、算法和计算平台&#xff0c;可以实现自动驾驶功能的全覆盖。 Mobileye创始人兼首席执行官Amnon Shashua教授 期间&#xff0c;Mobileye创始人兼首席执行官Amnon …

腾讯云AI代码助手编程挑战赛-智能聊天助手

作品简介 本作品开发于腾讯云 AI 代码助手编程挑战赛&#xff0c;旨在体验腾讯云 AI 代码助手在项目开发中的助力。通过这一开发过程&#xff0c;体验到了 AI 辅助编程的高效性。 技术架构 前端: 使用 VUE3、TypeScript、TDesign 和 ElementUI 实现。 后端: 基于 Python 开发…