微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

如何编写查询以将剩余的小时数提前以进行负载均衡计划?

如何解决如何编写查询以将剩余的小时数提前以进行负载均衡计划?

我有一个查询结果,其中按时间顺序排列每周安排的总小时数,没有间隔,并且有固定的每周可以处理的小时数。任何未处理的小时数应结转到接下来的一个或多个星期。以下信息可用。

Week | Hours | Capacity
1       2000     160
2        100     160
3          0     140
4        150     160
5        500     160
6       1500     160

每周它应该减少新的小时数加上容量结转的小时数,但永远不会低于零。正值应延续到接下来的一周。

Week | Hours | Capacity | LeftOver = (Hours + LAG(LeftOver) - Capacity)
1        400     160          240 (400 +   0 - 160) 
2        100     160          180 (100 + 240 - 160)
3          0     140           40 (  0 + 180 - 140) 
4         20     160            0 ( 20 +  40 - 160) (no negative,change to zero)
5        500     160          340 (500 +   0 - 160)
6          0     160          180 (  0 + 340 - 160)

我假设这可以通过 cte 递归和一个不低于零的运行值来完成,但我找不到任何具体的例子来说明如何编写。

解决方法

好吧,您没有看错,递归公用表表达式确实是构建解决方案的一种选择。

递归查询的构建通常可以分步完成。在每一步之后运行您的查询并验证结果。

  1. 定义递归的“锚点”:递归从哪里开始
    这里的开始由 Week = 1 定义。
  2. 定义递归迭代:迭代之间的关系是什么
    这里是递增的周数 d.Week = r.Week + 1

避免负数可以用 case 表达式解决。

示例数据

create table data
(
  Week int,Hours int,Capacity int
);

insert into data (Week,Hours,Capacity) values
(1,400,160),(2,100,(3,140),(4,20,(5,500,(6,160);

解决方案

with rcte as
(
  select d.Week,d.Hours,d.Capacity,case
           when d.Hours - d.Capacity > 0
           then d.Hours - d.Capacity
           else 0
         end as LeftOver
  from data d
  where d.Week = 1
union all
  select d.Week,case
           when d.Hours + r.LeftOver - d.Capacity > 0
           then d.Hours + r.LeftOver - d.Capacity
           else 0
         end
  from rcte r
  join data d
    on d.Week = r.Week + 1
)
select r.Week,r.Hours,r.Capacity,r.LeftOver
from rcte r
order by r.Week;

结果

Week  Hours  Capacity  LeftOver
----  -----  --------  --------
1     400    160       240
2     100    160       180
3     0      140       40
4     20     160       0
5     500    160       340
6     0      160       180

Fiddle 查看实际情况。

,

我最终写了一些 CTE,然后是递归 CTE,得到了我需要的东西。容量在这里是一个静态数字,但稍后会被替换为一个考虑到假期和假期的数字。还需要考虑第一周的初始“LeftOver”值,但可以使用此查询与较早的日期周期来查找具有零 LeftOver 值的最近日期,然后将其用作新的开始日期,然后过滤掉较早的日期数周后的最终查询。

DECLARE @StartDate date = (SELECT MAX(FirstDayOfWorkWeek) FROM dbo._Calendar WHERE Date <= GETDATE());
DECLARE @EndDate date = DATEADD(week,12,@StartDate);
DECLARE @EmployeeQty int = (SELECT ISNULL(COUNT(*),0) FROM Employee WHERE DefaultDepartment IN (4) AND Hidden = 0 AND DateTerminated IS NULL);

WITH hours AS ( 
/* GRAB ALL NEW HOURS SCHEDULED FOR EACH WEEK IN THE SELECTED PERIOD */
SELECT c.FirstDayOfWorkWeek as [Date],SUM(budget.Hours) as hours
FROM dbo.Project_Phase phase
  JOIN dbo.Project_Budget_Labor budget on phase.ID = budget.Phase
  JOIN dbo._Calendar c on CONVERT(date,phase.Date1) = c.[Date]
WHERE phase.CompletedOn IS NULL AND phase.Project <> 4266
  AND phase.Date1 BETWEEN @StartDate AND @EndDate
  AND budget.Department IN (4)
GROUP BY c.FirstDayOfWorkWeek
),weeks AS (
/* CREATE BLANK ROWS FOR EACH WEEK AND JOIN TO ACTUAL HOURS TO ELIMINATE GAPS */
/* ADD A ROW NUMBER FOR RECURSION IN NEXT CTE */
SELECT cal.[Date],ROW_NUMBER() OVER(ORDER BY cal.[Date]) as [rownum],ISNULL(SUM(hours.Hours),0) as Hours
FROM (SELECT FirstDayOfWorkWeek as [Date] FROM dbo._Calendar WHERE [Date] BETWEEN @StartDate AND @EndDate GROUP BY FirstDayOfWorkWeek) as cal
  LEFT JOIN hours on cal.[Date] = hours.[Date]
GROUP BY cal.[Date]
),spread AS (
/* GRAB FIRST WEEK AND USE RECURSION TO CREATE RUNNING TOTAL THAT DOES NOT DROP BELOW ZERO*/
SELECT TOP 1 [Date],rownum,@EmployeeQty * 40 as Capacity,CONVERT(numeric(9,2),0.00) as LeftOver,Hours as running
FROM weeks
ORDER BY rownum
UNION ALL
SELECT curr.[Date],curr.rownum,curr.Hours,CASE WHEN curr.Hours + prev.LeftOver - (@EmployeeQty * 40) < 0 THEN 0 ELSE curr.Hours + prev.LeftOver - (@EmployeeQty * 40) END) as LeftOver,curr.Hours + prev.LeftOver as running
FROM weeks curr
  JOIN spread prev on curr.rownum = (prev.rownum + 1)
)

SELECT spread.Hours as NewHours,spread.LeftOver as PrevHours,spread.Capacity,spread.running as RunningTotal,CASE WHEN running < Capacity THEN running ELSE Capacity END as HoursThisWeek
FROM spread

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。