概要
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;
/