当前位置: 代码迷 >> SQL >> PL/SQL 程序开发,惯用处理
  详细解决方案

PL/SQL 程序开发,惯用处理

热度:62   发布时间:2016-05-05 14:20:04.0
PL/SQL 程序开发,常用处理

整理了一下PL/SQL开发中较孤立的脚本,如:测试时用到的数据表填充、对象HWM查询、动态性能统计信息、字符串拆分等; 具体的使用方法在包头中都有描述。

?

?

希望感兴趣的朋友可以对其进行扩展,共同分享。? 目前正在更新中。。。

?

代码:

?

?

CREATE OR REPLACE PACKAGE PKG_COMMON IS

? TYPE TAB_STR IS TABLE OF VARCHAR2(2000);
? TYPE TAB_NUM IS TABLE OF NUMBER; -- INDEX BY BINARY_INTEGER;

? /*? OBJECT 类型 包中不支持?? "RECORED" 包体通过编译*/
? TYPE T_SQLTEXT IS RECORD(
??? SQL_ID???? VARCHAR2(20),
??? HASH_VALUE VARCHAR2(20),
??? SQL_TEXT?? CLOB);
? TYPE TAB_SQLTEXT IS TABLE OF T_SQLTEXT;

? TYPE T_OUTPUT IS RECORD(
??? NAME???? VARCHAR2(300),
??? VALUE??? NUMBER,
??? DIFF???? NUMBER,
??? COMMENTS VARCHAR2(500));
? TYPE TAB_OUTPUT IS TABLE OF T_OUTPUT; --INDEX BY BINARY_INTEGER;

? /************************************************************************
? 函数名: F_SQLTEXT
? 参数说明:
? 功能描述 : V$SQLTEXT 视图 格式化结果返回
? 作者:ZHANGYONG
? 修改时间:2010-7-22 20:03:44
? 备注: 返回 TAB_SQLTEXT 类型
? 调用测试: SELECT * FROM TABLE(PKG_COMMON.F_SQLTEXT);
? /************************************************************************/

? FUNCTION F_SQLTEXT RETURN TAB_SQLTEXT
??? PIPELINED;

? /************************************************************************
? 函数名: F_CONTAIN_DIGIT
? 参数说明: P_STR 目标字符串
? 功能描述 :判断字符串是否包涵数字 (10g 可用正则实现)
? 作者:ZHANGYONG
? 修改时间:2010-10-17 18:54:11
? 备注: 存在返回1,不存在返回 0
? 调用测试: SELECT PKG_COMMON.F_CONTAIN_DIGIT('ABCEDFG') RS FROM DUAL;
? /************************************************************************/

? FUNCTION F_CONTAIN_DIGIT(P_STR IN VARCHAR2) RETURN NUMBER;

? /************************************************************************
? 函数名: F_CONTAIN_ALPHA
? 参数说明: P_STR 目标字符串
? 功能描述 :判断字符串是否包涵字母 (10g 可用正则实现)
? 作者:ZHANGYONG
? 修改时间:2010-10-17 18:54:11
? 备注: 存在返回1,不存在返回 0
? 调用测试: SELECT PKG_COMMON.F_CONTAIN_ALPHA('4523543Q543') RS FROM DUAL;
? /************************************************************************/

? FUNCTION F_CONTAIN_ALPHA(P_STR IN VARCHAR2) RETURN NUMBER;

? /************************************************************************
? 函数名: F_SPLITSTR
? 参数说明: P_STR VARCHAR2:? 目标字符串
???????????? P_GAP VARCHAR2:? 字符串分间符
? 功能描述 :根据分间符对目标字符串进行切分
? 作者:ZHANGYONG
? 修改时间:2010-7-22 20:03:44
? 备注: 返回字符串(返回字符串长度需小于1000)
? 调用测试:? SELECT * FROM TABLE(PKG_COMMON.F_SPLITSTR(',A,D,B,F,,', ','));
? /************************************************************************/

? FUNCTION F_SPLITSTR(P_STR IN VARCHAR2, P_GAP IN VARCHAR2 DEFAULT ',')
??? RETURN TAB_STR
??? PIPELINED;

? /************************************************************************
? 过程名:??? PROC_TAB_FULL
? 参数说明: P_OWNER:??? 表属主
???????????? P_TAB_NAME: 目标数据表
???????????? P_FTYPE:??? 填充类型(1:字母[默认]? 2:数字 3:中文)
???????????? P_ROWCNT:?? 填充行数
? 功能描述 :以字段的最大长度值填充数据表
? 作者:ZHANGYONG
? 修改时间:2010-10-17 10:54:54
? 执行环境:对目标表需要有插入权限,且能查看 "ALL_TAB_COLS" 数据字典
? 备注:
? 1 对于 BLOB,CLOB,LOGN 等字段以 NULL值处理;
??? DATE,TIMESTAMP 填充 SYSDATE;
??? NUMBER,INTEGER,DECIMAL,FLOAT 填充10的次数
? 2 若目标表存在主键,外键,触发器等约束,暂没进行处理。
? 3 若目标表非常宽,内存溢出; 可进入 "OUTPUT" 面板,改大 "BUFFER SIZE" ;
? 4 调用测试 CALL PKG_COMMON.PROC_TAB_FULL('DEPT',USER,3);
? /************************************************************************/

