随机选择一行

mzillmmw  于 2021-07-26  发布在  Java
关注(0)|答案(2)|浏览(372)

我有表s1,它有3行。如何从s1中随机选取一行并将其对应的值插入d1。
我不想要硬编码的解决方案。rownum()是否可以用于dbms\u random?假设d1中有10行。
请举个例子。

Create table s1(
val NUMBER(4)
);

 INSERT into s1
(val) VALUES (30);

 INSERT into s1
 (val) VALUES (40);

 INSERT into s1
 (val) VALUES (50);

Create table d1(
val NUMBER(4)
 );
q3qa4bjr

q3qa4bjr1#

您可以按随机值排序并选择一行:

insert into d1 (val)
    select val
    from (select s1.*
          from s1
          order by dbms_random.value
         ) s1
    where rownum = 1;

在oracle 12c+中,您不需要子查询:

insert into d1 (val)
    select val
    from s1
    order by dbms_random.value
    fetch first 1 row only;

注意:这假设你的意思是随机的,而不是任意的。随机行意味着表中的任何行在任何给定的查询调用中被选择的几率都是相等的。

yrdbyhpb

yrdbyhpb2#

在大表的情况下,按dbms\u random.value排序的标准方法是无效的,因为您需要扫描整个表,而dbms\u random.value的函数非常慢,需要上下文切换。对于这种情况,有两种众所周知的方法:
使用 sample 条款:
https://docs.oracle.com/en/database/oracle/oracle-database/19/sqlrf/select.html#guid-cfa006ca-6ff1-4972-821e-6996142a51c6
https://docs.oracle.com/en/database/oracle/oracle-database/19/sqlrf/select.html#guid-cfa006ca-6ff1-4972-821e-6996142a51c6
例如:

select *
from s1 sample block(1)
order by dbms_random.value
fetch first 1 rows only

即得到所有块的1%,然后随机排序,只返回1行。
如果在正态分布的列上有索引/主键,则可以获取最小值和最大值,获取此范围内的随机值,并获取值大于或等于随机生成值的第一行。
例子:

--big table with 1 mln rows with primary key on ID with normal distribution:
Create table s1(id primary key,padding) as 
   select level, rpad('x',100,'x')
   from dual 
   connect by level<=1e6;

select *
from s1 
where id>=(select 
              dbms_random.value(
                 (select min(id) from s1),
                 (select max(id) from s1) 
              )
           from dual)
order by id
fetch first 1 rows only;

更新
第三个变量:获取随机表块,生成rowid,并根据此rowid从表中获取行:

select * 
from s1
where rowid = (
   select
      DBMS_ROWID.ROWID_CREATE (
         1, 
         objd,
         file#,
         block#,
         1) 
   from    
      (
      select/*+ rule */ file#,block#,objd
      from v$bh b
      where b.objd in (select o.data_object_id from user_objects o where object_name='S1' /* table_name */)
      order by dbms_random.value
      fetch first 1 rows only
      )
);

相关问题