(495) 925-0049, ITShop интернет-магазин 229-0436, Учебный Центр 925-0049
  Главная страница Карта сайта Контакты
Поиск
Вход
Регистрация
Рассылки сайта
 
 
 
 
 

Снова аналитические функции

Источник: ln

Балансировка нагрузки на сотрудников - снова аналитические функции

Том,

У меня возникла следующая проблема с оператором update:

Есть таблица кредитов (loan):

state_cd,
user_id,
status_cd,
...

И таблица user_state_served:

user_id,
state_cd,
last_asgnmt_dt

Хотелось бы распределить кредиты равномерно среди сотрудников, имеющих право работать в соответствующем штате. Для этого я изменяю last_asgnmt_dt = sysdate и беру в качестве следующего ответственного за кредит user_id с min(last_asgnmt_dt).

Однако после первоначального распределения нагрузка сотрудников может оказаться разной, в зависимости от количества кредитов, выданных в штате. Как можно было бы взять среднее количество кредитов в штате и поровну распределить их между сотрудниками? Например, в штате TX выдано 400 кредитов. Этим штатом сейчас занимается 4 сотрудника, нагрузка среди которых распределена так:

emp1:             150
emp2:              50
emp3:              75
emp4:               0
нераспределенные: 125.

Я хочу поровну поделить все активные кредиты между 4 сотрудниками.

Ответ Тома Кайта

Как вам такое решение:

ops$tkyte@ORA920LAP> create table user_state_served
  2  as
  3  select rownum user_id, 'TX' state_cd from all_objects where rownum <= 4
  4  union all
  5  select rownum+4 user_id, 'VA' state_cd from all_objects where rownum <= 3;
Table created.

ops$tkyte@ORA920LAP> create table loan_table
  2  as
  3  select 'TX' state_cd, 1 user_id from all_objects where rownum <= 150
  4  union all
  5  select 'TX', 2 from all_objects where rownum <= 50
  6  union all
  7  select 'TX', 3 from all_objects where rownum <= 75
  8  union all
  9  select 'TX', null from all_objects where rownum <= 125;
Table created.

ops$tkyte@ORA920LAP> insert into loan_table
  2  select 'VA', 5 from loan_table
  3  /
400 rows created.

ops$tkyte@ORA920LAP> select user_id, count(*) from loan_table group by user_id
  2  /
   USER_ID   COUNT(*)
---------- ----------
         1        150
         2         50
         3         75
         5        400
                  125

ops$tkyte@ORA920LAP> create or replace procedure redistribute_state(p_state_cd in varchar2)
  2  as
  3      type rowidArray is table of rowid INDEX BY BINARY_INTEGER;
  4
  5      l_user_id  dbms_sql.number_table;
  6      l_rowids   rowidArray;
  7  begin
  8
  9  select b.user_id, a.rid BULK COLLECT into l_user_id, l_rowids
 10    from (
 11  select state_cd,
 12         ntile(buckets) over ( partition by buckets, state_cd order by state_cd ) idx,
 13         loan_table.rowid rid
 14    from loan_table,
 15         (select count(*) BUCKETS
 16            from user_state_served
 17           where state_cd = p_state_cd)
 18   where state_cd = p_state_cd
 19         ) A,
 20         (select user_id, row_number() over ( order by user_id ) rn
 21            from user_state_served
 22           where state_cd = p_state_cd ) b
 23   where a.idx = b.rn;
 24
 25   forall i in 1 .. l_rowids.count
 26       update loan_table set user_id = l_user_id(i) where rowid = l_rowids(i);
 27  end;
 28  /
Procedure created.

ops$tkyte@ORA920LAP> exec redistribute_state( 'TX' );
PL/SQL procedure successfully completed.

ops$tkyte@ORA920LAP> exec redistribute_state( 'VA' );
PL/SQL procedure successfully completed.

ops$tkyte@ORA920LAP> select user_id, count(*) from loan_table group by user_id
  2  /
   USER_ID   COUNT(*)
---------- ----------
         1        100
         2        100
         3        100
         4        100
         5        134
         6        133
         7        133
7 rows selected.

Поскольку в версии 8i функцию ntile в plsql использовать нельзя, вот как можно изменить это решение для версии Oracle 8i:

