PL/SQL生成1-3亿随机数分布不均问题咨询
解决Oracle PL/SQL生成1-3亿随机数位数分布不均的问题
问题原因
你用的floor(dbms_random.value(1, 300000000))是在数值范围上均匀随机采样,但不同位数对应的数值区间大小差异极大:
- 1位数仅包含1-9(共9个数)
- 2位数是10-99(90个数)
- ...
- 8位数是10000000-99999999(9000万个)
- 9位数是100000000-300000000(2亿个)
数值区间越大,被采样到的概率越高,所以结果自然集中在8、9位数,低位数几乎不会出现。
解决方案:按位数区间均匀采样
要生成包含各位数的随机数,需要先随机选择位数(1-9),再在对应位数的数值范围内生成随机数,确保每个位数区间被选中的概率均等。
方案1:随机选择位数生成(各位数概率均等)
以下PL/SQL代码循环生成50个随机数,每次先随机选1-9的位数,再生成对应区间的数:
DECLARE v_digit NUMBER; v_random_num NUMBER; BEGIN FOR i IN 1..50 LOOP -- 随机选取1-9的位数 v_digit := FLOOR(DBMS_RANDOM.VALUE(1, 10)); CASE v_digit WHEN 1 THEN v_random_num := FLOOR(DBMS_RANDOM.VALUE(1, 10)); WHEN 2 THEN v_random_num := FLOOR(DBMS_RANDOM.VALUE(10, 100)); WHEN 3 THEN v_random_num := FLOOR(DBMS_RANDOM.VALUE(100, 1000)); WHEN 4 THEN v_random_num := FLOOR(DBMS_RANDOM.VALUE(1000, 10000)); WHEN 5 THEN v_random_num := FLOOR(DBMS_RANDOM.VALUE(10000, 100000)); WHEN 6 THEN v_random_num := FLOOR(DBMS_RANDOM.VALUE(100000, 1000000)); WHEN 7 THEN v_random_num := FLOOR(DBMS_RANDOM.VALUE(1000000, 10000000)); WHEN 8 THEN v_random_num := FLOOR(DBMS_RANDOM.VALUE(10000000, 100000000)); WHEN 9 THEN v_random_num := FLOOR(DBMS_RANDOM.VALUE(100000000, 300000001)); -- 包含3亿 END CASE; DBMS_OUTPUT.PUT_LINE(v_random_num); END LOOP; END; /
方案2:精准控制各位数数量
如果需要确保每个位数的数都有固定数量(比如1-9位各至少5个),可以先分配数量再生成:
DECLARE TYPE digit_count_type IS TABLE OF NUMBER INDEX BY PLS_INTEGER; v_digit_counts digit_count_type; v_digit NUMBER; v_random_num NUMBER; v_total_num CONSTANT NUMBER := 50; BEGIN -- 初始化:1-9位各分配5个,共45个,剩余5个随机分配 FOR d IN 1..9 LOOP v_digit_counts(d) := 5; END LOOP; -- 分配剩余的5个名额 FOR i IN 1..(v_total_num - 45) LOOP v_digit := FLOOR(DBMS_RANDOM.VALUE(1, 10)); v_digit_counts(v_digit) := v_digit_counts(v_digit) + 1; END LOOP; -- 按分配数量生成随机数 FOR d IN 1..9 LOOP FOR j IN 1..v_digit_counts(d) LOOP CASE d WHEN 1 THEN v_random_num := FLOOR(DBMS_RANDOM.VALUE(1, 10)); WHEN 2 THEN v_random_num := FLOOR(DBMS_RANDOM.VALUE(10, 100)); WHEN 3 THEN v_random_num := FLOOR(DBMS_RANDOM.VALUE(100, 1000)); WHEN 4 THEN v_random_num := FLOOR(DBMS_RANDOM.VALUE(1000, 10000)); WHEN 5 THEN v_random_num := FLOOR(DBMS_RANDOM.VALUE(10000, 100000)); WHEN 6 THEN v_random_num := FLOOR(DBMS_RANDOM.VALUE(100000, 1000000)); WHEN 7 THEN v_random_num := FLOOR(DBMS_RANDOM.VALUE(1000000, 10000000)); WHEN 8 THEN v_random_num := FLOOR(DBMS_RANDOM.VALUE(10000000, 100000000)); WHEN 9 THEN v_random_num := FLOOR(DBMS_RANDOM.VALUE(100000000, 300000001)); END CASE; DBMS_OUTPUT.PUT_LINE(v_random_num); END LOOP; END LOOP; END; /
注意事项
- 方案1中,虽然各位数概率均等,但仍可能出现某位数暂时没出现的情况(概率极低),如果需要绝对保证各位数都有,优先用方案2。
- 9位数的上限是3亿,所以对应的区间是
100000000到300000001(因为dbms_random.value的右边界是开区间,所以要写300000001才能包含300000000)。
内容的提问来源于stack exchange,提问作者UserU95
相关产品推荐
相关产品推荐

