mysql 使用 游标进行批量刷新

本文介绍了一个使用MySQL存储过程批量更新用户表中部门ID的过程。该过程通过读取OA_org_update_info表中的数据,并根据不同的业务部门层级(如交付部、事业部等)来更新USER表中的部门信息。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

drop procedure if exists UpdateUserOrg; 
CREATE PROCEDURE UpdateUserOrg()  
BEGIN  
    -- 创建接收游标数据的变量  
    declare v_lob_number varchar(20);
    declare v_lob_group varchar(20);
    declare v_lob varchar(20);
    declare v_budu varchar(20);
    declare v_dd varchar(20);
  --
 
    declare total int default 0;     -- 创建总数变量  
 
    declare done int default false;     -- 创建结束标志变量  

    -- 创建游标  
    declare cur cursor for select lob_number,lob_group,lob,budu,dd from OA_org_update_info;  
   


 
    declare continue HANDLER for not found set done = true;     -- 指定游标循环结束时的返回值 
   
    set total = 0;    -- 设置初始值 
    
    open cur;    -- 打开游标
   
    read_loop:loop    -- 开始循环游标里的数据 
   
    fetch cur into v_lob_number,v_lob_group,v_lob,v_budu,v_dd;   -- 根据游标当前指向的一条数据  
 
    if done then     -- 判断游标的循环是否结束  
        leave read_loop;     -- 跳出游标循环  
    end if;  
    -- 获取一条数据时,将count值进行累加操作,这里可以做任意你想做的操作,
    IF v_dd is not null and v_dd!=''        //dd交付部设置
    THEN  
        UPDATE `USER` SET dept_id =ifnull((  //根据交付部
      SELECT dept_id FROM DEPARTMENT
      WHERE dept_parent IN (
    SELECT dept_id FROM DEPARTMENT WHERE dept_name LIKE CONCAT("%",ifnull(v_budu,''),"%"))
      AND dept_name LIKE CONCAT("%",ifnull(v_dd,''),"%")
       ),0)
       WHERE
      remark=v_lob_number;  
  
    ELSEIF v_budu is not null and v_budu!=''  //budu事业部设置
    THEN  
        UPDATE `USER` SET dept_id = ifnull((
      SELECT dept_id FROM DEPARTMENT
      WHERE dept_parent IN (
    SELECT dept_id FROM DEPARTMENT WHERE dept_name LIKE CONCAT("%",ifnull(v_lob,''),"%"))
      AND dept_name LIKE CONCAT("%",ifnull(v_budu,''),"%")
       ),0)
       WHERE
      remark=v_lob_number;   
  
    ELSEIF v_lob is not null and v_lob!='' //lob业务线设置
    THEN  
        UPDATE `USER` SET dept_id = ifnull((
      SELECT dept_id FROM DEPARTMENT
      WHERE dept_parent IN (
    SELECT dept_id FROM DEPARTMENT WHERE dept_name LIKE CONCAT("%",ifnull(v_lob_group,''),"%"))
      AND dept_name LIKE CONCAT("%",ifnull(v_lob,''),"%")
       ),0)
       WHERE
      remark=v_lob_number; 
  
    ELSE                                   //lob_group业务群设置
       UPDATE `USER` SET dept_id = ifnull((   
      SELECT dept_id FROM DEPARTMENT
      WHERE  dept_name LIKE CONCAT("%",ifnull(v_lob_group,''),"%")
       ),0)
       WHERE
      remark=v_lob_number; 


    END IF;
    set total = total + 1;  -- 结束游标循环 
     
    end loop;  -- 关闭游标 
     
    close cur;  
   -- 输出不成功结果,分析为什么DEPT_ID为0,一般为OA_org_update_info部门信息有误 
  select lob_number,lob_group,lob,budu,dd from OA_org_update_info where lob_number in (
     select user_id from USER where substr(USER_id,2,length(user_id)-1) in (
        select lob_number from OA_org_update_info
     )
        and dept_id='0'
  );


  select total;
