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 完全ガイドも参照してください。