? PROCEDURE PROC_TAB_FULL(P_TAB_NAME VARCHAR2,
????????????????????????? P_OWNER??? IN VARCHAR2 DEFAULT USER,
????????????????????????? P_FTYPE??? NUMBER DEFAULT 1,
????????????????????????? P_ROWCNT?? NUMBER DEFAULT 1);

? /************************************************************************
? 函数名:??? SHOW_STAT
? 参数说明: P_STATNAME:统计性能信息名称,默认为'redo size'; 若有多个则以“,”相隔
? 功能描述 :展示完成某操作之前和之后的某些Oracle“统计结果”的变化情况。
? 作者:ZHANGYONG
? 修改时间:2010-10-21 21:19:07
? 执行环境:有权限查看 V$STATNAME 与 V$MYSTAT 动态性能视图
? 注意:
????? 第一次执行对数据库内存信息进行记录,当处理完操作后,第二次执行方可查看前后
????? 变化结果,两次执行 P_STATNAME 应保持一致 !
? 备注:
??? 调用测试
??? SELECT * FROM TABLE(PKG_COMMON.SHOW_STAT());
??? SELECT * FROM TABLE(PKG_COMMON.SHOW_STAT('redo ,parse'));
? /************************************************************************/

? FUNCTION SHOW_STAT(P_STATNAME IN VARCHAR2 DEFAULT 'redo size')
??? RETURN TAB_OUTPUT
??? PIPELINED;
? /************************************************************************
? 函数名:??? SHOW_SPACE(在TOM上进行修改)
? 参数说明: P_SEGNAME:段名(例如,表或索引名)。
???????????? P_OWNER:默认为当前用户,不过也可以使用这个例程查看另外某个模式。
???????????? P_TYPE:默认为TABLE,这个参数表示查看哪种类型的对象(段)。
???? 例如,SELECT DISTINCT SEGMENT_TYPE FROM DBA_SEGMENTS 会列出合法的段类型。
???????????? P_PARTITION:显示分区对象的空间时所用的分区名。SHOW_SPACE 一次只显示一个分区的空间利用率。
? 功能描述 :输出数据库段空间利用率信息
? 作者:ZHANGYONG
? 修改时间:2010-10-21 21:19:07
? 执行环境:有权限查看 DBA_SEGMENTS 与 DBA_TABLESPACES 数据视图
? 备注:
??? 调用测试? SELECT * FROM TABLE(PKG_COMMON.SHOW_SPACE('DEPT'));
? /************************************************************************/

? FUNCTION SHOW_SPACE(P_SEGNAME?? IN VARCHAR2,
????????????????????? P_OWNER???? IN VARCHAR2 DEFAULT USER,
????????????????????? P_TYPE????? IN VARCHAR2 DEFAULT 'TABLE',
????????????????????? P_PARTITION IN VARCHAR2 DEFAULT NULL) RETURN TAB_OUTPUT
??? PIPELINED;

END PKG_COMMON;
/
CREATE OR REPLACE PACKAGE BODY PKG_COMMON IS

? G_CNT???? PLS_INTEGER := 0;
? G_STR???? VARCHAR2(100);
? G_TAB_NUM TAB_NUM := TAB_NUM();
? --G_TAB_STR TAB_STR;

? /************************************************************************
? 函数名: F_SQLTEXT
? 参数说明:
? 功能描述 : V$SQLTEXT 格式化结果返回
? 作者:ZHANGYONG
? 修改时间:2010-7-22 20:03:44
? 备注: 返回 TAB_SQLTEXT 类型
? /************************************************************************/
? FUNCTION F_SQLTEXT RETURN TAB_SQLTEXT
??? PIPELINED IS
??? V_T_SQLTEXT T_SQLTEXT;
??? V_SQLTEXT?? CLOB;
??? CURSOR CUR_SQLTEXT IS
????? SELECT T.SQL_ID,
???????????? T.HASH_VALUE,
???????????? T.PIECE,
???????????? MAX(PIECE) OVER(PARTITION BY SQL_ID, HASH_VALUE ORDER BY T.PIECE ASC NULLS LAST ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) CNT,
???????????? T.SQL_TEXT
??????? FROM V$SQLTEXT T;
? BEGIN
??? FOR CUR IN CUR_SQLTEXT LOOP
????? V_SQLTEXT := V_SQLTEXT || CUR.SQL_TEXT;
????? IF CUR.PIECE = CUR.CNT THEN
??????? V_T_SQLTEXT.SQL_ID???? := CUR.SQL_ID;
??????? V_T_SQLTEXT.HASH_VALUE := CUR.HASH_VALUE;
??????? V_T_SQLTEXT.SQL_TEXT?? := V_SQLTEXT;
??????? --PIPE ROW(T_SQLTEXT(CUR.SQL_ID, CUR.HASH_VALUE, V_SQLTEXT));
??????? PIPE ROW(V_T_SQLTEXT);
??????? V_SQLTEXT := '';
????? END IF;
??? END LOOP;
??? RETURN;
? END F_SQLTEXT;

