大家知道oracle中的序列與表之前沒有必然的關係,一個序列可以給一個表使用也可以給另一個一使用。
所以最好增加字典表及文檔來保存序列與表之間的對應關係。
那最好這些都沒有怎麼辦呢?
有一個系統中是根據觸發器來調用序列,通過觸發器我們可以找到表與序列之間的對應關係
SELECT NAME,
MAX(CASE referenced_type
WHEN 'TABLE' THEN
referenced_name
END) AS tbl,
MAX(CASE referenced_type
WHEN 'SEQUENCE' THEN
referenced_name
END) AS seq
FROM user_dependencies seq
WHERE TYPE = 'TRIGGER'
AND NAME IN (SELECT NAME
FROM user_source
WHERE TYPE = 'TRIGGER'
AND upper(text) LIKE upper('%.nextval%'))
AND referenced_type IN ('TABLE', 'SEQUENCE')
GROUP BY NAME
HAVING COUNT(*) = 2
/
NAME TBL SEQ
---------- ---------- ----------
TRG_EMP2 EMP2 SEQ_EMP2
有了這個對應關係後就可以查找表對應的主鍵列
WITH seq AS
(SELECT /*+ materialize */
NAME,
MAX(CASE referenced_type
WHEN 'TABLE' THEN
referenced_name
END) AS tbl,
MAX(CASE referenced_type
WHEN 'SEQUENCE' THEN
referenced_name
END) AS seq
FROM user_dependencies seq
WHERE TYPE = 'TRIGGER'
AND NAME IN (SELECT NAME
FROM user_source
WHERE TYPE = 'TRIGGER'
AND upper(text) LIKE upper('%.nextval%'))
AND referenced_type IN ('TABLE', 'SEQUENCE')
GROUP BY NAME
HAVING COUNT(*) = 2)
SELECT trg,seq, tbl, column_name
FROM (SELECT seq.seq,
seq.tbl,
seq.NAME AS trg,
ic.column_name,
COUNT(*) over(PARTITION BY ic.table_name) AS cnt
FROM seq
INNER JOIN user_constraints c
ON c.table_name = seq.tbl
INNER JOIN user_ind_columns ic
ON ic.index_name = c.index_name
INNER JOIN user_tab_cols col
ON col.table_name = ic.table_name
AND col.column_name = ic.column_name
WHERE constraint_type = 'P')
WHERE cnt = 1;
TRG SEQ TBL COLUMN_NAME
---------- ---------- ---------- ---------------
TRG_EMP2 SEQ_EMP2 EMP2 EMPNO
因爲使用序列的表一般都是單列主鍵,所以這兒沒有判斷主鍵列的個數。
對應信息都得到後就可以重建seq了
DECLARE
CURSOR cur_seq IS
WITH seq AS
(SELECT /*+ materialize */
NAME,
MAX(CASE referenced_type
WHEN 'TABLE' THEN
referenced_name
END) AS tbl,
MAX(CASE referenced_type
WHEN 'SEQUENCE' THEN
referenced_name
END) AS seq
FROM user_dependencies seq
WHERE TYPE = 'TRIGGER'
AND NAME IN (SELECT NAME
FROM user_source
WHERE TYPE = 'TRIGGER'
AND upper(text) LIKE upper('%.nextval%'))
AND referenced_type IN ('TABLE', 'SEQUENCE')
GROUP BY NAME
HAVING COUNT(*) = 2)
SELECT trg,seq, tbl, column_name
FROM (SELECT seq.seq,
seq.tbl,
seq.NAME AS trg,
ic.column_name,
COUNT(*) over(PARTITION BY ic.table_name) AS cnt
FROM seq
INNER JOIN user_constraints c
ON c.table_name = seq.tbl
INNER JOIN user_ind_columns ic
ON ic.index_name = c.index_name
INNER JOIN user_tab_cols col
ON col.table_name = ic.table_name
AND col.column_name = ic.column_name
WHERE constraint_type = 'P')
WHERE cnt = 1;
v_trg VARCHAR2(50);
v_seq VARCHAR2(50);
v_tbl VARCHAR2(50);
v_col VARCHAR2(50);
v_sql VARCHAR2(4000);
v_maxid NUMBER;
v_nextval NUMBER;
BEGIN
OPEN cur_seq;
LOOP
FETCH cur_seq
INTO v_trg,v_seq, v_tbl, v_col;
EXIT WHEN cur_seq%NOTFOUND;
v_sql := 'select max(' || v_col || ') from ' || v_tbl;
--dbms_output.put_line(v_sql);
EXECUTE IMMEDIATE v_sql INTO v_maxid;
v_maxid := NVL(v_maxid,0) + 1;
v_sql := 'drop sequence ' || v_seq;
--dbms_output.put_line(v_sql);
EXECUTE IMMEDIATE v_sql;
v_sql := 'create sequence ' || v_seq || ' start with ' || to_char(v_maxid);
--dbms_output.put_line(v_sql);
EXECUTE IMMEDIATE v_sql;
v_sql := 'alter trigger ' || v_trg || ' compile';
--dbms_output.put_line(v_sql);
EXECUTE IMMEDIATE v_sql;
NULL;
END LOOP;
CLOSE cur_seq;
END;