I'm trying to generate a Random String using PL/SQL with some restricted letters, because i want to avoid letters like O, o, 0, etc. I heard that this task can be achievable using the listagg function available in oracle 11g. But i want to achieve this using Oracle 9i as we are using this in our environment. Any suggestions will be appreciated.

有帮助吗?

解决方案 2

Riffing off A.B.Cade's answer (it's getting a bit too far away from the original to keep in comments):

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 Fiddle

The inner select is putting each character in the string of values into a random order; the next level uses first_value() and distinct to pick whichever it sees first of an uppercase and lowercase pair (a/A) so you don't get repetition even ignoring case; that's then restricted to the first 10, 11 or 12 (distinct) rows; and finally it uses the same xmlagg call to turn those rows into a single string.

其他提示

Try using DBMS_RANDOM package to generate random strings.

Ex : dbms_random.string('x',10) gives uppercase alphanumeric character string of length 10.

But you cant exclude specific characters. You will have to use TRANSLATE or REPLACE functions to remove the unwanted characters.

One of the approaches would be creating a user-defined aggregate function that mimic listagg function's behavior. Here is an example:

  1. Our user-defined aggregate function:

     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
    

If you plan to work with strings that are more then 4000 in length you can use CLOB datatype instead of varchar2. Now, you can create an additional function that will generate a random string for you using that str_agg aggregate function. As you want to exclude some characters from the resulting string, I think it would be better to provide a set of characters from which the desired string will be generated.

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

And here is how it works:

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
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;
/

Without directly repeating of the same letters

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;
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top