我最终选择了Gordon Linoff 的第一种方法suggested,并进行了一些小的修改。我保留了最初的想法,但还引入了几个额外的子查询来指定组内所需的记录分布,并构建了一个矩阵,其中包含每组所需的记录数。还有一个全局参数部分,其中包含指定总记录数的唯一参数。
查询产生了非常有用的结果:
with
people as (
select id,
floor(months_between(sysdate, date_birth)/12) age,
195 - least(floor(months_between(sysdate, date_birth)/12), 50) height,
decode(sex, 1, 'male', 'female') gender
from my_people_table
where date_birth is not null and rownum < 100000
),
params as ( /* Global params */
select 100 rec_count -- total record count
from dual
),
age_groups as ( /* distribution by height */
select 'group 1' age_group, .7 prc from dual union
select 'group 2' age_group, .3 prc from dual
),
height_groups as ( /* distribution by height */
select 'group 1' height_group, .6 prc from dual union
select 'group 2' height_group, .4 prc from dual
),
genders as ( /* distribution by gender */
select 'male' gender, .6 prc from dual union
select 'female' gender, .4 prc from dual
),
mx as ( /* a matrix with record counts per group */
select age_group, height_group, gender,
ceil(
age_groups.prc *
height_groups.prc *
genders.prc *
rec_count
) rec_count
from age_groups, height_groups, genders, params
),
xpeople as ( /* Minor transformations - groups and group counters */
select p.*,
row_number() over (
partition by age_group, height_group, gender
order by age_group, height_group, gender
) rec_num
from (
select people.*,
case
when age <= 40 then 'group 1'
else 'group 2'
end age_group,
case
when height <= 180 then 'group 1'
else 'group 2'
end height_group
from people
) p
)
/* the resulting query uses the matrix to filter the records */
select xpeople.*
from xpeople join mx
on xpeople.age_group = mx.age_group
and xpeople.height_group = mx.height_group
and xpeople.gender = mx.gender
and xpeople.rec_num <= mx.rec_count
感谢您的帮助!