END;
call UpdateUserOrg();
drop procedure UpdateUserOrg
public void testSimpleImportBuilder(){ DB2ESImportBuilder importBuilder = DB2ESImportBuilder.newInstance(); try { //清除测试表据 ElasticSearchHelper.getRestClientUtil().dropIndice("dbclobdemo"); } catch (Exception e){ } //据源相关配置,可选项,可以在外部启动据源 importBuilder.setDbName("test") .setDbDriver("com.mysql.jdbc.Driver") //据库驱动程序,必须导入相关据库的驱动jar包 .setDbUrl("jdbc:mysql://localhost:3306/bboss?useCursorFetch=true") //通过useCursorFetch=true启用mysql游标fetch机制,否则会有严重的性能隐患,useCursorFetch必须和jdbcFetchSize参配合使用,否则不会生效 .setDbUser("root") .setDbPassword("123456") .setValidateSQL("select 1") .setUsePool(false);//是否使用连接池 //指定导入据的sql语句,必填项,可以设置自己的提取逻辑 importBuilder.setSql("select * from td_cms_document"); /** * es相关配置 */ importBuilder .setIndex("dbclobdemo") //必填项 .setIndexType("dbclobdemo") //必填项 .setRefreshOption(null)//可选项,null表示不实时刷新,importBuilder.setRefreshOption("refresh");表示实时刷新 .setUseJavaName(true) //可选项,将据库字段名称转换为java驼峰规范的名称,例如:doc_id -> docId .setBatchSize(5000) //可选项,批量导入es的记录,默认为-1,逐条处理,> 0时批量处理 .setJdbcFetchSize(10000);//设置据库的查询fetchsize,同时在mysql url上设置useCursorFetch=true启用mysql游标fetch机制,否则会有严重的性能隐患,jdbcFetchSize必须和useCursorFetch参配合使用,否则不会生效 /** * 执行据库表据导入es操作 */ DataStream dataStream = importBuilder.builder(); dataStream.execute(); }
07-23
<think>我们正在讨论MySQL中基于游标的分页查询。基于游标的分页(也称为键集分页)是一种高效的分页技术,特别适用于大据集和深度分页的场景。它通过记住上一页最后一项的位置(即游标)来获取下一页的据,避免了传统分页(如LIMIToffset,size)在深度分页时的性能问题。在基于游标的分页中,我们通常使用一个或多个有序列(如时间戳、ID等)作为游标。假设我们有一个表`orders`,其中包含`id`(主键)、`order_date`(订单日期)和`amount`(订单金额)等列。我们想要按订单日期(降序)和ID(升序)进行分页。步骤:1.确定游标列:通常选择唯一且有序的列,例如主键。如果主键不能完全满足排序需求,可能需要组合多个列(例如,订单日期和ID)。2.在查询中,我们使用WHERE条件来指定从游标之后(或之前,取决于排序方向)开始获取据。3.使用ORDERBY确保顺序一致。示例:假设我们想要按`order_dateDESC,idASC`排序,每页10条记录。第一页查询(没有游标):```sqlSELECTid,order_date,amountFROMordersORDERBYorder_dateDESC,idASCLIMIT10;```假设第一页的最后一条记录的`order_date`为'2023-10-1012:00:00',`id`为100。那么第二页的查询应该从这条记录之后开始。第二页查询:```sqlSELECTid,order_date,amountFROMordersWHERE(order_date<'2023-10-1012:00:00')OR(order_date='2023-10-1012:00:00'ANDid>100)ORDERBYorder_dateDESC,idASCLIMIT10;```解释:-由于我们是按`order_date`降序排列,所以下一页的订单日期应该小于上一页最后一条的订单日期(因为日期越早越小)。-或者,当订单日期相等时,我们要求ID大于上一页最后一条的ID(因为我们按ID升序,所以下一页的ID应该更大)。注意:在构建条件时,需要根据排序方向调整不等号的方向。如果排序是升序(ASC),则下一页的条件应该是大于(>);如果是降序(DESC),则条件应该是小于(<)。在MySQL中,我们可以使用多个条件组合来处理多列游标。另外,基于游标的分页通常需要客户端传递上一页最后一条记录的游标值(即排序字段的值)。因此,在返回每一页据时,需要将最后一行的游标值返回给客户端,以便客户端请求下一页时提供。关于性能:为了确保查询效率,我们需要在排序字段上建立合适的索引。例如,对于上面的查询,可以创建索引:`(order_dateDESC,idASC)`。现在,根据要求生成相关问题。</think>### MySQL 游标分页查询实现 在 MySQL 中,基于游标的分页(Cursor-based Pagination)通过**记录位置标识**而非传统 `LIMIT offset` 实现高效分页,特别适合大据量场景。核心原理是利用有序列的唯一值作为定位点[^1]。 #### 基础实现示例 假设有订单表 `orders`,按创建时间分页: ```sql -- 第一页(无游标) SELECT order_id, created_at, amount FROM orders WHERE created_at >= '2023-01-01' ORDER BY created_at ASC, order_id ASC -- 必须包含唯一列保证顺序 LIMIT 10; -- 下一页(使用上一页最后一条记录的游标值) SELECT order_id, created_at, amount FROM orders WHERE created_at > '2023-05-20 14:30:00' -- 上一页最后记录的 created_at OR (created_at = '2023-05-20 14:30:00' AND order_id > 10025) -- 处理相同时间点 ORDER BY created_at ASC, order_id ASC LIMIT 10; ``` #### 多列游标分页[^2] 当需要多列排序时(如按金额+时间): ```sql SELECT order_id, created_at, amount FROM orders WHERE (amount, created_at, order_id) > (50.00, '2023-05-20', 10025) -- 元组比较 ORDER BY amount DESC, created_at ASC, order_id ASC LIMIT 10; ``` #### 关键要点 1. **排序要求** - 必须包含至少一个唯一列(如主键)作为最终排序条件 - 排序顺序需与 WHERE 条件中的比较方向一致 2. **性能优势** ```mermaid graph LR A[传统分页] -->|深分页扫描| B(offset+N行) C[游标分页] -->|索引定位| D(直接目标位置) ``` 3. **索引优化** 需为所有排序字段创建复合索引: ```sql CREATE INDEX idx_pagination ON orders (amount DESC, created_at ASC, order_id ASC); ``` #### ORM 实现参考 在 ORM 中(如 Django),可通过封装查询条件实现: ```python # 伪代码示例 def get_next_page(last_record): return Orders.objects.filter( Q(amount__lt=last_record.amount) | Q(amount=last_record.amount, created_at__gt=last_record.created_at) | Q(amount=last_record.amount, created_at=last_record.created_at, id__gt=last_record.id) ).order_by('-amount', 'created_at', 'id')[:10] ``` [^3] ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值