? /************************************************************************
? 函数名: F_CONTAIN_DIGIT
? 参数说明: P_STR 目标字符串
? 功能描述 :判断字符串是否包涵数字(10g 可用正则实现)
? 作者:ZHANGYONG
? 修改时间:2010-10-17 18:54:11
? 备注: 存在返回1,不存在返回0
? /************************************************************************/

? FUNCTION F_CONTAIN_DIGIT(P_STR VARCHAR2) RETURN NUMBER IS
??? L_BASE_STR VARCHAR2(10) := '0123456789';
??? L_TMP_STR? VARCHAR2(2000);
? BEGIN
??? SELECT TRANSLATE(P_STR || L_BASE_STR, P_STR || L_BASE_STR, P_STR)
????? INTO L_TMP_STR
????? FROM DUAL;
??? IF LENGTH(P_STR) = LENGTH(L_TMP_STR) THEN
????? RETURN 0;
??? ELSE
????? RETURN 1;
??? END IF;
? END F_CONTAIN_DIGIT;

? /************************************************************************
? 函数名: F_CONTAIN_LETTER
? 参数说明: P_STR 目标字符串
? 功能描述 :判断字符串是否包涵字母 (10g 可用正则实现)
? 作者:ZHANGYONG
? 修改时间:2010-10-17 18:54:11
? 备注: 存在返回1,不存在返回 0
? SELECT PKG_COMMON.F_CONTAIN_NUM('ABCEDFG') RS FROM DUAL;
? /************************************************************************/

? FUNCTION F_CONTAIN_ALPHA(P_STR VARCHAR2) RETURN NUMBER IS
??? L_BASE_STR VARCHAR2(52) := 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
??? L_TMP_STR? VARCHAR2(2000);
? BEGIN
??? SELECT TRANSLATE(P_STR || L_BASE_STR, P_STR || L_BASE_STR, P_STR)
????? INTO L_TMP_STR
????? FROM DUAL;
??? IF LENGTH(P_STR) = LENGTH(L_TMP_STR) THEN
????? RETURN 0;
??? ELSE
????? RETURN 1;
??? END IF;
? END F_CONTAIN_ALPHA;

? /************************************************************************
? 函数名: F_SPLITSTR
? 参数说明: P_STR VARCHAR2:? 目标字符串
???????????? P_GAP VARCHAR2:? 字符串分间符
? 功能描述 :根据分间符对目标字符串进行切分
? 作者:ZHANGYONG
? 修改时间:2010-7-22 20:03:44
? 备注: 返回字符串(截断字符串长度需小于2000)
? /************************************************************************/

? FUNCTION F_SPLITSTR(P_STR IN VARCHAR2, P_GAP IN VARCHAR2 DEFAULT ',')
??? RETURN TAB_STR
??? PIPELINED AS
??? L_FLAG??? NUMBER := 0;
??? L_STR???? VARCHAR2(4000) := P_STR || P_GAP;
??? L_TMP_STR VARCHAR2(2000);
? BEGIN
?
??? IF P_STR IS NULL THEN
????? PIPE ROW(P_STR);
????? RETURN;
??? END IF;
??? WHILE L_STR IS NOT NULL LOOP
????? SELECT INSTR(L_STR, P_GAP) INTO L_FLAG FROM DUAL; --查找切分位置
????? L_TMP_STR := SUBSTR(L_STR, 1, L_FLAG - 1);
????? IF LENGTH(L_TMP_STR) > 0 THEN
??????? PIPE ROW(L_TMP_STR);
????? END IF;
????? L_STR := SUBSTR(L_STR, L_FLAG + 1);
??? END LOOP;
? END F_SPLITSTR;

? /************************************************************************
? 函数名:??? GET_VALUE
? 参数说明: P_CUR_CHAR: 基字符串
???????????? P_DLEN:? 目标长度
? 功能描述 :返回目标长度的基字符串
? 作者:ZHANGYONG
? 修改时间:2010-10-17 10:54:54
? 备注:? P_CUR_CHAR 长度不要超过4000
? /************************************************************************/
? FUNCTION GET_VALUE(P_CUR_CHAR VARCHAR2, P_DLEN NUMBER) RETURN VARCHAR2 IS
??? L_CUR_CHAR VARCHAR2(4000) := P_CUR_CHAR;
? BEGIN
??? WHILE LENGTHB(L_CUR_CHAR) < P_DLEN LOOP
????? L_CUR_CHAR := L_CUR_CHAR || P_CUR_CHAR;
??? END LOOP;
??? RETURN SUBSTRB(L_CUR_CHAR, 1, P_DLEN);
? END GET_VALUE;

