【问题标题】:adding column in Oracle SQL table that is random sample from another column/table在 Oracle SQL 表中添加列,该列是来自另一列/表的随机样本
【发布时间】:2018-09-09 21:11:12
【问题描述】:

我在 SQL 中有一个预先存在的表 (MYORIGTABLE),我想添加一个列,该列是另一个表 (RANDNUM10) 中列的随机样本。另一个表是我预先确定并希望从中采样的 1 列随机数样本;列名是 RANDVAL。我已经尝试了以下

select (select randval from (SELECT randval FROM RANDNUM10 ORDER BY dbms_random.value) where rownum=1) as mynum from MYORIGTABLE

但不幸的是,这只是给了我从 RANDNUM10 中采样的相同随机数,该随机数在整个 MYORIGTABLE 长度中重复。如何执行采样以便 MYORIGTABLE 的每一行都获得一个新生成的样本?

谢谢, 克里斯蒂

【问题讨论】:

  • 当你说你想添加一列时,你到底是什么意思? @Littlefoot 的回答中的 UPDATE 声明可能有效,而 SELECT 可能无效。
  • 您需要更清楚地解释您要做什么。您说过要添加一列,但随后显示了一个 SELECT 语句,您只需从表中的单个列中选择值。添加列是什么意思 - 在哪里?在MYORIGTABLE 表中?还是仅在 SELECT 查询的结果集中(显然也会从 MYORIGTABLE 中选择其他列)?
  • 另外,当您说“随机样本”时,是替换还是不替换?如果您不知道这意味着什么:如果随机数是 1、2、3、4、5、6、7 - 那么“带替换的三个数字的随机样本”可能是 (3, 4, 3)。 WITHOUT REPLACEMENT 不允许重复。如果您的要求是无替换,则必须保证第二个表的行数比第一个多 - 是这样吗?

标签: sql oracle random sample


【解决方案1】:

这是您的查询:

select (select randval
        from (SELECT randval 
              FROM  RANDNUM10
              ORDER BY dbms_random.value
             ) 
        where rownum = 1
      ) as mynum
from MYORIGTABLE;

数据库优化器的一个常见问题——在这种情况下——它优化了对子查询的多次调用。它最终用一个调用替换了子查询。

解决此问题的一种方法是使用相关子查询。为此,我建议删除一层嵌套:

select (select max(randval) keep (dense_rank first order by dbms_rnadom.value)
        from randnum10
        where myorigtable.id is not null -- or whatever
      ) as mynum
from MYORIGTABLE;

我认为这会起作用,因此子查询会被调用 10 次,尽管可能需要更复杂的关联子句。

【讨论】:

  • 但是如果你尝试这样的事情,它可能会:where myorigtable.id > 0(代替is not null
  • 无论如何都是错误的方法 - 例如,如果基表有 200,000 行,而随机数表有 300 万行,则相关子查询将需要生成 300 万个随机值并选择第一个, 200,000 次。效率极低。
【解决方案2】:

大概是这样的吧?

测试用例:

SQL> create table myorigtable (id number);

Table created.

SQL> create table randnum10 (randval number);

Table created.

SQL> insert into myorigtable select level from dual connect by level <= 10;

10 rows created.

SQL> insert into randnum10 select round(dbms_random.value(1, 100)) from dual connect by level <= 10;

10 rows created.

SQL> alter table myorigtable add randval number;

Table altered.

更新:

SQL> update myorigtable m set
  2    m.randval = (select x.randval
  3                 from (select randval, row_number() over (order by randval) rn
  4                       from randnum10
  5                      ) x
  6                 where x.rn = m.id
  7                );

10 rows updated.

SQL> select * from myorigtable;

        ID    RANDVAL
---------- ----------
         1          5
         2         18
         3         29
         4         31
         5         31
         6         62
         7         66
         8         87
         9         94
        10         98

10 rows selected.

SQL>

【讨论】:

  • 这是正确的方法,但它取决于基表的 ID 列的值为 1、2、3、...、N。在现实生活中可能是这样,也可能不是- 但这并不难解决。更大的问题是您没有从随机数表中分配值的“随机样本” - 您正在分配 N 个最小值。这也可以通过更多的工作来解决。
【解决方案3】:

这是一种方法。我假设您的RANDNUM10 表有很多行(比MYORIGTABLE 更多的行),您想在不替换的情况下对随机数进行采样(从RANDNUM10 中选择 DISTINCT 随机值)-因此随机数表有足够的行-在至少与MYORIGTABLE 一样多 - 您需要将该列添加到SELECT 查询的结果集中,而不是添加到存储的表中。 (如果您需要将结果存储在附加列中,则必须先添加该列(如果该列不存在),然后在 UPDATE 语句中使用下面的 SELECT 查询。)

策略很简单:将任意行号关联到较小的表(值为 1、2、...、N,其中 N 是行数),并将随机行号关联到随机数表中的行。两者都可以通过ROW_NUMBER()... 完成——第一个可以通过NULL 订购,因为无论如何我们需要的所有随机性都来自另一个表的行号。然后 JOIN 两个表上的行号,从而添加到两个表中。

为了说明,我创建了MYORIGTABLE 作为SCOTT.EMP 的副本,只从该表中选择了几列。这是查询的样子,输出使用MYORIGTABLE

设置

create table myorigtable as select empno, ename, job, deptno from scott.emp;

create table randnum10 ( randval ) as
  select dbms_random.value() from dual connect by level <= 1000;

查询与输出

select a.empno, a.ename, a.job, a.deptno, b.randval
from   (
         select empno, ename, job, deptno, row_number() over (order by null) as rn
         from   myorigtable
       ) a
       inner join
       (
         select randval, row_number() over (order by dbms_random.value()) as rn
         from   randnum10
       ) b
       on a.rn = b.rn
;

EMPNO  ENAME       JOB        DEPTNO     RANDVAL
-----  ----------  --------- -------  ----------
 7369  SMITH       CLERK          20  .991998901
 7499  ALLEN       SALESMAN       30  .448133242
 7521  WARD        SALESMAN       30  .136242235
 7566  JONES       MANAGER        20  .443347421
 7654  MARTIN      SALESMAN       30  .836931008
 7698  BLAKE       MANAGER        30  .361437867
 7782  CLARK       MANAGER        10  .433786615
 7788  SCOTT       ANALYST        20  .285173363
 7839  KING        PRESIDENT      10  .063840361
 7844  TURNER      SALESMAN       30  .825888729
 7876  ADAMS       CLERK          20  .818415041
 7900  JAMES       CLERK          30  .150180080
 7902  FORD        ANALYST        20  .442389099
 7934  MILLER      CLERK          10  .086995415

【讨论】:

    猜你喜欢
    • 2014-11-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-06-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多