ops$tkyte@ORA920LAP> rollback;
Rollback complete.

ops$tkyte@ORA920LAP> select user_id, count(*) from loan_table group by user_id
  2  /
   USER_ID   COUNT(*)
---------- ----------
         1        150
         2         50
         3         75
         5        400
                  125

ops$tkyte@ORA920LAP> create or replace view V
  2  as
  3  select b.user_id, a.rid
  4    from (
  5  select state_cd,
  6         ntile(buckets) over ( partition by buckets, state_cd order by state_cd ) idx,
  7         loan_table.rowid rid
  8    from loan_table,
  9         (select count(*) BUCKETS
 10            from user_state_served
 11           where state_cd = userenv('client_info'))
 12   where state_cd = userenv('client_info')
 13         ) A,
 14         (select user_id, row_number() over ( order by user_id ) rn
 15            from user_state_served
 16           where state_cd = userenv('client_info') ) b
 17   where a.idx = b.rn;
View created.

ops$tkyte@ORA920LAP> create or replace procedure redistribute_state(p_state_cd in varchar2)
  2  as
  3      type rowidArray is table of rowid index by binary_integer;
  4
  5      l_user_id  dbms_sql.number_table;
  6      l_rowids   rowidArray;
  7  begin
  8      dbms_application_info.set_client_info(p_state_cd);
  9      select user_id, rid BULK COLLECT into l_user_id, l_rowids
 10        from v;
 11
 12      forall i in 1 .. l_rowids.count
 13          update loan_table set user_id = l_user_id(i) where rowid = l_rowids(i);
 14  end;
 15  /
Procedure created.

ops$tkyte@ORA920LAP> exec redistribute_state( 'TX' );
PL/SQL procedure successfully completed.

ops$tkyte@ORA920LAP> exec redistribute_state( 'VA' );
PL/SQL procedure successfully completed.

ops$tkyte@ORA920LAP> select user_id, count(*) from loan_table group by user_id
  2  /
   USER_ID   COUNT(*)
---------- ----------
         1        100
         2        100
         3        100
         4        100
         5        134
         6        133
         7        133
7 rows selected.

Комментарий читателя от 24 июня 2003 года

Том!

Хранимая процедура работает не совсем так, как мне хотелось бы. Например, у меня есть 6 кредитов для в штате TX:

user_id         loan_id
2               1
3               2
3               3
3               4
3               5
                6

При выполнении твоей хранимой процедуры, она равномерно распределяет 6 кредитов среди 2 пользователей в группе, но меняет уже выделенные сотруднику задания. Например, в данном случае она может взять кредит с идентификатором 1 и передать его для работы сотруднику с user_id 3. Хотя этого не надо делать - надо только забрать кредиты у перегруженных сотрудников и передать для управления менее загруженным, не отбирая у них те кредиты, с которыми они уже работают.

Ответ Тома Кайта

Ну, идею вы поняли, так почему бы не попытаться решить самому?

Ссылки по теме


 Распечатать »
 Правила публикации »
  Написать редактору 
 Рекомендовать » Дата публикации: 24.03.2010 
 

Магазин программного обеспечения   WWW.ITSHOP.RU
Oracle Database Standard Edition 2 Named User Plus License
Oracle Database Personal Edition Named User Plus Software Update License & Support
Oracle Database Standard Edition 2 Processor License
Oracle Database Personal Edition Named User Plus License
TeeChart for .NET with source code single license
 
Другие предложения...
 
Курсы обучения   WWW.ITSHOP.RU
 
Другие предложения...
 
Магазин сертификационных экзаменов   WWW.ITSHOP.RU
 
Другие предложения...
 
3D Принтеры | 3D Печать   WWW.ITSHOP.RU
 
Другие предложения...
 
Новости по теме
 
Рассылки Subscribe.ru
Информационные технологии: CASE, RAD, ERP, OLAP
Новости ITShop.ru - ПО, книги, документация, курсы обучения
Программирование на Microsoft Access
CASE-технологии
СУБД Oracle "с нуля"
Adobe Photoshop: алхимия дизайна
ЕRP-Форум. Творческие дискуссии о системах автоматизации
 
Статьи по теме
 
Новинки каталога Download
 
Исходники
 
Документация
 
 



    
rambler's top100 Rambler's Top100