? /************************************************************************
? 函数名:??? GET_VALUE
? 参数说明: P_DTYPE: Oralce 常用数据类型
???????????? P_DLEN:? 填充长度
???????????? P_FTYPE: 填充类型(1:字母[默认]? 2:数字 3:中文)
? 功能描述 :返回特定长度、格式的字符串
? 作者:ZHANGYONG
? 修改时间:2010-10-17 10:54:54
? 备注:
? /************************************************************************/

? FUNCTION GET_VALUE(P_DTYPE????? VARCHAR2,
???????????????????? P_DLEN?????? NUMBER,
???????????????????? P_DPRECISION NUMBER,
???????????????????? P_DSCALE???? NUMBER,
???????????????????? P_FTYPE????? NUMBER) RETURN VARCHAR2 IS
??? L_BCHAR??? VARCHAR2(52) := 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; --DEFUALT
??? L_NUMCHAR? VARCHAR(10) := '1234567890';
??? L_CHAR???? VARCHAR2(20) := '中文中文中文中文中文';
??? L_CUR_CHAR VARCHAR2(52);
? BEGIN
??? IF P_FTYPE IS NULL OR P_FTYPE = 1 THEN
????? L_CUR_CHAR := L_BCHAR;
??? ELSIF P_FTYPE = 2 THEN
????? L_CUR_CHAR := L_NUMCHAR;
??? ELSIF P_FTYPE = 3 THEN
????? L_CUR_CHAR := L_CHAR;
??? ELSE
????? L_CUR_CHAR := L_BCHAR;
??? END IF;
?
??? IF P_DTYPE = 'VARCHAR2' OR P_DTYPE = 'CHAR' THEN
????? RETURN CHR(39) || GET_VALUE(L_CUR_CHAR, P_DLEN) || CHR(39);
??? ELSIF P_DTYPE = 'NUMBER' OR P_DTYPE = 'FLOAT' THEN
????? IF P_DPRECISION IS NOT NULL THEN
??????? RETURN CHR(39) || TO_CHAR(POWER(10, P_DPRECISION - P_DSCALE - 1)) || CHR(39);
????? ELSE
??????? RETURN CHR(39) || TO_CHAR(POWER(10, 2)) || CHR(39); --没有设置精度,默认为100
????? END IF;
??? ELSIF P_DTYPE = 'DATE' OR P_DTYPE LIKE '%TIMESTAMP%' THEN
????? RETURN 'SYSDATE';
??? ELSE
????? RETURN 'NULL';
??? END IF;
? END GET_VALUE;

? /************************************************************************
? 过程名:??? PROC_TAB_FULL
? 参数说明: P_TAB_NAME: 目标数据表
???????????? P_FTYPE:?? 填充类型(1:字母[默认]? 2:数字 3:中文)
???????????? P_ROWCNT: 填充行数
? 功能描述 :以字段的最大长度值填充数据表
? 作者:ZHANGYONG
? 修改时间:2010-10-17 10:54:54
? 执行环境:对目标表需要有插入权限,且能查看 "ALL_TAB_COLS" 数据字典
? 备注:
? 1 对于 BLOB,CLOB,LOGN 等字段以 NULL值处理;
??? DATE,TIMESTAMP 填充 SYSDATE;
??? NUMBER,INTEGER,DECIMAL,FLOAT 填充10的次数
? 2 若目标表存在主键,外键,触发器等约束,暂没进行处理。
? 3 若目标表非常宽,内存溢出; 可进入 "OUTPUT" 面板,改大 "BUFFER SIZE" ;
? /************************************************************************/

