使用任意分布对结果进行排序

时间:2009-12-04 11:18:15

标签: sql postgresql

我的数据库中有很少的thousends作业,其列的值为“active”或“inactive”。大约5%的工作是“不活跃的”。每天添加工作(以数量为单位)。当现有作业被标记为“不活动”时,我们将比率保持准确(如果有太多的作业,则删除“非活动”作业)。

我需要以“非活动”作业均匀分布的方式对所有作业进行排序。最好每20个“活动”作业中就有一个应该是“非活动”作业(结果分为20个)。

我怎样才能实现这一目标?数据库是Postgresql。

3 个答案:

答案 0 :(得分:1)

drop sequence rownum1 ;
create temp sequence rownum1;
drop sequence rownum2 ;
create temp sequence rownum2;

select * from(
select job_name, rownum1*20 as myorder from jobs where job_status =0
union
select job_name, rownum2 as myorder from jobs where job_status =1
)
order by myorder desc

如果查询对活动作业的比例为1到20不活动,则此查询将使它们均匀分布。如果您具有超过此最佳比率,则查询顶部将包含大量非活动作业。 每次运行此查询时,您都需要删除并重新创建rownums序列

答案 1 :(得分:0)

我同意kurast的一般方法,但有几点可能会有所帮助:

  1. 我认为您需要使用nextval函数从序列中获取下一个值,如
  2. X

    SELECT * FROM
      (SELECT *, nextval('rownum1') AS SORT_ORDER
           FROM JOBS
           WHERE JOB_STATUS = 'active'
       UNION ALL
       SELECT *, nextval('rownum2') * 19 AS SORT_ORDER
           FROM JOBS
           WHERE JOB_STATUS = 'inactive')
    ORDER BY SORT_ORDER, JOB_STATUS;
    
    1. 我建议在这样的查询中使用UNION ALL,因为你确定子选择返回的表不包含第一行,所以一个普通的UNION(它对组合数据有效地做了DISTINCT)不是必要的,可能会慢慢运行。
    2. 我认为上述查询会在20个作业的每个页面上为您提供一个非活动作业,最后定位,但您必须使用它才能确定。

      请注意,在Oracle中,您可以使用ROWNUM而不必乱用序列。 (提示,提示,PostgreSQL团队?)

      分享并享受。

答案 2 :(得分:0)

我会为此尝试一个用户定义的函数。

create table jobs (
    id serial primary key,
    job_status smallint not null default 1,
    job_name text default 'FIXME',
    inserted timestamptz default now()
);
insert into jobs ( job_status,inserted ) 
select case when random()<=0.05 then 0 else 1 end, localtimestamp
from generate_series(1,1000) x(x);

create or replace function get_jobs(p_limit int,p_offset int)
returns setof jobs as $$
declare
    v_limit1 integer;
    v_offset2 integer;
    rec record;
begin
    v_limit1 := p_limit - 1;
    v_offset2 := p_offset / 20;
    for rec in select * from jobs where job_status=1 
        order by inserted desc limit v_limit1 offset p_offset
    loop
        return next rec;
    end loop;
    return query select * from jobs where job_status=0 offset v_offset2 limit 1;
    return;
end;
$$ language plpgsql;

这将在页面的最后位置列出一个“非活动”作业。代码可能需要一些抛光,但你明白了。

希望这有帮助。

PS。 @kurast:你的解决方案在PostgreSQL 8.4.1中不起作用。它甚至在语法上都不正确。在纠正语法之后,它也不起作用。见下文。

select * from(
    select *, nextval('rownum1')*20 as myorder from jobs where job_status =0
union
    select *, nextval('rownum2') as myorder from jobs where job_status =1
) subq
order by myorder desc;