独悲十八爷吧 关注:10贴子:469
  • 8回复贴,共1

【大数据】在千万级数据量下的数据统计存储过程编写

只看楼主收藏回复

说明:
本帖不考虑服务器性能,只是基于SQL语句做讲解;
前提:
数据库环境:Gbase数据库(基于mysql二次开发);
数据库表数据量:2000+万;
SQL性能目标:
有条件下:日期按月统计实现8-15秒;
无条件下(全表统计):实现25-30秒以内;


IP属地:北京1楼2019-12-04 17:35回复
    【编写要义】
    1、存储过程的编写,需要进行完整的规划,以达到对运行过程可控、运行结果可控、运行异常可控、运行效率可控;
    2、存储过程通常配合定时器的方式调用;
    【概念说明】
    过程:封装了若干条语句,调用时,这些封装体执行;
    函数:是一个有返回值的“过程”;
    总结:过程是一个没有返回值的函数,自定义函数只能返回一个值(一行一列);
    【存储过程基本操作】
    1、编写
    示例一:无参存储过程
    create procedure p1()
    begin select 2+3;
    end
    执行结果:

    示例二:有参存储过程:
    主要有 输入参数IN、输出参数OUT、输入输出参数INOUT 三种类型
    create procedure p2(IN pram1 VARCHAR(5),OUT pram2 INT,INOUT pram3 INT)
    begin-- 定义内部变量,生命周期是运行存储过程时有效。
    DECLARE pram4 INT DEFAULT 0;
    -- 定义内部整型变量pram4 并初始化为0-- 使用查询方式给变量赋值
    SELECT 2+3 INTO pram4;
    -- 使用查询赋值方式给变量赋值
    SELECT LENGTH(pram1) INTO pram2;
    -- 使用set方式给变量赋值
    SET pram3=pram4+pram3;
    end
    执行结果:

    2、查看存储过程
    show procedure status;
    3、删除存储过程:
    drop procedure 存储过程名称;


    IP属地:北京2楼2019-12-04 17:40
    回复
      【实战存储过程】
      流程图

      编写存储过程,需要考虑
      (一)SQL的执行性能
      1、对千万级别以上的数据表进行分组统计时,为了快速得出最终的统计结果,需要分阶段统计。
      先使用临时表存储最基本统计数据记录,然后通过统计临时表的数据,得出最终结果。这样,
      避免对大表频繁的读取,提升统计效率;
      2、把数据从临时表使用游标写入统计表时,需使用批量提交的方式进行。即先根据主键批量删除数据,然后对字符串
      进行拼接SQL,然后执行大批量写入SQL,最终的数据入库速度则得到显著提升。
      (二)存储过程的监控
      1、为了能够对存储过程进行监控,必须有存储过程运行错误日志表、存储过程运行结果记录表。
      编写存储过程之前的准备
      (一)游标
      把存储过程的数据保存在临时表后,我们需要游标进行从上往下遍历读取数据,把数据写入统计表中。
      游标使用示例(对游标的使用流程大概了解):
      delimiter //
      drop procedure if exists StatisticStore;
      CREATE PROCEDURE StatisticStore()
      BEGIN
      --创建接收游标数据的变量
      declare c int;
      declare n varchar(20);
      --创建总数变量
      declare total int default 0;
      --创建结束标志变量
      declare done int default false;
      --创建游标
      declare cur cursor for select name,count from store where name = 'iphone';
      --指定游标循环结束时的返回值
      declare continue HANDLER for not found set done = true;
      --设置初始值
      set total = 0;
      --打开游标
      open cur;
      --开始循环游标里的数据
      read_loop:loop
      --根据游标当前指向的一条数据
      fetch cur into n,c;
      --判断游标的循环是否结束
      if done then
      leave read_loop; --跳出游标循环
      end if;
      --获取一条数据时,将count值进行累加操作,这里可以做任意你想做的操作,
      set total = total + c;
      --结束游标循环
      end loop;
      --关闭游标
      close cur;
      --输出结果
      select total;
      END;
      --调用存储过程
      call StatisticStore();


      IP属地:北京3楼2019-12-04 17:43
      回复
        【实战例子】
        1、编写生成临时基础统计数据表
        /*
        1、功能:根据表A 表B, 统计得出 tmp_table_79_80_81
        2、编写人:CZQ
        3、编写/更新时间:2019年7月29日00:22:57
        */
        DROP PROCEDURE IF EXISTS P_tmptable;
        CREATE PROCEDURE "P_tmptable"( in countdatetime VARCHAR(6),in xmid VARCHAR(6))
        BEGIN
        -- 设置异常信息变量
        DECLARE ERROR_CODE CHAR(5) DEFAULT '00000';
        DECLARE ERROR_MSG TEXT;
        DECLARE ERROR_PROCEDURE_INFO TEXT;
        -- 声明异常处理
        DECLARE CONTINUE HANDLER FOR SQLEXCEPTION
        BEGIN
        -- 捕获异常信息
        GET DIAGNOSTICS CONDITION 1 ERROR_CODE=RETURNED_SQLSTATE,ERROR_MSG=MESSAGE_TEXT;
        SET ERROR_PROCEDURE_INFO=CONCAT('{"PROCEDURE_NAME":','"P_tmptable",'
        ,'"countdatetime":"',countdatetime,',"xmid":"',xmid,'"}');
        -- 把异常捕获,并写入错误日志表中
        INSERT INTO
        t_procedure_error_log(error_code,error_msg,error_procedure_info,error_create_time)
        VALUES(ERROR_CODE,ERROR_MSG,ERROR_PROCEDURE_INFO,DATE_FORMAT(NOW(),'%Y-%m-%d %H:%i:%s'));
        END;
        /*
        开始统计
        */
        -- *****建立临时表-开始***** 把所要查询的最大范围的记录查询出来,做临时表
        DROP TEMPORARY TABLE IF EXISTS tmp_table_79_80_81;-- 判断是否存在该临时表
        CREATE TEMPORARY TABLE tmp_table_79_80_81 -- 把查询出来的最大范围的数据 并存到临时表
        SELECT
        t3.pcsdm AS bmid,
        STR_TO_DATE(CONCAT(DATE_FORMAT(t3.FASJKS,'%Y%m'),'01'),'%Y%m%d') AS tjsj,
        COUNT(*) AS tjsl
        FROM(
        SELECT
        FASJKS,
        CASE
        WHEN LOCATE('FR',t2.qc)>0 THEN '43***00'
        WHEN LOCATE('TX',t2.qc)>0 THEN '43***00'
        WHEN LOCATE('YM',t2.qc)>0 THEN '43***00'
        WHEN LOCATE('KF',t2.qc)>0 THEN '43***00'
        WHEN LOCATE('YH',t2.qc)>0 THEN '43***00'
        WHEN LOCATE('WC',t2.qc)>0 THEN '43***00'
        WHEN LOCATE('CSX',t2.qc)>0 THEN '43***00'
        WHEN LOCATE('NX',t2.qc)>0 THEN '430***00'
        WHEN LOCATE('LY',t2.qc)>0 THEN '430***00'
        WHEN LOCATE('GX',t2.qc)>0 THEN '430***00'
        ELSE
        '43***00' -- 如果名称为null 则统计到SJ
        END
        AS pcsdm
        FROM
        (
        SELECT
        FASQdm,
        FASJKS
        FROM
        表A
        WHERE
        FASJKS IS NOT NULL
        AND
        CASE
        WHEN xmid='79' THEN LOCATE('SR',mc)>0 OR LOCATE('QJ1',mc)>0
        OR LOCATE('QJ2',mc)>0 OR LOCATE('BJ',mc)>0
        WHEN xmid='80' THEN 1=2
        WHEN xmid='81' THEN 1=1
        ELSE
        1=2
        END
        AND
        -- 判断统计范围
        CASE WHEN countdatetime<>'0' THEN
        DATE_FORMAT(FASJKS,'%Y')>=YEAR(SUBDATE(STR_TO_DATE(CONCAT(countdatetime,'01'),'%Y%m%d'),INTERVAL 1 YEAR))
        AND DATE_FORMAT(FASJKS,'%Y%m')<= countdatetime
        ELSE 1=1 END
        )t1
        LEFT JOIN
        (
        SELECT dm,qc FROM 表B
        )t2
        ON t1.FASQdm=t2.dm
        )t3
        GROUP BY
        t3.pcsdm ,
        DATE_FORMAT(t3.FASJKS,'%Y%m')
        ;
        END


        IP属地:北京4楼2019-12-04 17:44
        回复
          /*
          1、功能:根据临时表 tmp_table_79_80_81 统计得出 SQSLXSFA绝对数、SQTDCSFA绝对数、SQFA总数
          2、编写人:CZQ
          3、编写/更新时间:2019年7月29日00:27:15
          */
          DROP PROCEDURE IF EXISTS P_79_80_81_count;
          CREATE PROCEDURE "P_79_80_81_count"(IN countdatetime VARCHAR(6),in xmid VARCHAR(6),IN update_insert_num INT,OUT count_num INT,OUT error_num INT)
          BEGIN
          DECLARE temp_id varchar(32);-- 变量'主键',
          DECLARE temp_lbid varchar(5);-- 变量 '类别id',
          DECLARE temp_lb varchar(255);-- 变量 '类别',
          DECLARE temp_xmid varchar(5);-- 变量 '项目id',
          DECLARE temp_xm varchar(255);-- 变量 '项目',
          DECLARE temp_xmxlid varchar(5);-- 变量 '项目小类id',
          DECLARE temp_xmxl varchar(255);-- 变量 '项目小类',
          DECLARE temp_tjyf varchar(7);-- 变量 '统计月份',
          DECLARE temp_ssqxdm varchar(255);-- 变量 '所属QX代码',
          DECLARE temp_ssqxmc varchar(255);-- 变量 '所属QX名称',
          DECLARE temp_tjsl int(20);-- 变量 '统计数量',
          DECLARE temp_qntytjsl int(20);-- 变量 '去年同月统计数量',
          DECLARE temp_jnlj int(20);-- 变量 '今年累计数量',
          DECLARE temp_qnlj int(20);-- 变量 '去年累计数量',
          DECLARE temp_qnqntj int(20);-- 变量 '去年全年统计数量',
          DECLARE temp_lydwdm varchar(255);-- 变量 '数据来源单位代码',
          DECLARE temp_lydwmc varchar(255);-- 变量 '数据来源单位名称'
          DECLARE temp_time varchar(20);-- 变量 '数据来源单位名称'
          DECLARE cur_account_finished INTEGER DEFAULT 0;-- 定义游标遍历数据结束的标志 1 遍历结束 ;0 没有结束
          -- 批量参数设置
          DECLARE temp_detele_idstr LONGTEXT DEFAULT '';-- 拼接id字符串
          DECLARE temp_insert_str LONGTEXT DEFAULT '';-- 批量更新字符串
          DECLARE temp_update_insert_count INT DEFAULT 1; -- 计数初始化
          DECLARE tj_count INT DEFAULT 0;-- 统计表是否存在记录
          -- 设置异常信息变量
          DECLARE ERROR_CODE CHAR(5) DEFAULT '00000';
          DECLARE ERROR_MSG TEXT;
          DECLARE ERROR_PROCEDURE_INFO TEXT;
          -- 设置错误统计数
          DECLARE tmp_error_num INT DEFAULT 0;
          /*
          开始统计
          */
          -- 根据临时表的内容进行查询*****查询统计数据并赋值给游标
          DECLARE cur_account CURSOR FOR
          SELECT
          DISTINCT tall.id,
          tall.tjyf,
          tall.ssqxdm,
          tall.tjsl,
          tall.qntytjsl,
          tall.jnlj,
          tall.qnlj,
          tall.qnqntj,
          tacl.ssqxmc,
          tacl.lydwdm,
          tacl.lydwmc,
          '018' AS lbid,
          'GFASQ数据' AS lb,
          xmid AS xmid,
          CASE
          WHEN xmid='79' THEN 'SQSLXSFA绝对数'
          WHEN xmid='80' THEN 'SQTDXSFA绝对数'
          WHEN xmid='81' THEN 'SQFA总数'
          ELSE NULL
          END AS xm,
          NULL AS xmxlid,
          NULL AS xmxl
          FROM(
          -- 开始查询PCSJB数据
          SELECT
          CONCAT(DATE_FORMAT(t_pcs.tjsj,'%Y%m'),t_pcs.bmid,'018',xmid,'000') AS id,-- 主键id
          t_pcs.bmid AS ssqxdm, -- id
          DATE_FORMAT(t_pcs.tjsj,'%Y-%m') AS tjyf,
          t_pcs.tjsl AS tjsl, -- 当前月份的统计数量
          ( -- 统计去年同月数量
          SELECT
          SUM(CASE WHEN t_qntytjsl.tjsl IS NULL THEN 0 ELSE t_qntytjsl.tjsl END)
          FROM
          tmp_table_79_80_81 t_qntytjsl
          WHERE
          t_qntytjsl.bmid=t_pcs.bmid -- 查询当前部门id记录
          AND t_qntytjsl.tjsj= SUBDATE(t_pcs.tjsj,INTERVAL 1 YEAR)
          )AS qntytjsl,
          (-- 统计今年累计数量
          SELECT
          SUM( CASE WHEN t_jnlj.tjsl IS NULL THEN 0 ELSE t_jnlj.tjsl END )
          FROM
          tmp_table_79_80_81 t_jnlj
          WHERE
          t_jnlj.bmid=t_pcs.bmid -- 查询当前部门id记录
          AND t_jnlj.tjsj >= STR_TO_DATE(CONCAT(YEAR(t_pcs.tjsj),'-01-01'),'%Y-%m-%d')
          AND t_jnlj.tjsj <=t_pcs.tjsj
          )AS jnlj,
          (-- 统计去年累计数量
          SELECT
          SUM( CASE WHEN t_qnlj.tjsl IS NULL THEN 0 ELSE t_qnlj.tjsl END )
          FROM
          tmp_table_79_80_81 t_qnlj
          WHERE
          t_qnlj.bmid=t_pcs.bmid -- 查询当前部门id记录
          AND t_qnlj.tjsj >= STR_TO_DATE(CONCAT(YEAR(SUBDATE(t_pcs.tjsj,INTERVAL 1 YEAR)),'-01-01'),'%Y-%m-%d')
          AND t_qnlj.tjsj <= SUBDATE(t_pcs.tjsj,INTERVAL 1 YEAR)
          )AS qnlj,
          (-- 统计去年全年累计
          SELECT
          SUM( CASE WHEN t_qnqntj.tjsl IS NULL THEN 0 ELSE t_qnqntj.tjsl END )
          FROM
          tmp_table_79_80_81 t_qnqntj
          WHERE
          t_qnqntj.bmid=t_pcs.bmid -- 查询当前部门id记录
          AND t_qnqntj.tjsj >= STR_TO_DATE(CONCAT(YEAR(SUBDATE(t_pcs.tjsj,INTERVAL 1 YEAR)),'-01-01'),'%Y-%m-%d')
          AND t_qnqntj.tjsj <= STR_TO_DATE(CONCAT(YEAR(SUBDATE(t_pcs.tjsj,INTERVAL 1 YEAR)),'-12-01'),'%Y-%m-%d')
          )AS qnqntj
          FROM
          tmp_table_79_80_81 t_pcs
          WHERE
          CASE WHEN countdatetime='0' -- 根据传入的参数进行判断统计时间范围
          THEN 1=1
          ELSE
          DATE_FORMAT(t_pcs.tjsj,'%Y%m')=countdatetime
          END
          AND t_pcs.bmid NOT IN( -- 把PCSid筛选出来
          SELECT id
          FROM gb_ztfx.t_acl_org
          WHERE org_level in (1,2,3)
          )
          UNION ALL
          -- 开始查询FJ数据
          SELECT
          CONCAT(DATE_FORMAT(t_fj.tjsj,'%Y%m'),
          CASE WHEN t_fj.bmid LIKE '43****%' THEN CONCAT(t_fj.bmid,'0000') ELSE CONCAT(t_fj.bmid,'000000') END
          ,'018',xmid,'000') AS id,-- 主键id
          CASE WHEN t_fj.bmid LIKE '43****%' THEN CONCAT(t_fj.bmid,'0000') ELSE CONCAT(t_fj.bmid,'000000') END
          AS ssqxdm,
          DATE_FORMAT(t_fj.tjsj,'%Y-%m') AS tjyf,
          ( -- 当前月份的统计数量
          SELECT
          SUM(CASE WHEN t_tjsl.tjsl IS NULL THEN 0 ELSE t_tjsl.tjsl END)
          FROM
          tmp_table_79_80_81 t_tjsl
          WHERE
          t_tjsl.bmid LIKE CONCAT(t_fj.bmid,'%') -- 查询当前部门id记录
          AND t_tjsl.tjsj= t_fj.tjsj
          )AS tjsl,
          ( -- 统计去年同月数量
          SELECT
          SUM(CASE WHEN t_qntytjsl.tjsl IS NULL THEN 0 ELSE t_qntytjsl.tjsl END)
          FROM
          tmp_table_79_80_81 t_qntytjsl
          WHERE
          t_qntytjsl.bmid LIKE CONCAT(t_fj.bmid,'%') -- 查询当前部门id记录
          AND t_qntytjsl.tjsj= SUBDATE(t_fj.tjsj,INTERVAL 1 YEAR)
          )AS qntytjsl,
          (-- 统计今年累计数量
          SELECT
          SUM( CASE WHEN t_jnlj.tjsl IS NULL THEN 0 ELSE t_jnlj.tjsl END )
          FROM
          tmp_table_79_80_81 t_jnlj
          WHERE
          t_jnlj.bmid LIKE CONCAT(t_fj.bmid,'%') -- 查询当前部门id记录
          AND t_jnlj.tjsj >= STR_TO_DATE(CONCAT(YEAR(t_fj.tjsj),'-01-01'),'%Y-%m-%d')
          AND t_jnlj.tjsj <=t_fj.tjsj
          )AS jnlj,
          (-- 统计去年累计数量
          SELECT
          SUM( CASE WHEN t_qnlj.tjsl IS NULL THEN 0 ELSE t_qnlj.tjsl END )
          FROM
          tmp_table_79_80_81 t_qnlj
          WHERE
          t_qnlj.bmid LIKE CONCAT(t_fj.bmid,'%') -- 查询当前部门id记录
          AND t_qnlj.tjsj >= STR_TO_DATE(CONCAT(YEAR(SUBDATE(t_fj.tjsj,INTERVAL 1 YEAR)),'-01-01'),'%Y-%m-%d')
          AND t_qnlj.tjsj <= SUBDATE(t_fj.tjsj,INTERVAL 1 YEAR)
          )AS qnlj,
          (-- 统计去年全年累计
          SELECT
          SUM( CASE WHEN t_qnqntj.tjsl IS NULL THEN 0 ELSE t_qnqntj.tjsl END )
          FROM
          tmp_table_79_80_81 t_qnqntj
          WHERE
          t_qnqntj.bmid LIKE CONCAT(t_fj.bmid,'%')-- 查询当前部门id记录
          AND t_qnqntj.tjsj >= STR_TO_DATE(CONCAT(YEAR(SUBDATE(t_fj.tjsj,INTERVAL 1 YEAR)),'-01-01'),'%Y-%m-%d')
          AND t_qnqntj.tjsj <= STR_TO_DATE(CONCAT(YEAR(SUBDATE(t_fj.tjsj,INTERVAL 1 YEAR)),'-12-01'),'%Y-%m-%d')
          )AS qnqntj
          FROM
          (
          SELECT
          CASE WHEN LEFT(fj.bmid,6)='430100' THEN LEFT(fj.bmid,8) ELSE LEFT(fj.bmid,6) END AS bmid,
          fj.tjsj,
          fj.tjsl
          FROM
          tmp_table_79_80_81 fj
          WHERE
          CASE WHEN countdatetime='0' -- 根据传入的参数进行判断统计时间范围
          THEN 1=1
          ELSE
          DATE_FORMAT(fj.tjsj,'%Y%m')=countdatetime
          END
          AND fj.bmid <>'43XXXXXXXX00'
          GROUP BY
          CASE WHEN LEFT(fj.bmid,6)='430100' THEN LEFT(fj.bmid,8) ELSE LEFT(fj.bmid,6) END
          ,fj.tjsj,
          fj.tjsl
          )t_fj
          UNION ALL


          IP属地:北京5楼2019-12-04 17:47
          回复
            (续)
            -- 统计SJ级别的数量
            SELECT
            CONCAT(DATE_FORMAT(t_sj.tjsj,'%Y%m'),'43XXXXXXXX00','018',xmid,'000') AS id,-- 部门id
            '43XXXXXXXX00' AS ssqxdm,
            DATE_FORMAT(t_sj.tjsj,'%Y-%m') AS tjyf,
            ( -- 当前月份的统计数量
            SELECT
            SUM(CASE WHEN t_tjsl.tjsl IS NULL THEN 0 ELSE t_tjsl.tjsl END)
            FROM
            tmp_table_79_80_81 t_tjsl
            WHERE
            t_tjsl.tjsj= t_sj.tjsj
            )AS tjsl,
            ( -- 统计去年同月数量
            SELECT
            SUM(CASE WHEN t_qntytjsl.tjsl IS NULL THEN 0 ELSE t_qntytjsl.tjsl END)
            FROM
            tmp_table_79_80_81 t_qntytjsl
            WHERE
            t_qntytjsl.tjsj= SUBDATE(t_sj.tjsj,INTERVAL 1 YEAR)
            )AS qntytjsl,
            (-- 统计今年累计数量
            SELECT
            SUM( CASE WHEN t_jnlj.tjsl IS NULL THEN 0 ELSE t_jnlj.tjsl END )
            FROM
            tmp_table_79_80_81 t_jnlj
            WHERE
            t_jnlj.tjsj >= STR_TO_DATE(CONCAT(YEAR(t_sj.tjsj),'-01-01'),'%Y-%m-%d')
            AND t_jnlj.tjsj <=t_sj.tjsj
            )AS jnlj,
            (-- 统计去年累计数量
            SELECT
            SUM( CASE WHEN t_qnlj.tjsl IS NULL THEN 0 ELSE t_qnlj.tjsl END )
            FROM
            tmp_table_79_80_81 t_qnlj
            WHERE
            t_qnlj.tjsj >= STR_TO_DATE(CONCAT(YEAR(SUBDATE(t_sj.tjsj,INTERVAL 1 YEAR)),'-01-01'),'%Y-%m-%d')
            AND t_qnlj.tjsj <= SUBDATE(t_sj.tjsj,INTERVAL 1 YEAR)
            )AS qnlj,
            (-- 统计去年全年累计
            SELECT
            SUM( CASE WHEN t_qnqntj.tjsl IS NULL THEN 0 ELSE t_qnqntj.tjsl END )
            FROM
            tmp_table_79_80_81 t_qnqntj
            WHERE
            t_qnqntj.tjsj >= STR_TO_DATE(CONCAT(YEAR(SUBDATE(t_sj.tjsj,INTERVAL 1 YEAR)),'-01-01'),'%Y-%m-%d')
            AND t_qnqntj.tjsj <= STR_TO_DATE(CONCAT(YEAR(SUBDATE(t_sj.tjsj,INTERVAL 1 YEAR)),'-12-01'),'%Y-%m-%d')
            )AS qnqntj
            FROM
            (
            SELECT
            sj.tjsj
            FROM
            tmp_table_79_80_81 sj
            WHERE
            CASE WHEN countdatetime='0' -- 根据传入的参数进行判断统计时间范围
            THEN 1=1
            ELSE
            DATE_FORMAT(sj.tjsj,'%Y%m')=countdatetime
            END
            GROUP BY
            sj.tjsj
            )t_sj
            )tall
            LEFT JOIN
            (
            SELECT
            id AS ssqxdm,
            org_name AS ssqxmc,
            parent_id AS lydwdm,
            (
            SELECT org_name FROM 表C org2 WHERE org2.id=org1.parent_id
            ) AS lydwmc
            FROM
            gb_ztfx.`t_acl_org` org1
            ) tacl
            ON tall.ssqxdm=tacl.ssqxdm
            WHERE tacl.ssqxdm IS NOT NULL;
            -- 查询统计数据并赋值给游标结束
            -- 声明异常处理
            DECLARE CONTINUE HANDLER FOR SQLEXCEPTION
            BEGIN
            -- 捕获异常信息
            GET DIAGNOSTICS CONDITION 1 ERROR_CODE=RETURNED_SQLSTATE,ERROR_MSG=MESSAGE_TEXT;
            -- 统计错误次数
            SET tmp_error_num=tmp_error_num+1;
            SET ERROR_PROCEDURE_INFO=CONCAT('{"PROCEDURE_NAME":','"P_79_80_81_count";'
            ,'"countdatetime":"',countdatetime,',"xmid":"',xmid,'"}');
            INSERT INTO
            t_ztfx_ywtj_procedure_error_log(error_code,error_msg,error_procedure_info,error_create_time)
            VALUES(ERROR_CODE,ERROR_MSG,ERROR_PROCEDURE_INFO,DATE_FORMAT(NOW(),'%Y-%m-%d %H:%i:%s'));
            END;
            -- 将结束标志绑定到游标
            DECLARE CONTINUE HANDLER FOR NOT FOUND SET cur_account_finished = 1;
            -- 打开游标
            OPEN cur_account;
            -- 统计计数置为0
            SET count_num=0;
            -- 遍历游标,取出数据,写入临时表
            read_loop:LOOP
            -- 进行遍历 字段赋值
            FETCH NEXT FROM cur_account
            INTO temp_id,temp_tjyf,temp_ssqxdm,temp_tjsl,temp_qntytjsl,temp_jnlj,
            temp_qnlj,temp_qnqntj,temp_ssqxmc,temp_lydwdm,temp_lydwmc,
            temp_lbid,temp_lb,temp_xmid,temp_xm,temp_xmxlid,temp_xmxl;
            -- 判断是否结束
            IF cur_account_finished = 1 THEN
            -- 判断是否刚好到达提交临界点
            IF temp_detele_idstr <>'' THEN
            -- 根据id批量删除数据
            SET temp_detele_idstr=SUBSTR(temp_detele_idstr,0,LENGTH(temp_detele_idstr)-1);
            SET @temp_detele_sql=CONCAT('DELETE FROM 统计表 tjtb WHERE tjtb.id IN ',
            '(',temp_detele_idstr,')');
            PREPARE delete_value_stmt FROM @temp_detele_sql;
            EXECUTE delete_value_stmt;
            -- 批量插入数据 防止有逗号在最后,使用0作消除。
            SET temp_insert_str=SUBSTRING(temp_insert_str,0,LENGTH(temp_insert_str)-1);
            SET @temp_insert_sql=CONCAT('INSERT INTO 统计表(',
            'id,lbid,lb,xmid,xm,xmxlid,xmxl,tjyf,ssqxdm,ssqxmc,tjsl,qntytjsl,jnlj,qnlj,qnqntj,lydwdm,lydwmc,tjsj',
            ') VALUES ',temp_insert_str,'(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)');
            PREPARE insert_value_stmt1 FROM @temp_insert_sql;
            EXECUTE insert_value_stmt1;
            -- 删除id为‘0’的数据
            DELETE FROM 统计表 tjtb WHERE tjtb.id='0';
            END IF;
            LEAVE read_loop;
            END IF;
            -- 判断批量提交的次数
            IF temp_update_insert_count%update_insert_num = 0 THEN
            -- 批量删除数据
            SET temp_detele_idstr=SUBSTR(temp_detele_idstr,0,LENGTH(temp_detele_idstr)-1);
            SET @temp_detele_sql=CONCAT('DELETE FROM 统计表 tjtb WHERE tjtb.id IN ',
            '(',temp_detele_idstr,')');
            PREPARE delete_value_stmt FROM @temp_detele_sql;
            EXECUTE delete_value_stmt;
            -- 批量插入数据
            SET @temp_insert_sql=CONCAT('INSERT INTO 统计表(',
            'id,lbid,lb,xmid,xm,xmxlid,xmxl,tjyf,ssqxdm,ssqxmc,tjsl,qntytjsl,jnlj,qnlj,qnqntj,lydwdm,lydwmc,tjsj',
            ') VALUES ',temp_insert_str);
            PREPARE insert_value_stmt2 FROM @temp_insert_sql;
            EXECUTE insert_value_stmt2;
            -- 重置操作字符串
            SET temp_detele_idstr='';
            SET temp_insert_str='';
            END IF;
            -- 拼接批量id
            SET temp_detele_idstr=CONCAT(temp_detele_idstr,'\'',temp_id,'\',');
            -- 拼接批量插入字符串
            SET temp_time= DATE_FORMAT(NOW(),'%Y-%m-%d %H:%i:%s');
            SET temp_insert_str=CONCAT(temp_insert_str,'(','\'',temp_id,'\',\'',temp_lbid,'\',\'',temp_lb,'\',\'',
            temp_xmid,'\',\'',temp_xm,'\',\'',IFNULL(temp_xmxlid,''),'\',\'',IFNULL(temp_xmxl,''),'\',\'',temp_tjyf,'\',\'',
            IFNULL(temp_ssqxdm,''),'\',\'',IFNULL(temp_ssqxmc,''),'\',',IFNULL(temp_tjsl,0),',',
            IFNULL(temp_qntytjsl,0),',',IFNULL(temp_jnlj,0),',',IFNULL(temp_qnlj,0),',',
            IFNULL(temp_qnqntj,0),',\'',IFNULL(temp_lydwdm,''),'\',\'',IFNULL(temp_lydwmc,''),'\',\'',temp_time,'\')',
            CASE WHEN (temp_update_insert_count+1)%update_insert_num = 0 THEN '' ELSE ',' END);
            -- 计数器+1
            SET temp_update_insert_count=temp_update_insert_count + 1;
            SET count_num=count_num+1;
            -- 结束循环
            END LOOP;
            -- 关闭游标
            CLOSE cur_account;
            SET error_num=tmp_error_num;
            END


            IP属地:北京6楼2019-12-04 17:51
            回复
              3、把生成临时表的存储过程和二阶段的统计存储过程合成一个存储过程
              /*
              1、功能:统计 1绝对数、2绝对数、3总数
              2、编写人:CZQ
              3、编写/更新时间:2019年7月29日00:34:59
              */
              DROP PROCEDURE IF EXISTS P_79_80_81;
              CREATE PROCEDURE "P_79_80_81"(IN countdatetime VARCHAR(6),IN xmid VARCHAR(6),IN update_insert_num INT)
              BEGIN
              DECLARE temp_prodedure_name varchar(100);-- 存储过程名,
              DECLARE temp_prodedure_pram varchar(255);-- 存储参数
              DECLARE temp_start_time varchar(20);-- 开始时间
              DECLARE temp_end_time varchar(20);-- 结束时间
              -- 记录赋值
              SET temp_prodedure_name='P_79_80_81';
              SET temp_prodedure_pram=CONCAT('{"countdatetime":"',countdatetime,',"xmid":"',xmid,'"}');
              SET temp_start_time=DATE_FORMAT(NOW(),'%Y-%m-%d %H:%i:%s');
              -- 调用生成临时表的存储过程
              CALL P_Ywtj_79_80_81_sqajtj_tmptable(countdatetime,xmid);
              -- 调用二阶段的存储过程(生成最终统计数据并把数据写入到统计表中)
              CALL P_79_80_81_count(countdatetime,xmid,update_insert_num,@count_num,@error_num);
              SET temp_end_time=DATE_FORMAT(NOW(),'%Y-%m-%d %H:%i:%s');
              -- 把统计情况记录到存储过程统计表中
              INSERT INTO t_procedure_call_log(id,prodedure_name,prodedure_pram,start_time,end_time,update_num,error_num)
              VALUES( MD5(CONCAT(temp_prodedure_name,temp_prodedure_pram,NOW())),temp_prodedure_name,temp_prodedure_pram,
              temp_start_time,temp_end_time,@count_num,@error_num);
              END


              IP属地:北京7楼2019-12-04 17:52
              回复
                【定时器编写】
                DROP EVENT IF EXISTS e_ywtj_79_80_81;
                DELIMITER;;
                CREATE EVENT e_ywtj_79_80_81
                -- 每天的3:55分执行
                ON SCHEDULE EVERY 1 DAY STARTS CONCAT(CURDATE(),' 03:55:00')
                ON COMPLETION NOT PRESERVE ENABLE DO
                BEGIN
                -- 统计当前月份的三项统计类型数据,并每次批量提交200条
                CALL P_79_80_81(DATE_FORMAT(NOW(),'%Y%m'),'79',200);
                CALL P_79_80_81(DATE_FORMAT(NOW(),'%Y%m'),'80',200);
                CALL P_79_80_81(DATE_FORMAT(NOW(),'%Y%m'),'81',200);
                END;;
                DELIMITER;


                IP属地:北京8楼2019-12-04 17:53
                回复
                  最后,如果需要排版好看的,请在本帖回复,我会给我自己的服务器博客地址你去看。


                  IP属地:北京9楼2019-12-04 17:54
                  回复