【Oracle】DBMS_RANDOM完全ガイド|乱数・ランダム文字列の生成・テストデータ作成・ランダムサンプリングまで解説

Oracle の DBMS_RANDOM パッケージは、PL/SQL・SQL からランダムな数値や文字列を生成するためのユーティリティです。単体テスト用のテストデータ生成・統計的サンプリング・シミュレーションデータの作成・パスワード候補の生成などで活用できます。

この記事でわかること

  • DBMS_RANDOM.VALUE で 0〜1 の乱数・範囲指定の乱数を生成する方法
  • DBMS_RANDOM.STRING でランダムな文字列を生成する方法(大文字・小文字・英数字・印字可能文字)
  • DBMS_RANDOM.NORMAL で正規分布の乱数を生成する方法
  • DBMS_RANDOM.SEED でシードを設定して再現性のある乱数を生成する方法
  • SQL の SELECT 文でランダムサンプリングを行う方法
  • テストデータを大量生成するスクリプトパターン
スポンサーリンク

DBMS_RANDOM.VALUE で乱数を生成する

VALUE で 0〜1 の乱数・範囲指定の乱数を生成する
-- VALUE(): 0 以上 1 未満の浮動小数点数を返す
SELECT DBMS_RANDOM.VALUE FROM DUAL;
-- 出力例: 0.7423681902...

-- VALUE(low, high): low 以上 high 未満の乱数を返す
SELECT DBMS_RANDOM.VALUE(1, 100) FROM DUAL;
-- 出力例: 47.382...(1〜100 未満の小数)

-- 整数の乱数を生成する(TRUNC または ROUND で整数にする)
SELECT TRUNC(DBMS_RANDOM.VALUE(1, 11)) FROM DUAL;
-- 出力例: 7(1〜10 の整数)

-- TRUNC(DBMS_RANDOM.VALUE(low, high + 1)) で low〜high の整数を生成する
-- (high を含めるために high+1 を指定する)
SELECT TRUNC(DBMS_RANDOM.VALUE(1, 101)) AS dice FROM DUAL;
-- → 1〜100 の整数ランダム

-- 複数行の乱数を SELECT で生成する(CONNECT BY LEVEL を使う)
SELECT
    LEVEL AS row_no,
    ROUND(DBMS_RANDOM.VALUE(0, 100), 2) AS score,
    TRUNC(DBMS_RANDOM.VALUE(1, 13))     AS month_no
FROM DUAL
CONNECT BY LEVEL <= 10;
-- 10行の乱数データを生成する

DBMS_RANDOM.STRING でランダム文字列を生成する

DBMS_RANDOM.STRING(opt, len) は指定した文字種・長さのランダム文字列を返します。第1引数 opt で文字の種類を指定します。

opt の値 生成される文字種 主な用途
'U' または 'u' 大文字アルファベット(A〜Z) コード・識別子の生成
'L' または 'l' 小文字アルファベット(a〜z) スラッグ・キーの生成
'A' または 'a' 大文字・小文字アルファベット混合(A〜Z・a〜z) 名前・トークンの生成
'X' または 'x' 大文字アルファベット・数字(A〜Z・0〜9) 英数字コードの生成
'P' または 'p' 印字可能な任意の ASCII 文字 パスワード候補の生成(記号含む)
STRING でランダム文字列を生成する
-- 大文字のみ・10文字
SELECT DBMS_RANDOM.STRING('U', 10) FROM DUAL;
-- 出力例: KHQZTMALPW

-- 小文字のみ・8文字
SELECT DBMS_RANDOM.STRING('L', 8) FROM DUAL;
-- 出力例: xzvpmqba

-- 英数字混合(大文字+数字)・12文字(ランダムコード向き)
SELECT DBMS_RANDOM.STRING('X', 12) FROM DUAL;
-- 出力例: K3Y8BMNQ07PZ

-- 印字可能 ASCII・16文字(記号含む、パスワード候補向き)
SELECT DBMS_RANDOM.STRING('P', 16) FROM DUAL;
-- 出力例: J@k#9!qR&5mTp^2n

-- テストデータ用に名前風の文字列を生成する
SELECT
    LEVEL                                              AS id,
    DBMS_RANDOM.STRING('A', 6)                        AS first_name,
    DBMS_RANDOM.STRING('A', 8)                        AS last_name,
    LOWER(DBMS_RANDOM.STRING('A', 8)) || '@test.com'  AS email,
    TRUNC(DBMS_RANDOM.VALUE(20000, 100001))            AS salary
FROM DUAL
CONNECT BY LEVEL <= 20;

DBMS_RANDOM.NORMAL で正規分布の乱数を生成する

NORMAL で正規分布の乱数を生成する
-- NORMAL(): 平均 0・標準偏差 1 の標準正規分布に従う乱数を返す
DECLARE
    v_val NUMBER;
BEGIN
    v_val := DBMS_RANDOM.NORMAL;
    DBMS_OUTPUT.PUT_LINE('正規乱数: ' || ROUND(v_val, 4));
    -- 出力例: 1.2847 or -0.4521
END;
/