? PROCEDURE PROC_TAB_FULL(P_TAB_NAME VARCHAR2,
????????????????????????? P_OWNER??? IN VARCHAR2 DEFAULT USER,
????????????????????????? P_FTYPE??? NUMBER DEFAULT 1,
????????????????????????? P_ROWCNT?? NUMBER DEFAULT 1) IS
?
??? TYPE TY_COLS IS TABLE OF VARCHAR2(30); --表列类型
??? TAB_COLS???????? TY_COLS;
??? L_CUR_DTYPE????? VARCHAR2(106);
??? L_CUR_DLEN?????? NUMBER;
??? L_CUR_DPRECISION NUMBER;
??? L_CUR_DSCALE???? NUMBER;
??? L_SQL_STR??????? CLOB;
? BEGIN
??? -- 查询表的列
??? SELECT T.COLUMN_NAME BULK COLLECT
????? INTO TAB_COLS
????? FROM ALL_TAB_COLS T
???? WHERE T.TABLE_NAME = UPPER(P_TAB_NAME)
?????? AND T.OWNER = UPPER(P_OWNER);
?
??? FOR CNT IN 1 .. P_ROWCNT LOOP
???
????? --1 拼接SQL 头部
????? L_SQL_STR := 'INSERT INTO ' || P_TAB_NAME || '(';
????? FOR I IN TAB_COLS.FIRST .. TAB_COLS.LAST LOOP
??????? L_SQL_STR := L_SQL_STR || TAB_COLS(I) || ',';
????? END LOOP;
????? L_SQL_STR := SUBSTR(L_SQL_STR, 1, LENGTH(L_SQL_STR) - 1) ||
?????????????????? ')? VALUES (';
???
????? --2 拼接SQL 数据值
????? FOR I IN TAB_COLS.FIRST .. TAB_COLS.LAST LOOP
?????
??????? SELECT T.DATA_TYPE, T.DATA_LENGTH, T.DATA_PRECISION, T.DATA_SCALE
????????? INTO L_CUR_DTYPE, L_CUR_DLEN, L_CUR_DPRECISION, L_CUR_DSCALE
????????? FROM ALL_TAB_COLS T
???????? WHERE T.TABLE_NAME = UPPER(P_TAB_NAME)
?????????? AND T.COLUMN_NAME = TAB_COLS(I)
?????????? AND T.OWNER = UPPER(P_OWNER);
?????
??????? L_SQL_STR := L_SQL_STR || GET_VALUE(L_CUR_DTYPE,
??????????????????????????????????????????? L_CUR_DLEN,
??????????????????????????????????????????? L_CUR_DPRECISION,
??????????????????????????????????????????? L_CUR_DSCALE,
??????????????????????????????????????????? P_FTYPE) || ',';
????? END LOOP;
???
????? --3 拼接SQL 尾部
????? L_SQL_STR := SUBSTR(L_SQL_STR, 1, LENGTH(L_SQL_STR) - 1) || ')';
???
????? --SQL输出
????? /* FOR I IN 1 .. CEIL(LENGTH(L_SQL_STR) / 255) LOOP
??????? DBMS_OUTPUT.PUT_LINE(SUBSTR(L_SQL_STR, (I - 1) * 255 + 1, 255));
????? END LOOP;*/
???
????? -- SQL执行
????? EXECUTE IMMEDIATE DBMS_LOB.SUBSTR(L_SQL_STR);
???
????? --空置
????? L_SQL_STR := '';
???
??? END LOOP;
?
? END PROC_TAB_FULL;

? /************************************************************************
? 函数名:??? SHOW_STAT
? 参数说明: P_STATNAME:统计性能信息名称,默认为'redo size'; 若有多个则以“,”相隔
? 功能描述 :展示完成某操作之前和之后的某些Oracle“统计结果”的变化情况。
? 作者:ZHANGYONG
? 修改时间:2010-10-21 21:19:07
? 执行环境:有权限查看 V$STATNAME 与 V$MYSTAT 动态性能视图
? 注意:
????? 第一次执行对数据库内存信息进行记录,当处理完操作后,第二次执行方可查看前后
????? 变化结果,两次执行 P_STATNAME 应保持一致 !
? 备注:
? /************************************************************************/

