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