-- 任意の平均・標準偏差に変換する公式: X = mean + stddev * NORMAL
-- 例: 平均 50,000・標準偏差 10,000 の給与分布を生成する
SELECT
    LEVEL AS id,
    ROUND(50000 + 10000 * DBMS_RANDOM.NORMAL) AS salary
FROM DUAL
CONNECT BY LEVEL <= 10;
-- → 平均 50,000 付近のランダムな給与データが生成される
-- 注意: 正規分布なので稀に負の値が出ることがある(GREATEST(1, ...) でクリップする)

SELECT
    LEVEL AS id,
    GREATEST(10000, ROUND(50000 + 10000 * DBMS_RANDOM.NORMAL)) AS salary
FROM DUAL
CONNECT BY LEVEL <= 100;

DBMS_RANDOM.SEED でシードを設定する

DBMS_RANDOM.SEED を使ってシード値を設定すると、同じシードから同じ乱数列が生成されます。テストの再現性を確保したいとき・ユニットテストで期待値を固定したいときに使います。

SEED でシードを設定して再現性のある乱数を生成する
-- シードを整数で設定する
DBMS_RANDOM.SEED(42);   -- 同じシードを使えば毎回同じ乱数列が生成される

-- シードを文字列で設定することもできる
DBMS_RANDOM.SEED('my_test_seed_2024');

-- シード設定後の乱数生成
DECLARE
BEGIN
    DBMS_RANDOM.SEED(100);
    DBMS_OUTPUT.PUT_LINE(ROUND(DBMS_RANDOM.VALUE, 4));  -- 常に同じ値
    DBMS_OUTPUT.PUT_LINE(ROUND(DBMS_RANDOM.VALUE, 4));  -- 常に同じ値
    DBMS_OUTPUT.PUT_LINE(ROUND(DBMS_RANDOM.VALUE, 4));  -- 常に同じ値
END;
/
-- 同じシード(100)を使うと毎回同じ3つの数が出力される

-- INITIALIZE / TERMINATE (使い方)
-- DBMS_RANDOM.INITIALIZE(seed): 旧 API(SEED と同等)
-- DBMS_RANDOM.TERMINATE: 使用終了の通知(現在は実質的に何もしない)

ORDER BY DBMS_RANDOM.VALUE でランダムサンプリングする

ランダムに行を取得するサンプリングパターン
-- テーブルからランダムに10行を取得する(小〜中規模テーブル向け)
SELECT * FROM employees
ORDER BY DBMS_RANDOM.VALUE
FETCH FIRST 10 ROWS ONLY;
-- 注意: 全件ソートが発生するため大規模テーブルでは重い

-- SAMPLE 句でランダムサンプリングする(大規模テーブル向け)
-- SAMPLE(n): 全体の n % の行をランダムに取得する(近似)
SELECT * FROM sales
SAMPLE(10);   -- 約 10 % の行をサンプリングする
-- SAMPLE はブロックレベルのサンプリングで ORDER BY より高速

-- SAMPLE BLOCK(n): ブロック単位でサンプリングする(さらに高速)
SELECT * FROM sales SAMPLE BLOCK(5);  -- 約 5 % のブロックを取得

-- ランダムなグループに振り分ける(A/B テスト割り当て)
SELECT
    customer_id,
    CASE TRUNC(DBMS_RANDOM.VALUE(0, 2))
        WHEN 0 THEN 'GROUP_A'
        ELSE        'GROUP_B'
    END AS test_group
FROM customers;

-- ランダムな順序でレコードを更新する(ローリング更新のランダム化)
UPDATE employees
SET bonus_paid = 'Y'
WHERE ROWNUM <= 100
  AND bonus_paid = 'N'
ORDER BY DBMS_RANDOM.VALUE;   -- Oracle 11g 以降で ORDER BY + DML が使える(WHERE の前)
-- 注意: DML での ORDER BY + DBMS_RANDOM は特定バージョンで制限あり。サブクエリで代用する場合も

まとめ

  • DBMS_RANDOM.VALUE:0 以上 1 未満の乱数を返す。VALUE(low, high) で範囲指定可。TRUNC で整数に変換する
  • DBMS_RANDOM.STRING(opt, len):opt で文字種(U: 大文字 / L: 小文字 / A: 大小混合 / X: 英数字 / P: 印字可能 ASCII)、len で文字数を指定する
  • DBMS_RANDOM.NORMAL:平均 0・標準偏差 1 の正規分布乱数を返す。任意の分布は mean + stddev * NORMAL で変換する
  • DBMS_RANDOM.SEED:シードを設定することで再現性のある乱数列を生成できる。テストデータの固定に使う
  • ORDER BY DBMS_RANDOM.VALUE:小規模テーブルのランダム取得に使う。大規模テーブルには SAMPLE 句の方が高速
  • CONNECT BY LEVEL:DUAL と組み合わせてテストデータを大量生成できる

テストデータの大量生成に FORALL / BULK COLLECT を活用する方法は PL/SQL コレクション完全ガイドを参照してください。UTL_FILE でテストデータをファイルに書き出す方法は UTL_FILE 完全ガイドも参照してください。