Reputation: 61
I have tried using the noorder
clause in oracle SQL but still I am getting the generated sequence in ascending order.
Below is the sequence creation script
create sequence otp_seq
minvalue 100000 maxvalue 999999
increment by 1 nocycle noorder;
When I run the below command repeatedly:
select otp_seq.nextval from dual;
it gives the values only in the sequence:
100000
100001
100002
What I want is values to be generated randomly from the given domain i.e. between the minValue and maxValue and should be unique.
Upvotes: 2
Views: 9392
Reputation: 146239
Regarding the NOORDER
clause, the documentation says:
"Specify
NOORDER
if you do not want to guarantee sequence numbers are generated in order of request. "
The key word is guarantee. NOORDER
does not promise randomness, it means NEXTVAL
may generate numbers out of order. This is primarily of concern in RAC environments where each node has a cache of sequence numbers; in these scenarios NOORDER
means we cannot infer sequence of NEXTVAL
requests from the sequence of given values i.e. we cannot use those numbers to sort records in order of creation.
On to your requirements.
Your requirements are contradictory. Randomness means unpredictability. Uniqueness means predictability.
You cannot implement this with a sequence but you could build you own thing like this:
create table pseudo_sequence (
used varchar2(1) default 'N' not null
, id number not null
, next_val number not null
, primary key (used, id)
)
organization index
/
Note the Index Only Table syntax. The next trick is to populate the table randomly.
insert into pseudo_sequence (id, next_val)
with nbr as (
select level + 99999 as nx
from dual
connect by level <= 900000
order by dbms_random.value
)
select rownum, nx from nbr
/
We need the ID column to preserve the random distribution of NEXT_VAL across the table; without it the index will impose an order, and we want to avoid sorting every time we do a query.
Next we build a query to get a next value from the table, and mark it as used:
create or replace function random_nextval
return number
is
pragma autonomous_transaction;
cursor ps is
select next_val
from pseudo_sequence
where used = 'N'
and rownum = 1
for update of used skip locked;
return_value number;
begin
open ps;
fetch ps into return_value;
update pseudo_sequence
set used = 'Y'
where current of ps;
close ps;
commit;
return return_value;
end;
/
And here is how it works:
SQL> select random_nextval from dual
2 connect by level <= 5
3 /
RANDOM_NEXTVAL
--------------
216000
625803
806843
997165
989896
SQL> select * from pseudo_sequence where used='Y'
2 /
U ID NEXT_VAL
- ---------- ----------
Y 1 216000
Y 2 625803
Y 3 806843
Y 4 997165
Y 5 989896
SQL> select random_nextval from dual
2 connect by level <= 5
3 /
RANDOM_NEXTVAL
--------------
346547
911900
392290
712611
760088
SQL>
Of course, we could argue this is not random as the next value is predictable by looking at the underlying table but perhaps it's good enough for your needs. I won't make any promises about scalability in a multi-user environment, but given your numberspace is a scant 900,000 values I figure that's not a major concern anyway.
Upvotes: 3