【问题标题】:Create table from loop output Oracle SQL从循环输出 Oracle SQL 创建表
【发布时间】:2019-03-03 12:46:34
【问题描述】:

我需要根据 175 个人口统计选项从包含约 500 万个观察值的表中随机抽取一个样本。人口统计表类似于这种形式:

1 40 4%
2 30 3%
3 30 3%
- -
174 2 .02%
175 1 .01%

基本上,我需要从 5M 行表中随机抽样的相同人口统计细分。对于每个人口统计,我需要从较大的表格中获取相同样本,但观察次数是 5 倍(例如:对于人口统计 1,我需要 200 个随机样本)。

SELECT  *
FROM    (
        SELECT  *
        FROM    my_table
        ORDER BY
                dbms_random.value
        )
WHERE rownum <= 100;

我之前使用过这种语法来获取随机样本,但是有什么方法可以将其修改为循环并从现有表中替换变量名?我将尝试将我需要的逻辑封装在伪代码中:

for (each demographic_COLUMN in TABLE1) 
    select random(5*num_obs_COLUMN in TABLE1) from ID_COLUMN in TABLE2
/*somehow join the results of each step in the loop into one giant column of IDs */

【问题讨论】:

  • 你有一张还是两张?我发现很难遵循数据结构。 “与这些百分比相关的数值”是什么?
  • @GordonLinoff 我有两个。第一个表有人口统计、百分比、观察次数(“数字值”)——这个表有 175 行。第二个表是我要从中抽取随机样本的,大约 500 万行
  • @GordonLinoff 我编辑了我的问题以试图澄清。你不必完全理解它——主要的是我不知道从哪里开始循环来自不同表的列并聚合结果。
  • edit 提出您的问题并为相关表格添加create table 语句。您的示例数据仅显示两列(一列是 PK?)
  • 我仍然不清楚循环与需求有什么关系(循环遍历列?)。为什么要按dbms_random.value 订购而不是使用普通的sample 子句?一些例子会有很大帮助。

标签: sql oracle loops plsql


【解决方案1】:

您可以加入您的表格(假设两者中都存在 1-175 人口统计值,或者有一个等效的列可以加入),例如:

select id
from (
  select d.demographic, d.percentage, t.id,
    row_number() over (partition by d.demographic order by dbms_random.value) as rn
  from demographics d
  join my_table t on t.demographic = d.demographic
)
where rn <= 5 * percentage

主表中的每一行在其人口统计中被赋予一个随机伪行号(通过分析row_number())。然后,外部查询使用相关百分比来选择要为每个人口统计返回多少这些随机排序的行。

我不确定我是否理解你实际上是如何准确地选择你想要的每个,所以可能需要调整。

在 CTE 中使用较小样本并匹配较小匹配条件的演示:

-- CTEs for sample data
with my_table (id, demographic) as (
  select level, mod(level, 175) + 1 from dual connect by level <= 175000
),
demographics (demographic, percentage, str) as (
            select 1, 40, '4%' from dual
  union all select 2, 30, '3%' from dual
  union all select 3, 30, '3%' from dual
  -- ...
  union all select 174, 2, '.02%' from dual
  union all select 175, 1, '.01%' from dual
)
-- actual query
select demographic, percentage, id, rn
from (
  select d.demographic, d.percentage, t.id,
    row_number() over (partition by d.demographic order by dbms_random.value) as rn
  from demographics d
  join my_table t on t.demographic = d.demographic
)
where rn <= 5 * percentage;

DEMOGRAPHIC PERCENTAGE         ID         RN
----------- ---------- ---------- ----------
          1         40      94150          1
          1         40      36925          2
          1         40     154000          3
          1         40      82425          4
...
          1         40     154350        199
          1         40     126175        200
          2         30      36051          1
          2         30       1051          2
          2         30     100451          3
          2         30      18026        149
          2         30     151726        150
          3         30     125302          1
          3         30     152252          2
          3         30     114452          3
...
          3         30     104652        149
          3         30      70527        150
        174          2      35698          1
        174          2      67548          2
        174          2     114798          3
...
        174          2      70698          9
        174          2      30973         10
        175          1     139649          1
        175          1     156974          2
        175          1     145774          3
        175          1      97124          4
        175          1      40074          5

(您只需要 ID,但我将其他列包括在内);或更简洁:

with my_table (id, demographic) as (
  select level, mod(level, 175) + 1 from dual connect by level <= 175000
),
demographics (demographic, percentage, str) as (
            select 1, 40, '4%' from dual
  union all select 2, 30, '3%' from dual
  union all select 3, 30, '3%' from dual
  -- ...
  union all select 174, 2, '.02%' from dual
  union all select 175, 1, '.01%' from dual
)
select demographic, percentage, count(id) as ids, min(id) as min_id, max(id) as max_id
from (
  select d.demographic, d.percentage, t.id,
    row_number() over (partition by d.demographic order by dbms_random.value) as rn
  from demographics d
  join my_table t on t.demographic = d.demographic
)
where rn <= 5 * percentage
group by demographic, percentage
order by demographic;

DEMOGRAPHIC PERCENTAGE        IDS     MIN_ID     MAX_ID
----------- ---------- ---------- ---------- ----------
          1         40        200        175     174825
          2         30        150          1     174126
          3         30        150       2452     174477
        174          2         10      23448     146648
        175          1          5      19074     118649

db<>fiddle

【讨论】:

  • 第一个代码块只需替换我的列/表名称就可以很好地工作,感谢您理解我要问的问题!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-04-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-10-06
相关资源
最近更新 更多