テーブルの最小値、最大値の確認


テーブルの各カラムの最大値、最小値を確認するPL/SQL
データ量増大で桁あふれが近々発生しないか監視するためなどに使用。

--★結果の出力先を指定
SPOOL P:\HOGE.TXT;

SET linesize 2000

SET SERVEROUTPUT ON;

DECLARE

  --カーソル定義
  CURSOR CURCOLUMNS IS 
    SELECT 
              USER_TAB_COLUMNS.TABLE_NAME
             ,USER_TAB_COLUMNS.COLUMN_NAME
             ,USER_TAB_COLUMNS.DATA_TYPE
             ,USER_TAB_COLUMNS.DATA_LENGTH
             ,USER_TAB_COLUMNS.DATA_PRECISION
             ,USER_TAB_COL_STATISTICS.LOW_VALUE
             ,USER_TAB_COL_STATISTICS.HIGH_VALUE
             ,USER_TAB_COL_STATISTICS.SAMPLE_SIZE
    FROM USER_TAB_COLUMNS 
    LEFT JOIN USER_TAB_COL_STATISTICS 
    ON   USER_TAB_COLUMNS.TABLE_NAME  = USER_TAB_COL_STATISTICS.TABLE_NAME 
    AND  USER_TAB_COLUMNS.COLUMN_NAME = USER_TAB_COL_STATISTICS.COLUMN_NAME
    WHERE USER_TAB_COLUMNS.TABLE_NAME LIKE  '%%' --★テーブル名でのフィルタ
    ORDER BY TABLE_NAME,COLUMN_ID;

   --変数の定義
   VMIN_VAL           VARCHAR2(32767) := NULL;
   VMAX_VAL           VARCHAR2(32767) := NULL;

  --ローカルファンクション定義
  FUNCTION FUNC_CONVERT_RAW_VALUE(pVALUE IN RAW, pDATATYPE IN VARCHAR2)
    RETURN VARCHAR2
    IS
      VDATATYPE      VARCHAR2(2000) := UPPER(pDATATYPE);
      VDATE          DATE;
      VBINARYFLOAT   BINARY_FLOAT;
      VBINARYDOUBLE  BINARY_DOUBLE;
      VNUMBER        NUMBER;
      VROWID         ROWID;
      VRET           VARCHAR2(32767) := NULL;
    BEGIN
      IF (pVALUE IS NOT NULL) THEN
        CASE VDATATYPE
        WHEN 'DATE' THEN
          DBMS_STATS.CONVERT_RAW_VALUE(pVALUE, VDATE);
          VRET := VDATE;
        WHEN 'BINARY_FLOAT' THEN
          DBMS_STATS.CONVERT_RAW_VALUE(pVALUE, VBINARYFLOAT);
          VRET := TO_CHAR(VBINARYFLOAT);
        WHEN 'BINARY_DOUBLE' THEN
          DBMS_STATS.CONVERT_RAW_VALUE(pVALUE, VBINARYDOUBLE);
          VRET := TO_CHAR(VBINARYDOUBLE);
        WHEN 'NUMBER' THEN
          DBMS_STATS.CONVERT_RAW_VALUE(pVALUE, VNUMBER);
          VRET := TO_CHAR(VNUMBER);
        WHEN 'CHAR' THEN
          DBMS_STATS.CONVERT_RAW_VALUE(pVALUE, VRET);
        WHEN 'VARCHAR2' THEN
          DBMS_STATS.CONVERT_RAW_VALUE(pVALUE, VRET);
        WHEN 'NCHAR' THEN
          VRET := TO_CHAR(UTL_RAW.CAST_TO_NVARCHAR2(pVALUE));
        WHEN 'NVARCHAR2' THEN
          VRET := TO_CHAR(UTL_RAW.CAST_TO_NVARCHAR2(pVALUE));
        WHEN 'ROWID' THEN
          DBMS_STATS.CONVERT_RAW_VALUE_ROWID(pVALUE, VROWID);
          VRET := TO_CHAR(VROWID);
        ELSE
          VRET := '['|| TO_CHAR(pVALUE) ||']';
        END CASE;
      END IF;
      RETURN VRET;
    EXCEPTION
      WHEN OTHERS THEN
      VRET := 'ERR!['|| TO_CHAR(pVALUE) ||']';
      RETURN VRET;
    END;

--**********メイン処理***********************************************************************
BEGIN

    --タイトル
    DBMS_OUTPUT.PUT_LINE('-----------------------------------------------------------------');
    DBMS_OUTPUT.PUT_LINE(  'TABLE_NAME'     || CHR(9) 
            || 'COLUMN_NAME'    || CHR(9) 
            || 'DATA_TYPE'      || CHR(9) 
            || 'DATA_LENGTH'    || CHR(9) 
            || 'DATA_PRECISION' || CHR(9)
            || 'LOW_VALUE'      || CHR(9)
            || 'HIGH_VALUE'     || CHR(9)
            || 'SAMPLE_SIZE'     || CHR(9)
            || 'MIN_VALUE'     || CHR(9)
            || 'MAX_VALUE'     || CHR(9)
                        );

    --USER_TAB_COLUMNSのループ
    FOR C_DEPT_REC IN CURCOLUMNS LOOP

        --動的SQLでMIN/MAXを取得☆
        EXECUTE IMMEDIATE
         'SELECT MIN(' || C_DEPT_REC.COLUMN_NAME || ')  FROM  ' || C_DEPT_REC.TABLE_NAME  INTO VMIN_VAL;

        EXECUTE IMMEDIATE
         'SELECT MAX(' || C_DEPT_REC.COLUMN_NAME || ')  FROM  ' || C_DEPT_REC.TABLE_NAME  INTO VMAX_VAL;

        ---結果を出力
        DBMS_OUTPUT.PUT_LINE(C_DEPT_REC.TABLE_NAME || CHR(9) 
            || C_DEPT_REC.COLUMN_NAME  || CHR(9) 
            || C_DEPT_REC.DATA_TYPE    || CHR(9) 
            || C_DEPT_REC.DATA_LENGTH  || CHR(9) 
            || C_DEPT_REC.DATA_PRECISION || CHR(9) 
            || FUNC_CONVERT_RAW_VALUE(C_DEPT_REC.LOW_VALUE, C_DEPT_REC.DATA_TYPE) || CHR(9) 
            || FUNC_CONVERT_RAW_VALUE(C_DEPT_REC.HIGH_VALUE, C_DEPT_REC.DATA_TYPE) || CHR(9) 
            || C_DEPT_REC.SAMPLE_SIZE || CHR(9) 
            || VMIN_VAL || CHR(9) 
            || VMAX_VAL || CHR(9) 
            );


    END LOOP;


END;
/
SPOOL OFF;

統計情報を格納しているUSER_TAB_COL_STATISTICSにも値を保持しているが
サンプルサイズが小さい場合は精度が低くなってしまうので動的SQLでSELECTを発行する機能を追加した。
⇒ただし実行時間がかかるのでそこまでの精度が不要ならコメントしてもよい
(レスポンスは無視して実装したので改善の余地あり)


動作確認環境:Oracle 10g