docs(board4分表): 更新数据库排查与重建说明文档
parent
d22e7ca0ee
commit
c3fedce7d5
File diff suppressed because it is too large
Load Diff
@ -1,190 +0,0 @@
|
||||
-- 自动创建设备参数月分表与对应触发器
|
||||
-- 说明:
|
||||
-- 1. 仅需部署一次本包,后续可由 DBMS_SCHEDULER 自动调用。
|
||||
-- 2. 默认使用“当前月分表”克隆出“下月分表”,并自动创建下月 RT 触发器。
|
||||
-- 3. 本包是幂等的:目标分表或目标触发器已存在时会自动跳过。
|
||||
-- 4. 首次上线前,仍需人工确保“当前月分表”已经存在,例如 BASE_DEVICE_PARAM_VAL_202603。
|
||||
|
||||
CREATE OR REPLACE PACKAGE PKG_DEVICE_PARAM_PARTITION AS
|
||||
|
||||
PROCEDURE ENSURE_MONTH_TABLE_AND_TRIGGER(
|
||||
P_TARGET_SUFFIX IN VARCHAR2 DEFAULT TO_CHAR(ADD_MONTHS(TRUNC(SYSDATE, 'MM'), 1), 'YYYYMM'),
|
||||
P_SOURCE_SUFFIX IN VARCHAR2 DEFAULT TO_CHAR(TRUNC(SYSDATE, 'MM'), 'YYYYMM')
|
||||
);
|
||||
|
||||
END PKG_DEVICE_PARAM_PARTITION;
|
||||
/
|
||||
|
||||
CREATE OR REPLACE PACKAGE BODY PKG_DEVICE_PARAM_PARTITION AS
|
||||
|
||||
C_TABLE_PREFIX CONSTANT VARCHAR2(64) := 'BASE_DEVICE_PARAM_VAL_';
|
||||
C_TRIGGER_PREFIX CONSTANT VARCHAR2(64) := 'TRG_BDPV_';
|
||||
|
||||
PROCEDURE VALIDATE_SUFFIX(P_SUFFIX IN VARCHAR2) IS
|
||||
BEGIN
|
||||
IF P_SUFFIX IS NULL OR NOT REGEXP_LIKE(P_SUFFIX, '^\d{6}$') THEN
|
||||
RAISE_APPLICATION_ERROR(-20001, '非法分表后缀: ' || NVL(P_SUFFIX, 'NULL'));
|
||||
END IF;
|
||||
END VALIDATE_SUFFIX;
|
||||
|
||||
FUNCTION OBJECT_EXISTS(P_OBJECT_NAME IN VARCHAR2, P_OBJECT_TYPE IN VARCHAR2) RETURN NUMBER IS
|
||||
V_COUNT NUMBER;
|
||||
BEGIN
|
||||
SELECT COUNT(1)
|
||||
INTO V_COUNT
|
||||
FROM USER_OBJECTS
|
||||
WHERE OBJECT_NAME = UPPER(P_OBJECT_NAME)
|
||||
AND OBJECT_TYPE = UPPER(P_OBJECT_TYPE);
|
||||
RETURN V_COUNT;
|
||||
END OBJECT_EXISTS;
|
||||
|
||||
FUNCTION TABLE_EXISTS(P_TABLE_NAME IN VARCHAR2) RETURN NUMBER IS
|
||||
V_COUNT NUMBER;
|
||||
BEGIN
|
||||
SELECT COUNT(1)
|
||||
INTO V_COUNT
|
||||
FROM USER_TABLES
|
||||
WHERE TABLE_NAME = UPPER(P_TABLE_NAME);
|
||||
RETURN V_COUNT;
|
||||
END TABLE_EXISTS;
|
||||
|
||||
PROCEDURE EXECUTE_DDL(P_SQL IN CLOB) IS
|
||||
V_CURSOR INTEGER;
|
||||
BEGIN
|
||||
V_CURSOR := DBMS_SQL.OPEN_CURSOR;
|
||||
DBMS_SQL.PARSE(V_CURSOR, P_SQL, DBMS_SQL.NATIVE);
|
||||
DBMS_SQL.CLOSE_CURSOR(V_CURSOR);
|
||||
EXCEPTION
|
||||
WHEN OTHERS THEN
|
||||
IF DBMS_SQL.IS_OPEN(V_CURSOR) THEN
|
||||
DBMS_SQL.CLOSE_CURSOR(V_CURSOR);
|
||||
END IF;
|
||||
RAISE;
|
||||
END EXECUTE_DDL;
|
||||
|
||||
PROCEDURE CREATE_TARGET_TABLE(P_SOURCE_TABLE IN VARCHAR2, P_TARGET_TABLE IN VARCHAR2) IS
|
||||
V_SQL CLOB;
|
||||
BEGIN
|
||||
-- 为什么这样做:用当前月物理表结构克隆下月表,能保证字段类型与现网保持一致。
|
||||
V_SQL := 'CREATE TABLE ' || P_TARGET_TABLE || ' AS SELECT * FROM ' || P_SOURCE_TABLE || ' WHERE 1 = 0';
|
||||
EXECUTE IMMEDIATE V_SQL;
|
||||
END CREATE_TARGET_TABLE;
|
||||
|
||||
PROCEDURE CREATE_TARGET_INDEXES(P_TARGET_TABLE IN VARCHAR2, P_TARGET_SUFFIX IN VARCHAR2) IS
|
||||
V_INDEX_NAME_1 VARCHAR2(128);
|
||||
V_INDEX_NAME_2 VARCHAR2(128);
|
||||
BEGIN
|
||||
V_INDEX_NAME_1 := 'IDX_BDPV_' || P_TARGET_SUFFIX || '_PCD';
|
||||
V_INDEX_NAME_2 := 'IDX_BDPV_' || P_TARGET_SUFFIX || '_DCT';
|
||||
|
||||
IF OBJECT_EXISTS(V_INDEX_NAME_1, 'INDEX') = 0 THEN
|
||||
EXECUTE IMMEDIATE 'CREATE INDEX ' || V_INDEX_NAME_1 ||
|
||||
' ON ' || P_TARGET_TABLE || ' (PARAM_NAME, COLLECT_TIME, DEVICE_CODE, RECORD_ID)';
|
||||
END IF;
|
||||
|
||||
IF OBJECT_EXISTS(V_INDEX_NAME_2, 'INDEX') = 0 THEN
|
||||
EXECUTE IMMEDIATE 'CREATE INDEX ' || V_INDEX_NAME_2 ||
|
||||
' ON ' || P_TARGET_TABLE || ' (DEVICE_CODE, COLLECT_TIME)';
|
||||
END IF;
|
||||
END CREATE_TARGET_INDEXES;
|
||||
|
||||
PROCEDURE CREATE_TARGET_TRIGGER(P_TARGET_TABLE IN VARCHAR2, P_TARGET_SUFFIX IN VARCHAR2) IS
|
||||
V_TRIGGER_NAME VARCHAR2(128);
|
||||
V_SQL CLOB;
|
||||
BEGIN
|
||||
V_TRIGGER_NAME := C_TRIGGER_PREFIX || P_TARGET_SUFFIX || '_RT';
|
||||
IF OBJECT_EXISTS(V_TRIGGER_NAME, 'TRIGGER') > 0 THEN
|
||||
RETURN;
|
||||
END IF;
|
||||
|
||||
V_SQL := 'CREATE OR REPLACE TRIGGER ' || V_TRIGGER_NAME || CHR(10) ||
|
||||
'AFTER INSERT ON ' || P_TARGET_TABLE || CHR(10) ||
|
||||
'FOR EACH ROW' || CHR(10) ||
|
||||
'DECLARE' || CHR(10) ||
|
||||
' V_PROD_DATE DATE;' || CHR(10) ||
|
||||
' V_NEW_VAL NUMBER(18,4);' || CHR(10) ||
|
||||
' V_LAST_VAL NUMBER(18,4);' || CHR(10) ||
|
||||
' V_CUR_TOTAL NUMBER(18,4);' || CHR(10) ||
|
||||
' V_RESET_COUNT NUMBER(10);' || CHR(10) ||
|
||||
' V_DELTA NUMBER(18,4);' || CHR(10) ||
|
||||
'BEGIN' || CHR(10) ||
|
||||
' IF :NEW.PARAM_NAME <> ''机台状态-实际产出数量'' THEN' || CHR(10) ||
|
||||
' RETURN;' || CHR(10) ||
|
||||
' END IF;' || CHR(10) ||
|
||||
' IF :NEW.DEVICE_CODE LIKE ''OLD-%'' THEN' || CHR(10) ||
|
||||
' RETURN;' || CHR(10) ||
|
||||
' END IF;' || CHR(10) ||
|
||||
' BEGIN' || CHR(10) ||
|
||||
' V_NEW_VAL := TO_NUMBER(:NEW.PARAM_VALUE);' || CHR(10) ||
|
||||
' EXCEPTION' || CHR(10) ||
|
||||
' WHEN OTHERS THEN' || CHR(10) ||
|
||||
' RETURN;' || CHR(10) ||
|
||||
' END;' || CHR(10) ||
|
||||
' V_PROD_DATE := TRUNC(:NEW.COLLECT_TIME);' || CHR(10) ||
|
||||
' BEGIN' || CHR(10) ||
|
||||
' SELECT LAST_PARAM_VAL, CURRENT_TOTAL, RESET_COUNT' || CHR(10) ||
|
||||
' INTO V_LAST_VAL, V_CUR_TOTAL, V_RESET_COUNT' || CHR(10) ||
|
||||
' FROM RT_DAILY_PROD_STATE' || CHR(10) ||
|
||||
' WHERE PROD_DATE = V_PROD_DATE' || CHR(10) ||
|
||||
' AND DEVICE_CODE = :NEW.DEVICE_CODE' || CHR(10) ||
|
||||
' AND PARAM_NAME = :NEW.PARAM_NAME' || CHR(10) ||
|
||||
' FOR UPDATE;' || CHR(10) ||
|
||||
' IF V_NEW_VAL > V_LAST_VAL THEN' || CHR(10) ||
|
||||
' V_DELTA := V_NEW_VAL - V_LAST_VAL;' || CHR(10) ||
|
||||
' ELSIF V_NEW_VAL < V_LAST_VAL THEN' || CHR(10) ||
|
||||
' V_DELTA := V_NEW_VAL;' || CHR(10) ||
|
||||
' V_RESET_COUNT := NVL(V_RESET_COUNT, 0) + 1;' || CHR(10) ||
|
||||
' ELSE' || CHR(10) ||
|
||||
' V_DELTA := 0;' || CHR(10) ||
|
||||
' END IF;' || CHR(10) ||
|
||||
' UPDATE RT_DAILY_PROD_STATE' || CHR(10) ||
|
||||
' SET LAST_PARAM_VAL = V_NEW_VAL,' || CHR(10) ||
|
||||
' CURRENT_TOTAL = NVL(V_CUR_TOTAL, 0) + NVL(V_DELTA, 0),' || CHR(10) ||
|
||||
' RESET_COUNT = NVL(V_RESET_COUNT, 0),' || CHR(10) ||
|
||||
' LAST_COLLECT_TIME = :NEW.COLLECT_TIME,' || CHR(10) ||
|
||||
' UPDATE_TIME = SYSDATE' || CHR(10) ||
|
||||
' WHERE PROD_DATE = V_PROD_DATE' || CHR(10) ||
|
||||
' AND DEVICE_CODE = :NEW.DEVICE_CODE' || CHR(10) ||
|
||||
' AND PARAM_NAME = :NEW.PARAM_NAME;' || CHR(10) ||
|
||||
' EXCEPTION' || CHR(10) ||
|
||||
' WHEN NO_DATA_FOUND THEN' || CHR(10) ||
|
||||
' INSERT INTO RT_DAILY_PROD_STATE (' || CHR(10) ||
|
||||
' PROD_DATE, DEVICE_CODE, PARAM_NAME, LAST_PARAM_VAL,' || CHR(10) ||
|
||||
' CURRENT_TOTAL, RESET_COUNT, DIRTY_FLAG, LAST_COLLECT_TIME, UPDATE_TIME' || CHR(10) ||
|
||||
' ) VALUES (' || CHR(10) ||
|
||||
' V_PROD_DATE, :NEW.DEVICE_CODE, :NEW.PARAM_NAME, V_NEW_VAL,' || CHR(10) ||
|
||||
' 0, 0, 0, :NEW.COLLECT_TIME, SYSDATE' || CHR(10) ||
|
||||
' );' || CHR(10) ||
|
||||
' END;' || CHR(10) ||
|
||||
'END;';
|
||||
|
||||
EXECUTE_DDL(V_SQL);
|
||||
END CREATE_TARGET_TRIGGER;
|
||||
|
||||
PROCEDURE ENSURE_MONTH_TABLE_AND_TRIGGER(
|
||||
P_TARGET_SUFFIX IN VARCHAR2 DEFAULT TO_CHAR(ADD_MONTHS(TRUNC(SYSDATE, 'MM'), 1), 'YYYYMM'),
|
||||
P_SOURCE_SUFFIX IN VARCHAR2 DEFAULT TO_CHAR(TRUNC(SYSDATE, 'MM'), 'YYYYMM')
|
||||
) IS
|
||||
V_SOURCE_TABLE VARCHAR2(128);
|
||||
V_TARGET_TABLE VARCHAR2(128);
|
||||
BEGIN
|
||||
VALIDATE_SUFFIX(P_TARGET_SUFFIX);
|
||||
VALIDATE_SUFFIX(P_SOURCE_SUFFIX);
|
||||
|
||||
V_SOURCE_TABLE := C_TABLE_PREFIX || P_SOURCE_SUFFIX;
|
||||
V_TARGET_TABLE := C_TABLE_PREFIX || P_TARGET_SUFFIX;
|
||||
|
||||
IF TABLE_EXISTS(V_SOURCE_TABLE) = 0 THEN
|
||||
RAISE_APPLICATION_ERROR(-20002, '源分表不存在: ' || V_SOURCE_TABLE);
|
||||
END IF;
|
||||
|
||||
IF TABLE_EXISTS(V_TARGET_TABLE) = 0 THEN
|
||||
CREATE_TARGET_TABLE(V_SOURCE_TABLE, V_TARGET_TABLE);
|
||||
END IF;
|
||||
|
||||
CREATE_TARGET_INDEXES(V_TARGET_TABLE, P_TARGET_SUFFIX);
|
||||
CREATE_TARGET_TRIGGER(V_TARGET_TABLE, P_TARGET_SUFFIX);
|
||||
END ENSURE_MONTH_TABLE_AND_TRIGGER;
|
||||
|
||||
END PKG_DEVICE_PARAM_PARTITION;
|
||||
/
|
||||
@ -1,37 +0,0 @@
|
||||
-- 自动创建下月分表与触发器的数据库任务
|
||||
-- 说明:
|
||||
-- 1. 每月 28 号到 31 号 23:55 都会尝试执行一次。
|
||||
-- 2. 由于 ENSURE_MONTH_TABLE_AND_TRIGGER 是幂等的,所以重复执行不会重复建表。
|
||||
-- 3. 采用这种写法是为了兼容不同月份天数。
|
||||
|
||||
BEGIN
|
||||
DBMS_SCHEDULER.DROP_JOB(
|
||||
JOB_NAME => 'JOB_ENSURE_DEVICE_PARAM_PARTITION',
|
||||
FORCE => TRUE
|
||||
);
|
||||
EXCEPTION
|
||||
WHEN OTHERS THEN
|
||||
IF SQLCODE != -27475 THEN
|
||||
RAISE;
|
||||
END IF;
|
||||
END;
|
||||
/
|
||||
|
||||
BEGIN
|
||||
DBMS_SCHEDULER.CREATE_JOB(
|
||||
JOB_NAME => 'JOB_ENSURE_DEVICE_PARAM_PARTITION',
|
||||
JOB_TYPE => 'PLSQL_BLOCK',
|
||||
JOB_ACTION => 'BEGIN PKG_DEVICE_PARAM_PARTITION.ENSURE_MONTH_TABLE_AND_TRIGGER; END;',
|
||||
START_DATE => SYSTIMESTAMP,
|
||||
REPEAT_INTERVAL => 'FREQ=MONTHLY;BYMONTHDAY=28,29,30,31;BYHOUR=23;BYMINUTE=55;BYSECOND=0',
|
||||
ENABLED => TRUE,
|
||||
AUTO_DROP => FALSE,
|
||||
COMMENTS => '自动创建下月设备参数分表与 RT 触发器'
|
||||
);
|
||||
END;
|
||||
/
|
||||
|
||||
-- 查看状态:
|
||||
-- SELECT JOB_NAME, ENABLED, STATE, LAST_START_DATE, NEXT_RUN_DATE
|
||||
-- FROM USER_SCHEDULER_JOBS
|
||||
-- WHERE JOB_NAME = 'JOB_ENSURE_DEVICE_PARAM_PARTITION';
|
||||
Loading…
Reference in New Issue