我有3个注册:
ID RegisteredHours
1 7
2 11
3 6
小时7,11和6应根据规则在假期,工作时间和夜晚之间分开或分开:
首先应该填写假期,然后是WorkHours,然后是Nights。 预期的结果是:
ID RegisteredHours Holidays WorkHours Nights [Comment]
1 7 6 1 0 6 hours of 7 can go to Holidays so the remaining 1 hour goes to WorkHours. Holidays are now filled (Sum=6).
2 11 0 10 1 10 hours of 11 can go to WorkHours so the remaining 1 hour goes to Nights. WorkHours are now filled (Sum=11).
3 6 0 0 6 All 6 hours can go to Nights. Nights are now filled (Sum=7)
如何在不使用游标和使用运行总计的情况下计算?以下是要继续的代码:
if object_id('Regs') is not null drop table Regs
go
create table Regs
(
ID int,
RegisteredHours int
)
insert into Regs values (1, 7)
insert into Regs values (2, 1)
insert into Regs values (3, 6)
select *,
6 HolidayHoursMax,
11 WorkHoursMax,
7 NightsHoursMax
from Regs r
答案 0 :(得分:0)
这会产生预期的效果。您需要针对更大的数据集进行测试,并根据结果进行调整...
IF OBJECT_ID('tempdb..#Regs', 'U') IS NOT NULL
DROP TABLE #Regs;
CREATE TABLE #Regs (
ID INT NOT NULL PRIMARY KEY CLUSTERED,
RegisteredHours INT NOT NULL
);
INSERT #Regs (ID, RegisteredHours) VALUES
(1, 7), (2, 11), (3, 6);
-- SELECT * FROM #Regs r
--========================================
SELECT
r.ID,
r.RegisteredHours,
Holidays = CASE
WHEN r.ID = 1 AND r.RegisteredHours <= 6 THEN r.RegisteredHours
WHEN r.ID = 1 AND r.RegisteredHours > 6 THEN 6
ELSE 0
END,
WorkHours = CASE
WHEN r.ID = 1 AND r.RegisteredHours BETWEEN 7 AND 16 THEN r.RegisteredHours - 6
WHEN r.ID = 1 AND r.RegisteredHours > 16 THEN 10
WHEN r.ID = 2 AND r.RegisteredHours <= 10 THEN r.RegisteredHours
WHEN r.ID = 2 AND r.RegisteredHours > 10 THEN 10
ELSE 0
END,
Nights = CASE
WHEN r.ID = 1 AND r.RegisteredHours > 16 THEN r.RegisteredHours - 16
WHEN r.ID = 2 AND r.RegisteredHours > 10 THEN r.RegisteredHours - 10
WHEN r.ID = 3 THEN r.RegisteredHours
ELSE 0
END
FROM
#Regs r;
答案 1 :(得分:0)
请检查以下解决方案。也许它可以用较少的CTE来实现,但至少乍一看它产生的结果和你假设的结果相同,而且它对于ID的数量等是灵活的:
DECLARE @Regs TABLE
(
ID INT IDENTITY(1,1),
RegisteredHours int
)
insert into @Regs values (7);
insert into @Regs values (11);
insert into @Regs values (6);
insert into @Regs values (2);
insert into @Regs values (1);
insert into @Regs values (3);
insert into @Regs values (1);
insert into @Regs values (1);
insert into @Regs values (7);
insert into @Regs values (5);
insert into @Regs values (1);
insert into @Regs values (4);
insert into @Regs values (3);
DECLARE @HolidayHoursMax int = 6;
DECLARE @WorkHoursMax int = 11;
DECLARE @NightHoursMax int = 7;
WITH cteHolidayBasis AS(
SELECT r.ID
,r.RegisteredHours
,SUM(CASE
WHEN r.RegisteredHours <= @HolidayHoursMax THEN r.RegisteredHours
ELSE @HolidayHoursMax
END) OVER (ORDER BY ID) AS HolidayHours
,@HolidayHoursMax - SUM(CASE
WHEN r.RegisteredHours <= @HolidayHoursMax THEN r.RegisteredHours
ELSE @HolidayHoursMax
END) OVER (ORDER BY ID) AS HolidayHoursRem
FROM @Regs r
),
cteHoliday AS(
SELECT ID
,CASE
WHEN (HolidayHoursRem = 0) AND (RegisteredHours > @HolidayHoursMax) THEN @HolidayHoursMax
WHEN (HolidayHoursRem = 0) AND (RegisteredHours <= @HolidayHoursMax) THEN RegisteredHours
WHEN (HolidayHoursRem > 0) THEN RegisteredHours
WHEN (HolidayHoursRem < 0 AND LAG(HolidayHoursRem) OVER (ORDER BY ID) > 0) THEN LAG(HolidayHoursRem) OVER (ORDER BY ID)
ELSE 0
END AS HolidayHours
,RegisteredHours - CASE
WHEN (HolidayHoursRem = 0) AND (RegisteredHours > @HolidayHoursMax) THEN @HolidayHoursMax
WHEN (HolidayHoursRem = 0) AND (RegisteredHours <= @HolidayHoursMax) THEN RegisteredHours
WHEN (HolidayHoursRem > 0) THEN RegisteredHours
WHEN (HolidayHoursRem < 0 AND LAG(HolidayHoursRem) OVER (ORDER BY ID) > 0) THEN LAG(HolidayHoursRem) OVER (ORDER BY ID)
ELSE 0
END AS RemHours
FROM cteHolidayBasis
),
cteWorkBasis AS(
SELECT ID
,RemHours
,SUM(CASE
WHEN RemHours <= @WorkHoursMax THEN RemHours
ELSE @WorkHoursMax
END) OVER (ORDER BY ID) AS WorkHours
,@WorkHoursMax - SUM(CASE
WHEN RemHours <= @WorkHoursMax THEN RemHours
ELSE @WorkHoursMax
END) OVER (ORDER BY ID) AS WorkHoursRem
FROM cteHoliday
),
cteWork AS(
SELECT ID
,CASE
WHEN (WorkHoursRem = 0) AND (RemHours > @WorkHoursMax) THEN @WorkHoursMax
WHEN (WorkHoursRem = 0) AND (RemHours <= @WorkHoursMax) THEN RemHours
WHEN (WorkHoursRem > 0) THEN RemHours
WHEN (WorkHoursRem < 0 AND LAG(WorkHoursRem) OVER (ORDER BY ID) > 0) THEN LAG(WorkHoursRem) OVER (ORDER BY ID)
ELSE 0
END AS WorkHours
,RemHours - CASE
WHEN (WorkHoursRem = 0) AND (RemHours > @WorkHoursMax) THEN @WorkHoursMax
WHEN (WorkHoursRem = 0) AND (RemHours <= @WorkHoursMax) THEN RemHours
WHEN (WorkHoursRem > 0) THEN RemHours
WHEN (WorkHoursRem < 0 AND LAG(WorkHoursRem) OVER (ORDER BY ID) > 0) THEN LAG(WorkHoursRem) OVER (ORDER BY ID)
ELSE 0
END AS RemHours
FROM cteWorkBasis
),
cteNightBasis AS(
SELECT ID
,RemHours
,SUM(CASE
WHEN RemHours <= @NightHoursMax THEN RemHours
ELSE @NightHoursMax
END) OVER (ORDER BY ID) AS NightHours
,@NightHoursMax - SUM(CASE
WHEN RemHours <= @NightHoursMax THEN RemHours
ELSE @NightHoursMax
END) OVER (ORDER BY ID) AS NightHoursRem
FROM cteWork
),
cteNight AS(
SELECT ID
,CASE
WHEN (NightHoursRem = 0) AND (RemHours > @NightHoursMax) THEN @NightHoursMax
WHEN (NightHoursRem = 0) AND (RemHours <= @NightHoursMax) THEN RemHours
WHEN (NightHoursRem > 0) THEN RemHours
WHEN (NightHoursRem < 0 AND LAG(NightHoursRem) OVER (ORDER BY ID) > 0) THEN LAG(NightHoursRem) OVER (ORDER BY ID)
ELSE 0
END AS NightHours
,RemHours - CASE
WHEN (NightHoursRem = 0) AND (RemHours > @NightHoursMax) THEN @NightHoursMax
WHEN (NightHoursRem = 0) AND (RemHours <= @NightHoursMax) THEN RemHours
WHEN (NightHoursRem > 0) THEN RemHours
WHEN (NightHoursRem < 0 AND LAG(NightHoursRem) OVER (ORDER BY ID) > 0) THEN LAG(NightHoursRem) OVER (ORDER BY ID)
ELSE 0
END AS RemHours
FROM cteNightBasis
)
SELECT R.ID
,R.RegisteredHours
,cH.HolidayHours
,cW.WorkHours
,cN.NightHours
,cN.RemHours
FROM @Regs AS R
JOIN cteHoliday AS cH ON R.ID = cH.ID
JOIN cteWork AS cW ON R.ID = cW.ID
JOIN cteNight AS cN ON R.ID = cN.ID
ORDER BY R.ID
我添加了另一个专栏&#34; RemHours&#34;在输出中 - 如果你超过MaxWork + MaxHoliday + MaxNight的总小时数。此外,我添加了几个测试用例 - 只需注释前三个插入,以便用较小的值进行测试。