请帮我构建一个sql select来分配(软件开发)任务到软件版本。实际上,这是解决我的实际业务特定问题的一个虚拟示例。
我有一个关系任务:
ID Effort_In_Days
3 3
1 2
6 2
2 1
4 1
5 1
我想将任务分发给最多2天的版本(超过2的任务仍然会被放入一个版本中)。在我真正的问题中,我有更多的“日子”可以分发“任务”。预期产出:
Release Task_ID
1 3
2 1
3 6
4 2
4 4
5 5
我认为我需要使用分析函数,使用sum(effort_in_days) over
等来获取结果。但是我没有太多使用分析函数,也没有找到一个与我的具体问题足够接近的例子。如果达到总和(> = 2),我需要构建组(发布)。
答案 0 :(得分:2)
这是一个bin-packing问题的例子(见here)。除了在某些边界情况下,我所知道的SQL中没有最佳解决方案。例如,如果所有任务具有相同的长度或者所有任务都是> = 2,那么就有一个易于找到的最佳解决方案。
贪婪算法效果很好。这是将给定记录放在它适合的第一个bin中,可能按照大小顺序递减列表。
如果您的问题确实如您所述,那么贪婪算法将会产生最佳解决方案。也就是说,如果最大值是2并且努力是整数。在这种情况下,甚至可能有一种方法可以在SQL中计算解决方案。
否则,您将需要pl / sql代码来实现近似解决方案。
答案 1 :(得分:2)
我会做类似的事情:
with data as (
select 3 ID, 3 Effort_In_Days from dual union all
select 1 ID, 2 Effort_In_Days from dual union all
select 6 ID, 2 Effort_In_Days from dual union all
select 2 ID, 1 Effort_In_Days from dual union all
select 4 ID, 1 Effort_In_Days from dual union all
select 5 ID, 1 Effort_In_Days from dual
)
select id, effort_in_days, tmp, ceil(tmp/2) release
from (
select id, effort_in_days, sum(least(effort_in_days, 2)) over (order by effort_in_days desc rows unbounded preceding) tmp
from data
);
结果是:
ID EFFORT_IN_DAYS TMP RELEASE
---------- -------------- ---------- ----------
3 3 2 1
1 2 4 2
6 2 6 3
2 1 7 4
4 1 8 4
5 1 9 5
基本上,我使用least()将2以上的所有内容转换为2.然后我将所有行按该值按降序排列并开始分配版本。由于它们按降序排列,最大值为2,因此我知道每次达到2的倍数时我都需要指定一个新版本。
请注意,如果您有小数值,则最终可能会发布未分配完整2天的版本(而不是分配超过2天),这可能会也可能不会满足您的需求。
另请注意,我只显示输出中的所有列,以便更容易查看代码实际执行的操作。
答案 2 :(得分:0)
Oracle 11g R2架构设置:
CREATE TABLE data AS
select 3 ID, 3 Effort_In_Days from dual union all
select 1 ID, 2 Effort_In_Days from dual union all
select 6 ID, 2 Effort_In_Days from dual union all
select 2 ID, 1 Effort_In_Days from dual union all
select 4 ID, 1 Effort_In_Days from dual union all
select 5 ID, 1 Effort_In_Days from dual union all
select 9 ID, 2 Effort_In_Days from dual union all
select 7 ID, 1 Effort_In_Days from dual union all
select 8 ID, 1 Effort_In_Days from dual;
查询1 :
Effort_In_Days
为1
的行,以便Effort_In_Days
1
Effort_In_Days
的所有相邻行位于相同的组中,行之间的值由较高的值分隔Effort_In_Days
属于不同的群组; Effort_In_Days
大于1或WITH indexes AS (
SELECT ID,
Effort_In_Days,
ROWNUM AS idx
FROM Data
),
groups AS (
SELECT ID,
Effort_In_Days,
idx,
CASE Effort_In_Days
WHEN 1
THEN idx - ROW_NUMBER() OVER ( PARTITION BY Effort_In_Days ORDER BY idx )
END AS grp
FROM indexes
ORDER BY idx
),
costs AS (
SELECT ID,
Effort_In_Days,
idx,
CASE Effort_In_Days
WHEN 1
THEN MOD( ROW_NUMBER() OVER ( PARTITION BY grp ORDER BY idx ), 2 )
ELSE 1
END AS cost
FROM groups
ORDER BY idx
)
SELECT ID,
Effort_In_Days,
SUM( cost ) OVER ( ORDER BY idx ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW ) AS Release
FROM costs
ORDER BY idx
为1且行内有奇数行的每一行分配成本1;然后像这样:
| ID | EFFORT_IN_DAYS | RELEASE |
|----|----------------|---------|
| 3 | 3 | 1 |
| 1 | 2 | 2 |
| 6 | 2 | 3 |
| 2 | 1 | 4 |
| 4 | 1 | 4 |
| 5 | 1 | 5 |
| 9 | 2 | 6 |
| 7 | 1 | 7 |
| 8 | 1 | 7 |
<强> Results 强>:
{{1}}