? FUNCTION SHOW_STAT(P_STATNAME IN VARCHAR2 DEFAULT 'redo size')
??? RETURN TAB_OUTPUT
??? PIPELINED IS
??? L_STATNAME????? VARCHAR2(100) := P_STATNAME;
??? L_TAB_STR?????? TAB_STR;
??? L_TMP_TAB_NAME? TAB_STR;
??? L_TMP_TAB_VALUE TAB_NUM;
??? L_TAB_NAME????? TAB_STR := TAB_STR();
??? L_TAB_VALUE???? TAB_NUM := TAB_NUM();
??? L_T_OUTPUT????? T_OUTPUT;
??? L_STATAME?????? VARCHAR2(100);
?
??? -- inline function to return nicely t_output type
??? -- with a p_name、p_value、p_last_value parameter
??? FUNCTION F(P_NAME?????? IN VARCHAR2,
?????????????? P_VALUE????? IN NUMBER,
?????????????? P_LAST_VALUE IN NUMBER) RETURN T_OUTPUT IS
??? BEGIN
????? L_T_OUTPUT.NAME? := P_NAME;
????? L_T_OUTPUT.VALUE := P_VALUE;
????? L_T_OUTPUT.DIFF? := P_VALUE - P_LAST_VALUE;
????? RETURN L_T_OUTPUT;
??? END;
?
??? --数组迭加
??? PROCEDURE APPEND(P_SOURCE_TAB IN OUT NOCOPY TAB_STR,
???????????????????? P_TARGET_TAB IN OUT NOCOPY TAB_STR) IS
????? L_CUR_CNT PLS_INTEGER := NVL(P_SOURCE_TAB.LAST, 0); --源数组最后一个下标值
??? BEGIN
????? FOR I IN 1 .. P_TARGET_TAB.COUNT LOOP
??????? P_SOURCE_TAB.EXTEND();
??????? P_SOURCE_TAB(L_CUR_CNT + I) := P_TARGET_TAB(I);
????? END LOOP;
??? EXCEPTION
????? WHEN OTHERS THEN
??????? RAISE;
??? END;
?
??? PROCEDURE APPEND(P_SOURCE_TAB IN OUT NOCOPY TAB_NUM,
???????????????????? P_TARGET_TAB IN OUT NOCOPY TAB_NUM) IS
????? L_CUR_CNT PLS_INTEGER := NVL(P_SOURCE_TAB.LAST, 0); --源数组最后一个下标值
??? BEGIN
????? FOR I IN 1 .. P_TARGET_TAB.COUNT LOOP
??????? P_SOURCE_TAB.EXTEND();
??????? P_SOURCE_TAB(L_CUR_CNT + I) := P_TARGET_TAB(I);
????? END LOOP;
??? EXCEPTION
????? WHEN OTHERS THEN
??????? RAISE;
??? END;
?
? BEGIN
?
??? IF P_STATNAME IS NULL OR LENGTH(TRIM(P_STATNAME)) = 0 THEN
????? L_STATNAME := 'redo size';
??? END IF;
?
??? SELECT COLUMN_VALUE BULK COLLECT
????? INTO L_TAB_STR
????? FROM TABLE(F_SPLITSTR(L_STATNAME));
?
??? --访问信息变更,则重新记录
??? IF G_CNT <> 0 AND G_STR <> L_STATNAME THEN
????? G_CNT???? := 0;
????? G_TAB_NUM := L_TMP_TAB_VALUE;
??? END IF;
?
??? FOR I IN 1 .. L_TAB_STR.COUNT LOOP
????? L_STATAME := CHR(37) || LOWER(L_TAB_STR(I)) || CHR(37);
???
????? SELECT A.NAME, B.VALUE BULK COLLECT
??????? INTO L_TMP_TAB_NAME, L_TMP_TAB_VALUE
??????? FROM V$STATNAME A, V$MYSTAT B
?????? WHERE A.STATISTIC# = B.STATISTIC#
???????? AND LOWER(A.NAME) LIKE '' || L_STATAME || '';
???
????? --数组元素累加
????? APPEND(L_TAB_NAME, L_TMP_TAB_NAME);
????? APPEND(L_TAB_VALUE, L_TMP_TAB_VALUE);
??? END LOOP;
?
??? IF G_CNT = 0 THEN
????? G_STR???? := L_STATNAME;
????? G_TAB_NUM := L_TAB_VALUE;
??? END IF;
?
??? FOR I IN 1 .. L_TAB_NAME.COUNT LOOP
????? PIPE ROW(F(L_TAB_NAME(I), L_TAB_VALUE(I), G_TAB_NUM(I)));
??? END LOOP;
?
??? G_TAB_NUM := L_TAB_VALUE;
??? G_CNT???? := 1; --修改状态
??? RETURN;
? END SHOW_STAT;

? /************************************************************************
? 函数名:??? SHOW_SPACE(在TOM上进行修改)
? 参数说明: P_SEGNAME:段名(例如,表或索引名)。
???????????? P_OWNER:默认为当前用户,不过也可以使用这个例程查看另外某个模式。
???????????? P_TYPE:默认为TABLE,这个参数表示查看哪种类型的对象(段)。
???? 例如,SELECT DISTINCT SEGMENT_TYPE FROM DBA_SEGMENTS 会列出合法的段类型。
???????????? P_PARTITION:显示分区对象的空间时所用的分区名。SHOW_SPACE 一次只显示一个分区的空间利用率。
? 功能描述 :输出数据库段空间利用率信息
? 作者:ZHANGYONG
? 修改时间:2010-10-21 21:19:07
? 执行环境:有权限查看 DBA_SEGMENTS 与 DBA_TABLESPACES 数据视图
? /************************************************************************/

