【问题标题】:Generate Upper and Lowercase Alphanumeric Random String in Oracle在Oracle中生成大小写字母数字随机字符串
【发布时间】:2013-11-11 03:00:41
【问题描述】:

如何从oracle生成大小写字母数字随机字符串?

我已经使用select DBMS_RANDOM.STRING('x', 10) from dual 生成大写字母数字字符

select DBMS_RANDOM.STRING('a', 10) from dual 生成大小写字母字符

...但我想要一个同时处理大小写、字母和数字字符的函数。

此外,如果您能想出 Oracle 未实施此功能的充分理由,还可以加分(或只是点赞)?

【问题讨论】:

    标签: oracle


    【解决方案1】:

    您可以制作自己的功能。这是一种选择:

    create or replace function random_str(v_length number) return varchar2 is
        my_str varchar2(4000);
    begin
        for i in 1..v_length loop
            my_str := my_str || dbms_random.string(
                case when dbms_random.value(0, 1) < 0.5 then 'l' else 'x' end, 1);
        end loop;
        return my_str;
    end;
    /
    
    select random_str(30) from dual;
    
    RANDOM_STR(30)
    --------------------------------------------------------------------------------
    pAAHjlh49oZ2xuRqVatd0m1Pv8XuGs
    

    您可能需要调整 0.5 以考虑不同的池大小 - l 为 26,x 为 36。 (.419354839?)。您也可以使用 value() 并传入字符值的开始和结束范围,但这将是特定于字符集的。

    至于为什么……甲骨文需要理​​由吗? x 的使用可能表明它最初是十六进制并被扩展为包括所有大写字母,而他们却没有想到同时添加混合大小写的版本。

    【讨论】:

    • 调用 dbms_random 的次数会减少,并且可以避免在 case 表达式中选择阈值的需要,方法是使用它来获取要附加的下一个字符: substr( 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789', mod (abs(dbms_random.random), 62)+1, 1)
    • @Janek 我修改了 Alex 的代码以使用您的评论。很遗憾,我无法接受你的两个答案。
    【解决方案2】:

    试试这个,

    with
      r as (
        select
          level lvl,
          substr(
            'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789',
            mod(abs(dbms_random.random), 62)+1, 1) a
        from dual connect by level <= 10
      )
    select
      replace(sys_connect_by_path(a, '/'), '/') random_string
    from r
    where lvl = 1
    start with lvl = 10
    connect by lvl + 1 = prior lvl
    ;
    

    输出,

    FOps2k0Pcy
    

    【讨论】:

    • 我的解决方案表明,这可以在没有 PL/SQL 的情况下完成,但如果我预计不止一次需要这样的随机字符串,我会使用 PL/SQL 函数,如@Alex Poole 的回答所示。
    • 我认为这也可能与 SQL 优化发生冲突,这可能会导致随机函数每行调用少于一次。请参阅 asktom.oracle.com/pls/apex/… 上的 AskTom 讨论。也许可以通过在关卡中播种随机调用来防止这种情况。
    【解决方案3】:
    CREATE OR REPLACE FUNCTION fn_mac RETURN varchar2 IS
       w number :=0;
       a varchar2(10);
       b varchar2(50);
       x number :=0;
       y number :=0;
       z number :=0;
       c varchar2(50);
       result varchar2(20);
      BEGIN
      select round(dbms_random.value(1,99))into w from dual;
      SELECT upper(dbms_random.string('A', 2))into a FROM dual;
      SELECT round(dbms_random.value(1, 9)) into x FROM dual;
      SELECT upper(dbms_random.string('A', 4)) into b FROM dual;
      SELECT round(dbms_random.value(1, 9)) into y FROM dual;
      SELECT upper(dbms_random.string('A', 1)) into c FROM dual;
      SELECT round(dbms_random.value(1, 9)) into z FROM dual;
       result :=(  to_char(w) ||a|| to_char(x)|| b|| to_char(y)|| c ||to_char(z)) ;
       DBMS_OUTPUT.PUT_LINE( 'Result ::' || result);
       RETURN result ;
      END fn_mac;
      /
    

    【讨论】:

    • upper(dbms_random.string('A', 2)) 与 dbms_random.string('U', 2) 相同
    • 选择种子值:'a','A' 仅字母字符(混合大小写) 'l','L' 仅小写字母字符 'p','P' 任何可打印字符 'u ','U' 仅大写字母字符 'x','X' 任何字母数字字符(大写)
    【解决方案4】:

    这个怎么样:

    select translate(dbms_random.string('a', 20), 'abcXYZ', '158249') from dual;
    

    或者,甚至更随机;)

    select translate(dbms_random.string('a', 20), dbms_random.string('a',6), trunc(dbms_random.value(100000,999999))) from dual;
    

    【讨论】:

      【解决方案5】:

      您可以从 Printable 选项开始,然后去掉所有非字母数字:

      select SUBSTR(
               TRANSLATE(dbms_random.string('p',100)
                  ,'A`~!@#$%^&*()-=_+[]\{}|;'':",./<>?'
                  ,'A')
             ,1,10) from dual;
      

      (注意:很少,这将返回少于 10 个字符)

      或者,将违规字符映射到其他字母和数字(尽管这会大大降低随机性):

      select TRANSLATE(dbms_random.string('p',10)
                  ,'A`~!@#$%^&*()-=_+[]\{}|;'':",./<>? '
                  ,'A' || dbms_random.string('x',33)) from dual;
      

      顺便说一句,这个问题很好。

      现在,我的奖励积分:

      Oracle 没有实现这一点的原因是没有人要求它,而且它可能不是高优先级。

      【讨论】:

      • 因为Oracle 很懒呢? ;)
      【解决方案6】:
      create or replace procedure r1
          is
          v_1 varchar2(1);
          v_2 varchar2(10);
          begin 
          for inner_c in 1..10
          loop
          select  substr('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789',mod(abs(dbms_random.random), 62)+1, 1) into v_1 from dual;
          v_2 := v_2 || v_1;
          end loop;
          dbms_output.put_line(v_2);
          end;
          /
      

      【讨论】:

        猜你喜欢
        • 2011-08-23
        • 2010-09-08
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-07-26
        相关资源
        最近更新 更多