Oracle FAQ Your Portal to the Oracle Knowledge Grid
HOME | ASK QUESTION | ADD INFO | SEARCH | E-MAIL US
 

Home -> Community -> Usenet -> c.d.o.misc -> Re: Random selection of records in PL/SQL

Re: Random selection of records in PL/SQL

From: Brian Ewins <Brian.Ewins_at_gssec.bt.co.uk>
Date: 1997/06/11
Message-ID: <339E95B6.5A9A@gssec.bt.co.uk>

doid wrote:

> 
> HShukla538 wrote:
> >
> > How can i select a true random record in pl/sql
> 

I've done this in the past using code like:

foo:=random.next_int(range)+offset;
select * into rec
from bar
where key>foo
and rownum=1;

(ie I have a numeric key in the table, I generate a random number based on the offset and range of the values of this key (offset=min(key), range=max(key)-min(key)).)

The random number generator I used varied; in one case I was doing this in perl, so I used its random number generator to help build the sql; in other cases I've used a random number generator I converted from one in Numerical Recipes in C (Oxford University Press). The generator was a linear congruential generator with shuffling and had a pretty long period, so was random enough for almost any purpose.

The code is included below - use it at your own risk. It's not as efficient as it could be, but I didn't want to spend much time on it, other than to get a working conversion.

	Hope this helps.
		Brian

=========================================BEGIN
set verify off
set feedback off

create or replace package random is

        --PRIVATE UTILITIES
        function get_persistent(id varchar2) return number;
        procedure set_persistent(id varchar2, value number);
end random;
/
show errors;
create or replace package body random is
                        if j<NTAB then 
                                set_persistent(to_char(j),idum1);
                        end if;
                end loop;
                set_persistent('iy',get_persistent('0'));
                set_persistent('idum1',idum1);
        end seed;

        function next_num return number is
                idum1 number;
                idum2 number;
                iy number;
                temp number;
                k number;
                j integer;
        begin
                -- restore the persisted values
                idum1:=get_persistent('idum1');
                idum2:=get_persistent('idum2');
                iy:=get_persistent('iy');

                --generator1 begins here.
                --uses Schrager's method for calculating
                --mod without overflow. Not really necessary
                --here; number's are much bigger than 32 bit.
                k:=floor(idum1/IQ1);
                idum1:=IA1*(idum1-k*IQ1)-k*IR1;
                if idum1<0 then 
                        idum1:=idum1+IM1;
                end if;

                -- second generator.
                k:=floor(idum2/IQ2);
                idum2:=IA2*(idum2-k*IQ2)-k*IR2;
                if idum2<0 then 
                        idum2:=idum2+IM2;
                end if;

                -- shuffle/combine generators
                j:=floor(iy/NDIV);
                iy:=get_persistent(to_char(j))-idum2;
                if (iy<1) then 
                        iy:=iy+IMM1;
                end if;

                -- before returning, set the new persistents...
                set_persistent(to_char(j),idum1);
                set_persistent('idum1',idum1);
                set_persistent('idum2',idum2);
                set_persistent('iy',iy);

                --prevent endpoints being returned
                temp := AM*iy;
                if temp>RNMX then 
                        temp:=RNMX;
                end if;

                return temp;
        end next_num;


-- maintain persistent storage
function get_persistent(id varchar2) return number is retval number; begin select value into retval from random_persist where id=get_persistent.id; return retval; end get_persistent; procedure set_persistent(id varchar2,value number) is small_string random_persist.id%type; begin small_string:=substr(id,1,length(small_string)); insert into random_persist (id,value) select small_string, set_persistent.value from dual where not exists ( select null from random_persist where id=small_string ); update random_persist set value=set_persistent.value where id=set_persistent.id; end set_persistent;
-- convenience function to return integers up to a specified
range. function next_int(max_int integer) return integer is begin return floor(next_num*max_int); end next_int;
-- return the random number as a base 26 number, with digits
-- as letters in the range a-z. This prevents the user seeing
-- both the internal representation and the full precision of
the
-- number, to increase security. 32-bit randoms will return
-- trailing 'AAA...' strings for more than about 10 chars.
function next_string(chars in integer) return varchar2 is next_letter integer; i integer; temp number; retval varchar2(32); begin retval:=''; temp:=next_num; for i in 1 .. chars loop next_letter:=floor(temp*26); temp:=(temp*26)-next_letter; retval:=concat(retval,CHR(next_letter+ASCII('a'))); end loop; return retval; end next_string;

end random;
/
show errors;
--
****====----                                              Brian Ewins. 
Fax: (44) 141 220 6100                          Tel: (44) 141 220 6121
 "It's time we face reality, my friends...
      We're not exactly rocket scientists." --Gary Larson ----====****
Received on Wed Jun 11 1997 - 00:00:00 CDT

Original text of this message

HOME | ASK QUESTION | ADD INFO | SEARCH | E-MAIL US