4

我正在尝试使用带有一些受限字母的 PL/SQL 生成随机字符串,因为我想避免使用 O、o、0 等字母。我听说可以使用 oracle 11g 中提供的 listagg 函数来完成此任务。但是我想使用 Oracle 9i 来实现这一点,因为我们在我们的环境中使用它。任何建议将不胜感激。

4

4 回答 4

3

尝试使用DBMS_RANDOM包生成随机字符串。

例如:dbms_random.string('x',10)给出长度为 10 的大写字母数字字符串。

但是你不能排除特定的字符。您必须使用TRANSLATEREPLACE函数来删除不需要的字符。

于 2013-06-05T07:40:01.087 回答
2

其中一种方法是创建一个用户定义的聚合函数来模仿listagg函数的行为。这是一个例子:

  1. 我们用户定义的聚合函数:

     SQL> create or replace type stragg as object (
       2  
       3      str  varchar2(4000),
       4  
       5      static function ODCIAggregateInitialize(sctx  in out stragg)
       6                      return number,
       7  
       8      member function ODCIAggregateIterate   (self  in out stragg,
       9                                              value in varchar2 )
      10                      return number,
      11  
      12      member function ODCIAggregateTerminate (self         in     stragg   ,
      13                                              return_value    out varchar2,
      14                                              flags        in number      )
      15                      return number,
      16  
      17      member function ODCIAggregateMerge(self in out stragg,
      18                                         ctx2 in stragg    )
      19                      return number
      20  )
      21  /
    
      Type created
    
      SQL> create or replace type body stragg is
       2  
       3      static function ODCIAggregateInitialize(sctx in out stragg)
       4          return number is
       5      begin
       6          sctx := stragg(null);
       7          return ODCIConst.Success;
       8      end;
       9  
      10      member function ODCIAggregateIterate(
      11        self in out stragg, value in varchar2)
      12          return number is
      13      begin
      14          str := str || value;
      15          return ODCIConst.Success;
      16      end;
      17  
      18      member function ODCIAggregateTerminate(self in stragg,
      19          return_value out varchar2, flags in number) return number is
      20      begin
      21          return_value := str;
      22          return ODCIConst.Success;
      23      end;
      24  
      25      member function ODCIAggregateMerge(self in out stragg,
      26          ctx2 in stragg) return number is
      27      begin
      28          str := str || ctx2.str;
      29          return ODCIConst.Success;
      30      end;
      31  end;
      32  /
    
      Type body created
    
      SQL> create or replace function str_agg (input varchar2) return varchar2
        2      parallel_enable aggregate using stragg;
        3  /
    
      Function created
    

如果您计划使用长度超过 4000 的字符串,则可以使用CLOBdatatype 而不是varchar2. str_agg现在,您可以创建一个附加函数,该函数将使用该聚合函数为您生成一个随机字符串。由于您想从结果字符串中排除某些字符,我认为最好提供一组字符,从中生成所需的字符串。

SQL> create or replace function Str_gen(p_CharSet varchar2, p_length number)
  2  return varchar2
  3  is
  4    l_res_str varchar2(4000);
  5  begin
  6   select str_agg(symbol)
  7     into l_res_str
  8     from ( select substr(p_CharSet, 
  9                          dbms_random.value(1, length(p_charset)), 1) as symbol
 10              from dual
 11           connect by level <= p_length
 12           order by dbms_random.value
 13           );
 14  
 15   return l_res_str;
 16  end;
 17  /

Function created

以下是它的工作原理:

SQL> select str_gen('abcdefghijklmnpqrstuvwxyzABCDEFGHIJKLMNPQRSTUVWXYZ123456789',11) as res
  2    from dual
  3  connect by level <= 11
  4  /

RES
--------------------------------------------------------------------------------
NBG5jK6G46G
fSrzmyq7ZLE
vdGE1dRXlah
1D2IsI54qzD
PhktBAh5rXu
JtRsarxFNiV
1sUGFpwmypQ
7giwfdV4I7s
I2WMhKzxvc2
NZpngmrq1gM
rFuZ8gSUDgL

11 rows selected
于 2013-06-05T07:30:56.027 回答
2

扯掉 ABCade 的答案(它离原版有点太远了,无法保留评论):

select xmlagg(xmlelement("r", ch)).extract('//text()').getstringval()
from
(
  select distinct first_value(ch) over (partition by lower(ch)) as ch
  from (
    select substr('abcdefghijklmnpqrstuvwxyzABCDEFGHIJKLMNPQRSTUVWXYZ123456789',
        level, 1) as ch
    from dual 
    connect by level <= 59
    order by dbms_random.value
  )
  where rownum <= dbms_random.value(10,13)
);

SQL小提琴

内部选择是将值字符串中的每个字符按随机顺序排列;下一个级别使用first_value()anddistinct选择它首先看到的大写和小写对(a/ A),这样即使忽略大小写也不会重复;然后限制为前 10、11 或 12 行(不同的);最后它使用相同的xmlagg调用将这些行转换为单个字符串。

于 2013-06-05T11:05:46.223 回答
1
create or replace function str_gen
( len in number)
return varchar2
as 
  str varchar2(4000);
  valid_chars constant varchar2(50) := 'abcdefghijklmnpqrstuvwxyz';  
begin
  for i in 1..len
  loop
    str := str || substr( valid_chars, dbms_random.value(1, length(valid_chars)), 1);
  end loop;
  return str;
end;
/

不直接重复相同的字母

create or replace function str_gen
( len in number)
return varchar2
as 
  str varchar2(4000);
  valid_chars constant varchar2(50) := 'abcdefghijklmnpqrstuvwxyz';  
  last_char varchar2(1);
  new_char  varchar2(1);
  chars_len       NUMBER;
  num             NUMBER;
begin
  chars_len := length(valid_chars);
  num := 0;
  if len > 0 then
    loop      
      new_char := substr( valid_chars, dbms_random.value(1, chars_len ), 1);

      if num = 0 then 
        str := new_char;
        num := num +1;
      elsif new_char != last_char
      then 
        str := str || new_char;
        num := num +1;
      end if;
      last_char := new_char;
      exit when num = len;
    end loop;
  end if;
  return str;
end;
/


select str_gen(11) from dual;
于 2013-06-05T08:22:58.670 回答