作成日:2025/04/27 更新日:2025/04/27

概要

date型インターバルパーティションの最新データのパーティション名一覧を取得

詳細

date型インターバルパーティションの最新データを含むパーティション名一覧をリストするスクリプト

前提及びポイント

  • パーティション:date型のレンジインターバルパーティション(一か月毎)
  • パーティション名はシステムが自動命名するためパーティション名からは最新パーティションが判断できない。このためuser_tab_partitions.HIGH_VALUEから判断する
  • HIGH_VALUEはLONG型のためそのままではソートできない。PLSQLでいったん文字列型に変換したのち、最新かどうかを判断する

スクリプト

set serveroutput on
DECLARE
    v_high_value_oldest VARCHAR2(4000); -- 最古のHIGH_VALUEを保持
    v_partition_name_latest VARCHAR2(128); -- 最新のパーティション名を保持
BEGIN
    -- パーティションテーブル名を取得するカーソル
    FOR table_record IN (SELECT DISTINCT table_name FROM user_tab_partitions ORDER BY table_name) LOOP
        -- HIGH_VALUEの初期値を非常に古い日付に設定
        v_high_value_oldest := 'TO_DATE('' 1900-01-01 00:00:00'', ''SYYYY-MM-DD HH24:MI:SS'', ''NLS_CALENDAR=GREGORIAN'')';
        v_partition_name_latest := NULL;
        -- 各パーティションのHIGH_VALUEを取得するカーソル
        FOR partition_record IN (SELECT table_name, partition_name, high_value FROM user_tab_partitions WHERE table_name = table_record.table_name) LOOP
            -- 現在のHIGH_VALUEが保持している最古の値より新しいか比較
            -- HIGH_VALUEはLONG型なのでDBMS_LOB.SUBSTRで比較
            IF v_high_value_oldest < DBMS_LOB.SUBSTR(partition_record.high_value, 4000, 1) THEN
                -- より新しいHIGH_VALUEが見つかった場合更新
                v_high_value_oldest := DBMS_LOB.SUBSTR(partition_record.high_value, 4000, 1);
                v_partition_name_latest := partition_record.partition_name;
            END IF;
        END LOOP;
        DBMS_OUTPUT.PUT_LINE(table_record.table_name || ':' || v_partition_name_latest);
    END LOOP;
END;
/

--実行結果例
ORDERS:SYS_P331
ORDERS2:SYS_P535

前提となる表とデータ作成

def table_name = ORDERS

CREATE TABLE &table_name (
    order_id NUMBER PRIMARY KEY,
    order_date DATE NOT NULL,
    customer_id NUMBER,
    customer_segment VARCHAR2(2),
    order_amount NUMBER
)
PARTITION BY RANGE (order_date)
INTERVAL (INTERVAL '1' MONTH)
SUBPARTITION BY LIST (customer_segment)
SUBPARTITION TEMPLATE (
    SUBPARTITION segment_a VALUES ('A1'),
    SUBPARTITION segment_b VALUES ('B2'),
    SUBPARTITION segment_other VALUES (DEFAULT)
)
(
    PARTITION orders_initial VALUES LESS THAN (DATE '1900-01-01')
);


DECLARE
  v_order_date DATE;
  v_customer_segment VARCHAR2(2);
BEGIN
  FOR i IN 1..3000 LOOP
    -- 3年分のランダムな日付を生成 (現在日時から遡って3年間)
    v_order_date := SYSDATE - DBMS_RANDOM.VALUE(0, 3 * 365);

    -- ランダムな customer_segment を生成 ('A1', 'B2', その他)
    CASE TRUNC(DBMS_RANDOM.VALUE(1, 4))
      WHEN 1 THEN v_customer_segment := 'A1';
      WHEN 2 THEN v_customer_segment := 'B2';
      ELSE v_customer_segment := CHR(TRUNC(DBMS_RANDOM.VALUE(65, 91))) || TRUNC(DBMS_RANDOM.VALUE(0, 10)); -- ランダムな2文字
    END CASE;

    -- データの挿入
    INSERT INTO &TABLE_NAME (order_id, order_date, customer_id, customer_segment, order_amount)
    VALUES (i, v_order_date, TRUNC(DBMS_RANDOM.VALUE(1, 100)), v_customer_segment, TRUNC(DBMS_RANDOM.VALUE(100, 1000)));

    -- 各日付パーティションに対して、'A1', 'B2', 'C3' のデータを3件ずつ挿入するロジック (3年分 * 3セグメント * 1件 = 9件)
    IF MOD(i, 1000) = 1 THEN -- 粗い制御で、各1000件ごとに新しい日付とセグメントの組み合わせを試す
      FOR j IN 1..3 LOOP
        v_order_date := SYSDATE - DBMS_RANDOM.VALUE(0, 3 * 365);
        CASE j
          WHEN 1 THEN v_customer_segment := 'A1';
          WHEN 2 THEN v_customer_segment := 'B2';
          WHEN 3 THEN v_customer_segment := 'C3'; -- 'その他' のテスト
        END CASE;
        INSERT INTO &TABLE_NAME (order_id, order_date, customer_id, customer_segment, order_amount)
        VALUES (3000 + (i - 1) * 3 + j, v_order_date, TRUNC(DBMS_RANDOM.VALUE(1, 100)), v_customer_segment, TRUNC(DBMS_RANDOM.VALUE(100, 1000)));
      END LOOP;
    END IF;

  END LOOP;
  COMMIT;
END;
/
★ORACLE案件承ります