zoukankan      html  css  js  c++  java
  • oracle10G升级到12C的问题

    数据库字符集由16GBK,变成了32UTF8。数据库导出导入后,varchar2字段内容被截图的风险——在32UTF8下一个汉字占3个字符

    首先我们比对了所有表内容是否一致,后续对所有表字段扩容

    写了一个存储过程 

    CREATE OR REPLACE PACKAGE BODY "PKG_HXDI_ORACLE_UPDATE_UTIL" IS
    
      /**********************************************************
      #PROCEDURE::ORALCE 执行升级比对
      #author:diaoby
      #createdate:2018-12-2 13:00:24
      #example:
      ***********************************************************/
      PROCEDURE P_EXECORACLEUPGRADE IS
        V_USER       VARCHAR2(255); --用户名
        V_TABLE_NAME VARCHAR2(255); --表名
        V_COL_NAME   VARCHAR2(255); --字段名
        V_SQL        VARCHAR2(4000); --比对sql
        --返回表游标定义
        V_TABLE_CUR MYTYPE;
        V_TABLE_REC TABLE_REC;
        --返回字段游标定义
        V_COL_CUR MYTYPE;
        V_COL_REC COL_REC;
        --返回值游标定义
        V_VALUE_CUR MYTYPE;
        V_VALUE_REC V_REC;
      BEGIN
        V_USER      := 'GXMCPM_B_02';
        V_TABLE_CUR := F_GETALLTABLE(V_USER);
        --Fetch 循环  
        LOOP
          FETCH V_TABLE_CUR
            INTO V_TABLE_REC;
          EXIT WHEN V_TABLE_CUR%NOTFOUND;
          V_TABLE_NAME := V_TABLE_REC.TABLE_NAME;
          IF V_TABLE_NAME IS NOT NULL THEN
            V_COL_CUR := F_GETTABLECOL(V_TABLE_NAME);
            LOOP
              FETCH V_COL_CUR
                INTO V_COL_REC;
              EXIT WHEN V_COL_CUR%NOTFOUND;
              V_COL_NAME := V_COL_REC.CNAME;
              IF V_COL_NAME IS NOT NULL THEN
                V_SQL := F_GETSQL(V_TABLE_NAME, V_COL_NAME);
                IF V_SQL IS NOT NULL THEN
                  --打开游标     
                  OPEN V_VALUE_CUR FOR V_SQL;
                  LOOP
                    FETCH V_VALUE_CUR
                      INTO V_VALUE_REC;
                    EXIT WHEN V_VALUE_CUR%NOTFOUND;
                    IF V_VALUE_REC.PK_ID IS NOT NULL THEN
                      P_RECORDLOG(V_TABLE_NAME,
                                  F_GETTABLEPRIMARY(V_TABLE_NAME),
                                  V_VALUE_REC.PK_ID,
                                  V_COL_NAME,
                                  V_VALUE_REC.OLD_VALUE,
                                  V_VALUE_REC.NEW_VALUE);
                    END IF;
                  END LOOP;
                  CLOSE V_VALUE_CUR;
                END IF;
              END IF;
            END LOOP;
            CLOSE V_COL_CUR;
          END IF;
        END LOOP;
        CLOSE V_TABLE_CUR;
      EXCEPTION
        WHEN OTHERS THEN
          DBMS_OUTPUT.PUT_LINE('异常:sql:' || V_SQL || ' SQLCODE:' || SQLCODE);
      END;
    
      /**********************************************************
      #PROCEDURE::ORALCE 升级VARHCAR2 扩展2倍
      #author:diaoby
      #createdate:2018-12-2 13:00:24
      #example:
      ***********************************************************/
      PROCEDURE P_MODIFYVARCHAR IS
        V_USER       VARCHAR2(255); --用户名
        V_TABLE_NAME VARCHAR2(255); --表名
        V_COL_NAME   VARCHAR2(255); --字段名
        V_COL_WIDTH  NUMBER;
        V_SQL        VARCHAR2(4000); --比对sql
        --返回表游标定义
        V_TABLE_CUR MYTYPE;
        V_TABLE_REC TABLE_REC;
        --返回字段游标定义
        V_COL_CUR MYTYPE;
        V_COL_REC COL_REC;
      BEGIN
        V_USER      := 'GXMCPM_B_02';
        V_TABLE_CUR := F_GETALLTABLE(V_USER);
        --Fetch 循环  
        LOOP
          FETCH V_TABLE_CUR
            INTO V_TABLE_REC;
          EXIT WHEN V_TABLE_CUR%NOTFOUND;
          V_TABLE_NAME := V_TABLE_REC.TABLE_NAME;
          V_COL_CUR    := F_GETTABLECOL(V_TABLE_NAME);
          LOOP
            FETCH V_COL_CUR
              INTO V_COL_REC;
            EXIT WHEN V_COL_CUR%NOTFOUND;
            V_COL_NAME  := V_COL_REC.CNAME;
            V_COL_WIDTH := V_COL_REC.WIDTH;
            V_SQL       := 'alter table ' || V_TABLE_NAME || ' modify( ' ||
                           V_COL_NAME || ' VARCHAR2(' || 2 * V_COL_WIDTH || '))';
            --DBMS_OUTPUT.PUT_LINE(V_SQL);
            EXECUTE IMMEDIATE V_SQL;
            -- USING V_TABLE_NAME, V_COL_NAME, 2 * V_COL_WIDTH;
          END LOOP;
          CLOSE V_COL_CUR;
        END LOOP;
        CLOSE V_TABLE_CUR;
      EXCEPTION
        WHEN OTHERS THEN
          DBMS_OUTPUT.PUT_LINE('异常:sql:' || V_SQL || 'SQLCODE:' || SQLCODE);
      END;
    
      /**********************************************************
      #function::根据用户账号获取该用户下所有表结构排查记录表,返回游标
      #author:diaoby
      #createdate:2018-12-2 13:00:24
      #input:in_user  用户名
      #example:
      ***********************************************************/
      FUNCTION F_GETALLTABLE(IN_USER IN VARCHAR2) RETURN MYTYPE IS
        T_CUR MYTYPE;
      BEGIN
        OPEN T_CUR FOR
          SELECT DISTINCT T.TABLE_NAME
            FROM ALL_TABLES T
           WHERE T.OWNER = IN_USER
             /*AND T.TABLE_NAME = 'PD_TASK_PLAN_VER'*/
             AND T.TABLE_NAME != 'ORACLE_LOG';
        RETURN T_CUR;
      END;
    
      /**********************************************************
      #function::根据表名获取所有varhcar2的表字段
      #author:diaoby
      #createdate:2018-12-2 13:00:24
      #input:in_table  表名
      #example:
      ***********************************************************/
      FUNCTION F_GETTABLECOL(IN_TABLE IN VARCHAR2) RETURN MYTYPE IS
        T_CUR MYTYPE;
      BEGIN
        OPEN T_CUR FOR
          SELECT A.CNAME, A.WIDTH
            FROM COL A
           WHERE A.TNAME = UPPER(IN_TABLE)
             AND COLTYPE = 'VARCHAR2'
           ORDER BY A.COLNO;
        RETURN T_CUR;
      END;
    
      /**********************************************************
      #function::根据表名获取对应主键,可能是联合主键  返回,隔开的varhcar2字段
      #author:diaoby
      #createdate:2018-12-2 13:00:24
      #input:in_table  表名
      #example:
      ***********************************************************/
      FUNCTION F_GETTABLEPRIMARY(IN_TABLE IN VARCHAR2) RETURN VARCHAR2 IS
        RESULT_VALUE VARCHAR2(4000);
      BEGIN
        RESULT_VALUE := '';
        FOR REC IN (SELECT COL.COLUMN_NAME
                      FROM USER_CONSTRAINTS CON, USER_CONS_COLUMNS COL
                     WHERE CON.CONSTRAINT_NAME = COL.CONSTRAINT_NAME
                       AND CON.CONSTRAINT_TYPE = 'P'
                       AND COL.TABLE_NAME = UPPER(IN_TABLE)) LOOP
          IF RESULT_VALUE IS NULL THEN
            RESULT_VALUE := REC.COLUMN_NAME;
          ELSIF RESULT_VALUE IS NOT NULL THEN
            RESULT_VALUE := RESULT_VALUE || ',' || REC.COLUMN_NAME;
          END IF;
        END LOOP;
        RETURN RESULT_VALUE;
      END;
    
      /**********************************************************
      #function::根据表名,字段名获取执行的sql
      #author:diaoby
      #createdate:2018-12-2 13:00:24
      #input:in_table  表名
      #input:in_col  字段名
      #example:
      ***********************************************************/
      FUNCTION F_GETSQL(IN_TABLE IN VARCHAR2, IN_COL IN VARCHAR2) RETURN VARCHAR2 IS
        RESULT_SQL   VARCHAR2(4000);
        PRIMARYS     VARCHAR2(4000);
        PRIMARYS_NUM NUMBER;
        V_COLUMN     VARCHAR2(200);
      BEGIN
        V_COLUMN   := '';
        RESULT_SQL := 'SELECT ';
        --根据表名获取主键
        PRIMARYS := F_GETTABLEPRIMARY(IN_TABLE);
        IF PRIMARYS IS NOT NULL THEN
          --获取主键数
          PRIMARYS_NUM := PKG_HXDI_UTIL.F_GETNUM(PRIMARYS, ',');
          FOR I IN 1 .. PRIMARYS_NUM LOOP
            IF I < PRIMARYS_NUM THEN
              RESULT_SQL := RESULT_SQL || ' A.' ||
                            PKG_HXDI_UTIL.F_GETSTR(PRIMARYS, ',', I) || '||';
            ELSIF I = PRIMARYS_NUM THEN
              RESULT_SQL := RESULT_SQL || ' A.' ||
                            PKG_HXDI_UTIL.F_GETSTR(PRIMARYS, ',', I) ||
                            ' PK_ID ,';
            END IF;
          END LOOP;
          RESULT_SQL := RESULT_SQL || ' A.' || IN_COL || ' OLD_VALUE ,' ||
                        ' B.' || IN_COL || ' NEW_VALUE';
          RESULT_SQL := RESULT_SQL || ' FROM ' || IN_TABLE || ' A ,' ||
                        IN_TABLE || '@GXPMSLINK B';
          RESULT_SQL := RESULT_SQL || ' WHERE';
          RESULT_SQL := RESULT_SQL || ' A.' || IN_COL || ' != ' || 'B.' ||
                        IN_COL;
          FOR I IN 1 .. PRIMARYS_NUM LOOP
            V_COLUMN   := PKG_HXDI_UTIL.F_GETSTR(PRIMARYS, ',', I);
            RESULT_SQL := RESULT_SQL || ' AND A.' || V_COLUMN || ' = ';
            RESULT_SQL := RESULT_SQL || ' B.' || V_COLUMN;
          END LOOP;
        ELSE
          RESULT_SQL := '';
        END IF;
        RETURN RESULT_SQL;
      END;
    
      /**********************************************************
      #PROCEDURE::记录日志
      #author:diaoby
      #createdate:2018-12-2 13:00:24
      #input:in_table_name  表名
      #input:in_table_col  字段名
      #input:in_pk_ids   主键ID
      #input:in_pk_values 主键ID值
      #input:in_values10g  字段10g的内容
      #input:in_values12c   字段12c的内容
      #example:
      ***********************************************************/
      PROCEDURE P_RECORDLOG(IN_TABLE_NAME IN VARCHAR2,
                            IN_PK_IDS     IN VARCHAR2,
                            IN_PK_VALUES  IN VARCHAR2,
                            IN_TABLE_COL  IN VARCHAR2,
                            IN_VALUE10G   IN VARCHAR2,
                            IN_VALUE12C   IN VARCHAR2) IS
      
      BEGIN
        INSERT INTO ORACLE_LOG
          (ID_, TABLE_NAME, PK_IDS, PK_VALUES, TABLE_COL, VALUE10G, VALUE12C)
        VALUES
          (SYS_GUID(),
           IN_TABLE_NAME,
           IN_PK_IDS,
           IN_PK_VALUES,
           IN_TABLE_COL,
           IN_VALUE10G,
           IN_VALUE12C);
        COMMIT;
      END;
    END PKG_HXDI_ORACLE_UPDATE_UTIL;
    CREATE OR REPLACE PACKAGE "PKG_HXDI_ORACLE_UPDATE_UTIL" IS
      TYPE MYTYPE IS REF CURSOR; --游标
      TYPE TABLE_REC IS RECORD(
        TABLE_NAME VARCHAR2(255)); --表名
      TYPE COL_REC IS RECORD(
        CNAME VARCHAR2(255),
        WIDTH NUMBER); --字段
      TYPE V_REC IS RECORD(
        PK_ID     VARCHAR2(2000),
        OLD_VALUE VARCHAR2(4000),
        NEW_VALUE VARCHAR2(4000)); --比对结果值记录,防止有多主键的ID 扩展到主键3个  
      /**********************************************************
      #PROCEDURE::ORALCE 执行升级比对
      #author:diaoby
      #createdate:2018-12-2 13:00:24
      #example:
      ***********************************************************/
      PROCEDURE P_EXECORACLEUPGRADE;
      /**********************************************************
      #PROCEDURE::ORALCE 升级VARHCAR2 扩展2倍
      #author:diaoby
      #createdate:2018-12-2 13:00:24
      #example:
      ***********************************************************/
      PROCEDURE P_MODIFYVARCHAR;
      /**********************************************************
      #function::根据用户账号获取该用户下所有表结构排查记录表,返回游标
      #author:diaoby
      #createdate:2018-12-2 13:00:24
      #input:in_user  用户名
      #example:
      ***********************************************************/
      FUNCTION F_GETALLTABLE(IN_USER IN VARCHAR2) RETURN MYTYPE;
    
      /**********************************************************
      #function::根据表名获取所有varhcar2的表字段
      #author:diaoby
      #createdate:2018-12-2 13:00:24
      #input:in_table  表名
      #example:
      ***********************************************************/
      FUNCTION F_GETTABLECOL(IN_TABLE IN VARCHAR2) RETURN MYTYPE;
      /**********************************************************
      #function::根据表名获取对应主键,可能是联合主键  返回,隔开的varhcar2字段
      #author:diaoby
      #createdate:2018-12-2 13:00:24
      #input:in_table  表名
      #example:
      ***********************************************************/
      FUNCTION F_GETTABLEPRIMARY(IN_TABLE IN VARCHAR2) RETURN VARCHAR2;
      /**********************************************************
      #function::根据表名,字段名获取执行的sql
      #author:diaoby
      #createdate:2018-12-2 13:00:24
      #input:in_table  表名
      #input:in_col  字段名
      #example:
      ***********************************************************/
      FUNCTION F_GETSQL(IN_TABLE IN VARCHAR2, IN_COL IN VARCHAR2) RETURN VARCHAR2;
      /**********************************************************
      #PROCEDURE::记录日志
      #author:diaoby
      #createdate:2018-12-2 13:00:24
      #input:in_table_name  表名
      #input:in_table_col  字段名
      #input:in_pk_ids   主键ID
      #input:in_pk_values 主键ID值
      #input:in_values10g  字段10g的内容
      #input:in_values12c   字段12c的内容
      #example:
      ***********************************************************/
      PROCEDURE P_RECORDLOG(IN_TABLE_NAME IN VARCHAR2,
                            IN_PK_IDS     IN VARCHAR2,
                            IN_PK_VALUES  IN VARCHAR2,
                            IN_TABLE_COL  IN VARCHAR2,
                            IN_VALUE10G   IN VARCHAR2,
                            IN_VALUE12C   IN VARCHAR2);
    END PKG_HXDI_ORACLE_UPDATE_UTIL;

    先执行P_EXECORACLEUPGRADE 把所有差异的数据记录到ORACLE_LOG中

    后面根据情况执行 P_MODIFYVARCHAR 扩充VARCHAR2 

  • 相关阅读:
    With great power comes great responsibility
    2016年你应该学习的语言和框架
    箜篌长萧各一曲,月清淡似风人未眠。
    使用 RUP 管理小型项目和团队
    php文件加锁 lock_sh ,lock_ex
    PHP_EOL
    PHP输入流php://input介绍
    获取ip地址
    关键词拍卖和广义二阶拍卖(Internet Advertising and the Generalized Second-Price Auction译文)
    常用js选择
  • 原文地址:https://www.cnblogs.com/diaobiyong/p/10064133.html
Copyright © 2011-2022 走看看