Сортировка результатов с произвольным распределением - PullRequest
2 голосов
/ 04 декабря 2009

У меня есть база данных с несколькими тысячами заданий, в которых есть столбец со значением «активный» или «неактивный». Около 5% всех рабочих мест являются «неактивными». Задания добавляются ежедневно (в количестве сотен человек). Когда существующее задание помечается как «неактивное», мы сохраняем соотношение к точному (удаляя «неактивные» задания, если их слишком много).

Мне нужно отсортировать все задания таким образом, чтобы «неактивные» задания распределялись равномерно. Оптимально одно из каждых 20 «активных» заданий должно быть «неактивным» (результаты разбиты на страницы по 20).

Как мне этого добиться? База данных Postgresql.

Ответы [ 3 ]

1 голос
/ 04 декабря 2009
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 каждый раз, когда вы запускаете этот запрос

0 голосов
/ 04 декабря 2009

Я бы попробовал пользовательскую функцию для этого.

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;
0 голосов
/ 04 декабря 2009

Я согласен с Курастом в отношении общего подхода, но пара моментов может быть полезна:

  1. Я думаю, вам нужно использовать функцию nextval для получения следующего значения из последовательностей, как в

х

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 для объединенных данных) необходимо и, вероятно, будет работать медленно.

Я думаю, что приведенный выше запрос даст вам одно неактивное задание на каждой странице из 20 заданий, расположенных в конце, но вам наверняка придется поиграть с ним.

Обратите внимание, что в Oracle вы можете использовать ROWNUM вместо того, чтобы возиться с последовательностями. (Подсказка, подсказка, команда PostgreSQL?)

Делись и наслаждайся.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...