? FUNCTION SHOW_SPACE(P_SEGNAME?? IN VARCHAR2,
????????????????????? P_OWNER???? IN VARCHAR2 DEFAULT USER,
????????????????????? P_TYPE????? IN VARCHAR2 DEFAULT 'TABLE',
????????????????????? P_PARTITION IN VARCHAR2 DEFAULT NULL) RETURN TAB_OUTPUT
??? PIPELINED IS
??? /*
???????? this procedure uses authid current user so it can query DBA_*
???????? views using privileges from a ROLE
??? */
??? L_FREE_BLKS????????? NUMBER;
??? L_TOTAL_BLOCKS?????? NUMBER;
??? L_TOTAL_BYTES??????? NUMBER;
??? L_UNUSED_BLOCKS????? NUMBER;
??? L_UNUSED_BYTES?????? NUMBER;
??? L_LASTUSEDEXTFILEID? NUMBER;
??? L_LASTUSEDEXTBLOCKID NUMBER;
??? L_LAST_USED_BLOCK??? NUMBER;
??? L_SEGMENT_SPACE_MGMT VARCHAR2(255);
??? L_UNFORMATTED_BLOCKS NUMBER;
??? L_UNFORMATTED_BYTES? NUMBER;
??? L_FS1_BLOCKS???????? NUMBER;
??? L_FS1_BYTES????????? NUMBER;
??? L_FS2_BLOCKS???????? NUMBER;
??? L_FS2_BYTES????????? NUMBER;
??? L_FS3_BLOCKS???????? NUMBER;
??? L_FS3_BYTES????????? NUMBER;
??? L_FS4_BLOCKS???????? NUMBER;
??? L_FS4_BYTES????????? NUMBER;
??? L_FULL_BLOCKS??????? NUMBER;
??? L_FULL_BYTES???????? NUMBER;
??? L_T_OUTPUT?????????? T_OUTPUT;
?
??? -- inline function to return nicely t_output type
??? -- with a p_name、p_value、p_comment parameter
??? FUNCTION F(P_NAME??? IN VARCHAR2,
?????????????? P_VALUE?? IN NUMBER,
?????????????? P_COMMENT IN VARCHAR2 DEFAULT '') RETURN T_OUTPUT IS
??? BEGIN
????? L_T_OUTPUT.NAME???? := P_NAME;
????? L_T_OUTPUT.VALUE??? := P_VALUE;
????? L_T_OUTPUT.COMMENTS := P_COMMENT;
????? RETURN L_T_OUTPUT;
??? END;
? BEGIN
??? -- this query is executed dynamically in order to allow this procedure
??? -- to be created by a user who has access to DBA_SEGMENTS/TABLESPACES
??? -- via a role as is customary.
??? -- NOTE: at runtime, the invoker MUST have access to these two
??? -- views!
??? -- this query determines if the object is an ASSM object or not
??? BEGIN
????? EXECUTE IMMEDIATE ' SELECT TS.SEGMENT_SPACE_MANAGEMENT ' ||
??????????????????????? ' FROM DBA_SEGMENTS SEG, DBA_TABLESPACES TS ' ||
??????????????????????? ' WHERE SEG.SEGMENT_NAME = :P_SEGNAME ' ||
??????????????????????? ' AND (:P_PARTITION IS NULL OR ' ||
??????????????????????? ' SEG.PARTITION_NAME = :P_PARTITION ) ' ||
??????????????????????? ' AND SEG.OWNER = :P_OWNER ' ||
??????????????????????? ' AND SEG.TABLESPACE_NAME = TS.TABLESPACE_NAME'
??????? INTO L_SEGMENT_SPACE_MGMT
??????? USING P_SEGNAME, P_PARTITION, P_PARTITION, P_OWNER;
??? EXCEPTION
????? WHEN TOO_MANY_ROWS THEN
??????? DBMS_OUTPUT.PUT_LINE('THIS MUST BE A PARTITIONED TABLE, USEP_PARTITION => ');
??????? RETURN;
??? END;
??? -- if the object is in an ASSM tablespace, we must use this API
??? -- call to get space information, otherwise we use the FREE_BLOCKS
??? -- API for the user-managed segments
??? IF L_SEGMENT_SPACE_MGMT = 'AUTO' THEN
????? DBMS_SPACE.SPACE_USAGE(P_OWNER,
???????????????????????????? P_SEGNAME,
???????????????????????????? P_TYPE,
???????????????????????????? L_UNFORMATTED_BLOCKS,
???????????????????????????? L_UNFORMATTED_BYTES,
???????????????????????????? L_FS1_BLOCKS,
???????????????????????????? L_FS1_BYTES,
???????????????????????????? L_FS2_BLOCKS,
???????????????????????????? L_FS2_BYTES,
???????????????????????????? L_FS3_BLOCKS,
???????????????????????????? L_FS3_BYTES,
???????????????????????????? L_FS4_BLOCKS,
???????????????????????????? L_FS4_BYTES,
???????????????????????????? L_FULL_BLOCKS,
???????????????????????????? L_FULL_BYTES,
???????????????????????????? P_PARTITION);
????? PIPE ROW(F('Unformatted Blocks',
???????????????? L_UNFORMATTED_BLOCKS,
???????????????? '为表分配的位于高水位线(high-water mark,HWM)之下但未用的块数。' ||
???????????????? '把未格式化和未用的块加在一起,就是已为表分配但从未用于保存ASSM 对象数据的总块数。'));
????? PIPE ROW(F('FS1 Blocks (0-25) ',
???????????????? L_FS1_BLOCKS,
???????????????? 'FS1 Blocks-FS4 Blocks:包含数据的格式化块。项名后的数字区间表示各块的“空闲度”。' ||
???????????????? '例如,0-25)是指空闲度为0~25%的块数。'));
????? PIPE ROW(F('FS2 Blocks (25-50) ', L_FS2_BLOCKS));
????? PIPE ROW(F('FS3 Blocks (50-75) ', L_FS3_BLOCKS));
????? PIPE ROW(F('FS4 Blocks (75-100)', L_FS4_BLOCKS));
????? PIPE ROW(F('Full Blocks ',
???????????????? L_FULL_BLOCKS,
???????????????? '已满的块数,不能再对这些执行插入。'));
??? ELSE
????? DBMS_SPACE.FREE_BLOCKS(SEGMENT_OWNER???? => P_OWNER,
???????????????????????????? SEGMENT_NAME????? => P_SEGNAME,
???????????????????????????? SEGMENT_TYPE????? => P_TYPE,
???????????????????????????? FREELIST_GROUP_ID => 0,
???????????????????????????? FREE_BLKS???????? => L_FREE_BLKS);
????? PIPE ROW(F('Free Blocks',
???????????????? L_FREE_BLKS,
???????????????? '段的第一个freelist(自由列表)组中的块数。'));
??? END IF;
??? -- and then the unused space API call to get the rest of the
??? -- information
??? DBMS_SPACE.UNUSED_SPACE(SEGMENT_OWNER???????????? => P_OWNER,
??????????????????????????? SEGMENT_NAME????????????? => P_SEGNAME,
??????????????????????????? SEGMENT_TYPE????????????? => P_TYPE,
??????????????????????????? PARTITION_NAME??????????? => P_PARTITION,
??????????????????????????? TOTAL_BLOCKS????????????? => L_TOTAL_BLOCKS,
??????????????????????????? TOTAL_BYTES?????????????? => L_TOTAL_BYTES,
??????????????????????????? UNUSED_BLOCKS???????????? => L_UNUSED_BLOCKS,
??????????????????????????? UNUSED_BYTES????????????? => L_UNUSED_BYTES,
??????????????????????????? LAST_USED_EXTENT_FILE_ID? => L_LASTUSEDEXTFILEID,
??????????????????????????? LAST_USED_EXTENT_BLOCK_ID => L_LASTUSEDEXTBLOCKID,
??????????????????????????? LAST_USED_BLOCK?????????? => L_LAST_USED_BLOCK);
??? PIPE ROW(F('Total Blocks',
?????????????? L_TOTAL_BLOCKS,
?????????????? '为所查看的段分配的总空间量,单位:数据库块。'));
??? PIPE ROW(F('Total Bytes',
?????????????? L_TOTAL_BYTES,
?????????????? '为所查看的段分配的总空间量,单位:字节。'));
??? PIPE ROW(F('Total MBytes',
?????????????? TRUNC(L_TOTAL_BYTES / 1024 / 1024),
?????????????? '为所查看的段分配的总空间量,单位:兆。'));
??? PIPE ROW(F('Unused Blocks',
?????????????? L_UNUSED_BLOCKS,
?????????????? '表示未用空间所占的比例(未用空间量)。这些块已经分配给所查看的段,' ||
?????????????? '但目前在段的HWM 之上。单位:数据库块。'));
??? PIPE ROW(F('Unused Bytes',
?????????????? L_UNUSED_BYTES,
?????????????? '表示未用空间所占的比例(未用空间量)。这些块已经分配给所查看的段,' ||
?????????????? '但目前在段的HWM 之上。单位:字节。 '));
??? PIPE ROW(F('Last Used Ext FileId',
?????????????? L_LASTUSEDEXTFILEID,
?????????????? '最后使用的文件的文件ID,该文件包含最后一个含数据的区段( extent)。'));
??? PIPE ROW(F('Last Used Ext BlockId',
?????????????? L_LASTUSEDEXTBLOCKID,
?????????????? '最后一个区段开始处的块ID;这是最后使用的文件中的块ID。'));
??? PIPE ROW(F('Last Used Block',
?????????????? L_LAST_USED_BLOCK,
?????????????? '最后一个区段中最后一个块的偏移量;和 “Last Used Ext BlockId” 值合并起来' ||
?????????????? '就是HWM 位置。所查看的对象的高水位线 :' || L_LASTUSEDEXTBLOCKID ||
?????????????? '号extent的' || L_LAST_USED_BLOCK || '号块'));
??? RETURN;
? END SHOW_SPACE;

END PKG_COMMON;
/

  相关解决方案