Oracle SQL中的工作负载分配

时间:2018-05-07 10:31:38

标签: sql oracle

我尝试在SQL中进行Workload分发但看起来很难。

我的数据是:

work-station | workload
------------------------
Station1     |  500 
Station2     |  450 
Station3     |  50 
Station4     |  600 
Station5     |  2 
Station6     |  350 

并且:

Real Worker Number : 5

我的需求如下:

  • 我要求实际工人数量与理论工人数量(分配)之间的完全匹配
  • 如果不需要,我不想把某人放在车站(例如:station5)
  • 我不想知道我的工人是否能够完成整个工作量
  • 我希望我的工人能够获得最佳的工作效率

是否可以在sql Request中进行此WorkLoad分发?

可能的结果:

work-station | workload | theoretical worker distribution
------------------------
Station1     |  500     |    1
Station2     |  450     |    1
Station3     |  50      |    0
Station4     |  600     |    2
Station5     |  2       |    0
Station6     |  350     |    1

2 个答案:

答案 0 :(得分:2)

这是一种非常简单的方法,通过按工作人员分配给每个工作站的工作百分比来按比例分配工人。

复杂性来自于确保分配了整数个工作人员,并且分配的工作人员总数等于可用的工作人员数量。以下是执行此操作的查询:

with params as ( SELECT 5 total_workers FROM DUAL),
info ( station, workload) AS (
SELECT 'Station1', 500 FROM DUAL UNION ALL
SELECT 'Station2', 450 FROM DUAL UNION ALL
SELECT 'Station3', 50 FROM DUAL UNION ALL
SELECT 'Station4', 600 FROM DUAL UNION ALL
SELECT 'Station5', 2 FROM DUAL UNION ALL
SELECT 'Station6', 350 FROM DUAL ),
targets as (
select station, 
       workload,
       -- What % of total work is assigned to station?
       workload/sum(workload) over ( partition by null) pct_work,
       -- How many workers (target_workers) would we assign if we could assign fractional workers?
       total_workers * (workload/sum(workload) over ( partition by null)) target_workers,
       -- Take the integer part of target_workers
       floor(total_workers * (workload/sum(workload) over ( partition by null))) target_workers_floor,
       -- Take the fractional part of target workers
       mod(total_workers * (workload/sum(workload) over ( partition by null)),1) target_workers_frac
from params, info )
select t.station, 
       t.workload,
       -- Start with the integer part of target workers
       target_workers_floor + 
       -- Order the stations by the fractional part of target workers and assign 1 additional worker to each station until
       -- the total number of workers assigned = the number of workers we have available.
       case when row_number() over ( partition by null order by target_workers_frac desc ) 
            <= total_workers - sum(target_workers_floor) over ( partition by null) THEN 1 ELSE 0 END target_workers
from params, targets t
order by station;


+----------+----------+----------------+--+
| STATION  | WORKLOAD | TARGET_WORKERS |  |
+----------+----------+----------------+--+
| Station1 | 500      | 1              |  |
+----------+----------+----------------+--+
| Station2 | 450      | 1              |  |
+----------+----------+----------------+--+
| Station3 | 50       | 0              |  |
+----------+----------+----------------+--+
| Station4 | 600      | 2              |  |
+----------+----------+----------------+--+
| Station5 | 2        | 0              |  |
+----------+----------+----------------+--+
| Station6 | 350      | 1              |  |
+----------+----------+----------------+--+

答案 1 :(得分:1)

以下查询应该有效:

首先,我将工人划分到工作量大于平均工作量的工作站。

然后我按照剩余工作量的相同顺序将其余工人分成工作站。

http://sqlfiddle.com/#!4/55491/12

5代表工人数量。

SELECT
    workload,
    station,
    SUM (worker_count)
FROM
    (
SELECT workload, station, floor( workload / ( SELECT SUM (workload) / 5 FROM work_station ) ) worker_count -- divide workers to the stations have more workload then mean
      FROM
      work_station works
UNION ALL
    SELECT t_table.*, 1
    FROM ( SELECT workload, station
            FROM work_station
            ORDER BY
                ( workload - floor( workload / ( SELECT SUM (workload) / 5 FROM work_station ) ) * ( SELECT SUM (workload) / 5 FROM work_station )
                ) DESC
        ) t_table
    WHERE
        rownum < ( 5 - ( SELECT SUM ( floor( workload / ( SELECT SUM (workload) / 5 FROM work_station ) ) ) FROM work_station ) + 1 
        ) -- count of the rest of the workers
) table_sum
GROUP BY
    workload,
    station
ORDER BY
  station