mysql 存储过程循环

本文介绍了一个MySQL存储过程,用于更新客户信息表中的跟踪ID。通过游标遍历最新记录并将其关联到对应的客户ID上,实现数据同步。


create procedure pName(in a,out b,inout c) 

begin

 declare row_cus_id int;
 declare row_track_Id int;
 


-- 遍历数据结束标志
  DECLARE done INT DEFAULT FALSE;


 declare groupCursor cursor for SELECT id,cus_id from t_ct_cus_track where id in (SELECT MAX(id) FROM t_ct_cus_track GROUP BY cus_id);




  -- 将结束标志绑定到游标
  DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;  


open groupCursor;

 -- 开始循环
  read_loop: LOOP
    -- 提取游标里的数据,这里只有一个,多个的话也一样;
    FETCH groupCursor INTO  row_track_Id,row_cus_id;
    -- 声明结束的时候
    IF done THEN
      LEAVE read_loop;
    END IF;
     
  update t_ct_customer set track_id = row_track_Id where id = row_cus_id;


  END LOOP;


end
MySQL中,存储过程(Stored Procedure)可以通过循环结构(如`WHILE`、`REPEAT`、`LOOP`)实现重复操作,例如批量插入数据、遍历结果集或处理复杂逻辑。以下是详细说明和示例: --- ### **1. 循环类型及语法** #### **(1) WHILE循环** ```sql WHILE condition DO -- 循环体 END WHILE; ``` #### **(2) REPEAT循环** ```sql REPEAT -- 循环体 UNTIL condition -- 满足条件时退出 END REPEAT; ``` #### **(3) LOOP循环(需手动退出)** ```sql my_loop: LOOP -- 循环IF condition THEN LEAVE my_loop; -- 退出循环 END IF; END LOOP my_loop; ``` --- ### **2. 存储过程循环示例** #### **示例1:WHILE循环插入数据** ```sql DELIMITER // CREATE PROCEDURE insert_sample_data(IN num_rows INT) BEGIN DECLARE i INT DEFAULT 1; WHILE i <= num_rows DO INSERT INTO my_table (id, name, created_at) VALUES (i, CONCAT('Name_', i), NOW()); SET i = i + 1; END WHILE; END // DELIMITER ; -- 调用存储过程 CALL insert_sample_data(100); ``` #### **示例2:REPEAT循环处理日期范围** ```sql DELIMITER // CREATE PROCEDURE process_date_range(IN start_date DATE, IN end_date DATE) BEGIN DECLARE current_date DATE; SET current_date = start_date; REPEAT -- 处理当前日期(例如插入到日志表) INSERT INTO date_logs (log_date, status) VALUES (current_date, 'Processed'); -- 日期递增 SET current_date = DATE_ADD(current_date, INTERVAL 1 DAY); UNTIL current_date > end_date END REPEAT; END // DELIMITER ; -- 调用存储过程 CALL process_date_range('2023-01-01', '2023-01-31'); ``` #### **示例3:LOOP循环遍历游标** ```sql DELIMITER // CREATE PROCEDURE update_user_status() BEGIN DECLARE done INT DEFAULT FALSE; DECLARE user_id INT; DECLARE cur CURSOR FOR SELECT id FROM users WHERE last_login < DATE_SUB(NOW(), INTERVAL 1 YEAR); DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE; OPEN cur; my_loop: LOOP FETCH cur INTO user_id; IF done THEN LEAVE my_loop; END IF; -- 更新用户状态 UPDATE users SET status = 'inactive' WHERE id = user_id; END LOOP; CLOSE cur; END // DELIMITER ; -- 调用存储过程 CALL update_user_status(); ``` --- ### **3. 循环优化与注意事项** #### **(1) 性能优化** - **批量操作**:尽量减少循环内的单条操作,改用批量插入(如`INSERT INTO ... SELECT`)。 - **事务控制**:大循环中分批提交事务,避免锁表时间过长: ```sql DECLARE batch_size INT DEFAULT 1000; DECLARE counter INT DEFAULT 0; START TRANSACTION; WHILE i <= num_rows DO -- 插入数据... SET counter = counter + 1; IF counter % batch_size = 0 THEN COMMIT; START TRANSACTION; END IF; END WHILE; COMMIT; ``` #### **(2) 避免无限循环** - 确保循环条件最终会变为`FALSE`,或通过`LEAVE`主动退出。 - 设置最大迭代次数限制: ```sql DECLARE max_iterations INT DEFAULT 10000; DECLARE i INT DEFAULT 0; WHILE i < max_iterations AND condition DO -- 逻辑... SET i = i + 1; END WHILE; ``` #### **(3) 错误处理** - 使用`DECLARE CONTINUE HANDLER`捕获异常: ```sql DECLARE CONTINUE HANDLER FOR SQLEXCEPTION BEGIN GET DIAGNOSTICS CONDITION 1 @sqlstate = RETURNED_SQLSTATE, @errno = MYSQL_ERRNO, @text = MESSAGE_TEXT; INSERT INTO error_logs VALUES (NOW(), @errno, @text); END; ``` --- ### **4. 常见问题解答** #### **Q1: 如何在循环中动态生成SQL并执行?** 使用预处理语句(`PREPARE` + `EXECUTE`): ```sql DELIMITER // CREATE PROCEDURE dynamic_sql_loop() BEGIN DECLARE i INT DEFAULT 1; DECLARE sql_text TEXT; WHILE i <= 10 DO SET sql_text = CONCAT('INSERT INTO table_', i, ' VALUES (', i, ')'); SET @sql = sql_text; PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt; SET i = i + 1; END WHILE; END // DELIMITER ; ``` #### **Q2: 循环中如何跳过某些迭代?** 使用`ITERATE`(类似`continue`): ```sql my_loop: LOOP IF i % 2 = 0 THEN SET i = i + 1; ITERATE my_loop; -- 跳过偶数 END IF; -- 处理奇数... END LOOP; ``` #### **Q3: 存储过程循环能否返回结果集?** 可以,通过临时表或游标返回: ```sql DELIMITER // CREATE PROCEDURE get_even_numbers(IN max_num INT) BEGIN DECLARE i INT DEFAULT 0; DROP TEMPORARY TABLE IF EXISTS temp_result; CREATE TEMPORARY TABLE temp_result (num INT); WHILE i <= max_num DO IF i % 2 = 0 THEN INSERT INTO temp_result VALUES (i); END IF; SET i = i + 1; END WHILE; SELECT * FROM temp_result; END // DELIMITER ; ``` --- ### **5. 总结** - **适用场景**:批量数据操作、复杂业务逻辑、定时任务(结合Event)。 - **替代方案**:MySQL 8.0+优先使用递归CTE或窗口函数替代部分循环逻辑。 - **调试技巧**:通过`SELECT`或临时表输出中间结果,或使用`SHOW PROCEDURE STATUS`查看存储过程信息。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值