我需要使用游标执行此问题的第二部分(https://imgur.com/yyoZxsw),但是我的代码正在使用相同的值更新每行。基本上,我需要检查timein和timeout是否在某个范围内(如上午9点至中午12点之间),付款应为350。此外,如果从10am到16pm之间,我需要计算2个范围。
我尝试了以下代码,但无法正常工作。它应经过timein
和timeout
并计算要支付到amtpaid
列中的金额。
create table babysitter (
babysitterid char(5) not null primary key,
datein date not null,
timein time not null,
dateout date not null,
timeout time not null,
noofhrswrk int,
amtpaid int
);
insert into babysitter values('BS001', '18-Jan-2019', '10:00', '18-Jan-
2019', '16:00', '', '')
insert into babysitter values('BS002', '15-Jan-2019', '13:00', '15-Jan-
2019',
'20:00', '', '')
insert into babysitter values('BS003', '21-Jan-2019', '21:00', '21-Jan-
2019',
'07:00', '', '')
insert into babysitter values('BS004', '11-Jan-2019', '08:00', '11-Jan-
2019', '13:00', '', '')
declare @timein time
declare @timeout time
declare @hoursworked datetime
declare Calculate_No_Hrs cursor for
select timein, timeout, noofhrswrk from babysitter
open Calculate_No_Hrs
fetch next from Calculate_No_Hrs into @timein, @timeout, @hoursworked
while (@@FETCH_STATUS = 0)
begin
update babysitter
set noofhrswrk = abs(datediff(hour, timeout, timein))
fetch next from Calculate_No_Hrs into @timein, @timeout, @hoursworked
end
close Calculate_No_Hrs
deallocate Calculate_No_Hrs ---end first question
--------------------------------------------------------------
declare @timein time
declare @timeout time
declare @amount int
declare @hourswrk int
declare @pay int
set @pay = 0
declare Amt_Paid cursor for
select timein, timeout, noofhrswrk, amtpaid
from babysitter
open Amt_Paid
fetch next from Amt_Paid into @timein, @timeout, @hourswrk, @amount
while (@@FETCH_STATUS = 0)
begin
if (@timein >= '09:00' and @timeout <= '12:00')
begin
set @amount = 350 * @hourswrk
set @pay += @amount
-- update babysitter
-- set amtpaid = @amount
end
if (@timein >= '12:00' and @timeout <= '17:00')
begin
set @amount = 400 * @hourswrk
set @pay += @amount
-- update babysitter
-- set amtpaid = @amount
end
if (@timein >= '17:00' and @timeout <= '21:00')
begin
set @amount = 500 * @hourswrk
set @pay += @amount
-- update babysitter
-- set amtpaid = @amount
end
if (@timein >= '21:00' and @timeout <= '00:00')
begin
set @amount = 600 * @hourswrk
set @pay += @amount
-- update babysitter
-- set amtpaid = @amount
end
if (@timein >= '00:00' and @timeout <= '07:00')
begin
set @amount = 800 * @hourswrk
-- update babysitter
-- set amtpaid = @amount
end
update babysitter
set amtpaid = @pay
fetch next from Amt_Paid into @timein, @timeout, @hourswrk, @amount
end
close Amt_Paid
deallocate Amt_Paid
答案 0 :(得分:1)
有人认为你需要问;从08:00开始,为婴儿保姆支付的金额在任何范围内。我个人将重新构造整个日期时间,并以完全相同的逻辑将直到datetimeIn SQL标准函数不是DATEADD
不是DATE_ADD
,可能您应该更改它。 declare @time time, @timeout time
declare @dateIn date, @dateOut date
declare @BabysiterID NVARCHAR(10)
declare @pay int = 0
declare Amt_Paid cursor for
select BabysiterID, timein, timeout, DateIn, DateOut from @table
open Amt_Paid
fetch next from Amt_Paid into @BabysiterID, @time, @timeout, @dateIn, @dateOut
while (@@FETCH_STATUS = 0) begin
while (@time < @timeout) or (@dateIn < @dateOut) BEGIN
if (@time >= '09:00' and @time < '12:00') begin
set @pay += 350 end
if (@time >= '12:00' and @time < '17:00') begin
set @pay += 400 end
if (@time >= '17:00' and @time < '21:00') begin
set @pay += 500 end
if (@time >= '21:00') begin
set @pay += 600 end
if (@time >= '00:00' and @time < '07:00') begin
set @pay += 800 end
SELECT @time = DATEADD(HOUR,1,@time)
IF(@time = '00:00') BEGIN SELECT @dateIn = DATEADD(DAY,1,@dateIn) END
END -- while
update @table
set amtpaid = @pay
where BabysiterID = @BabysiterID
set @pay = 0
fetch next from Amt_Paid into @BabysiterID, @time, @timeout, @dateIn, @dateOut
end --cursor
close Amt_Paid
deallocate Amt_Paid
答案 1 :(得分:0)
检查此代码
DECLARE @timein TIME, @timeout TIME
DECLARE @amount INT, @hourswrk INT
SET @timein = '13:00'
SET @timeout = '20:00';
SET @hourswrk = 7
if (@timein > '7:00' AND @timeout <= '12:00:00')
BEGIN
set @amount = 350 * @hourswrk
END
else if (@timeout <= '17:00:00')
BEGIN
set @amount = 400 * @hourswrk
END
else if (@timeout <= '21:00:00')
BEGIN
set @amount = 500 * @hourswrk
END
else if (@timeout <= '00:00')
BEGIN
set @amount = 600 * @hourswrk
END
else if (@timeout <= '07:00')
BEGIN
set @amount = 800 * @hourswrk
END
答案 2 :(得分:0)
代码末尾的各种select
语句可用于查看CTE的中间结果,并弄清楚正在逐步进行的操作。 (这也是将问题分解成更简单的部分并一次调试它们的一种通常有用的方法。)
值得注意的是,DateDiff
返回了边界交叉点的计数。有关更多信息,请参阅documentation。
作为读者的练习,左手将CTE拆开以按照OP的要求使用游标和循环。
declare @Rates as Table ( RateId Int Identity, Shift Int, StartTime Time, EndTime Time, Rate Decimal(6,2) );
-- A rate is applicable from the StartTime up to, but not including, the EndTime .
-- StartTime < EndTime unless the EndTime is 00:00 indicating a rate that applies until midnight.
-- A rate cannot span across midnight, but two entries for a single shift may be used to continue a rate past midnight.
insert into @Rates ( Shift, StartTime, EndTime, Rate ) values
( 5, '00:00', '07:00', 800.00 ),
( 0, '07:00', '09:00', 0.00 ), -- No rate supplied in homework assignment.
( 1, '09:00', '12:00', 350.00 ),
( 2, '12:00', '17:00', 400.00 ),
( 3, '17:00', '21:00', 500.00 ),
( 4, '21:00', '00:00', 600.00 );
select * from @Rates order by Shift;
declare @Work as Table ( WorkId Int Identity, WorkerId Int, Started DateTime, Ended DateTime );
insert into @Work ( WorkerId, Started, Ended ) values
( 1, '2000-01-01T11:00:00', '2000-01-01T11:15:00' ), -- Single rate.
( 1, '2000-01-01T09:00:00', '2000-01-01T12:00:00' ), -- Single rate.
( 1, '2000-01-01T10:00:00', '2000-01-01T16:00:00' ), -- Multiple rates.
( 5, '2000-01-01T00:00:00', '2000-01-01T04:00:00' ), -- Single rate starting at midnight.
( 6, '2000-01-01T10:00:00', '2000-01-02T00:00:00' ), -- Multiple rates ending at midnight.
( 7, '2000-01-01T10:00:00', '2000-01-02T16:00:00' ), -- Multiple dates and rates.
( 8, '2000-01-01T10:00:00', '2000-01-03T16:00:00' ), -- Multiple dates and rates.
( 9, '2000-01-01T10:00:00', '2000-01-04T00:00:00' ); -- Multiple dates and rates.
select * from @Work order by Started, WorkerId;
declare @Midnight as Time = '00:00'; -- For easier reading.
with
Ten ( Number ) as ( select * from ( values (0), (1), (2), (3), (4), (5), (6), (7), (8), (9) ) as Digits( Number ) ),
TenUp2 ( Number ) as ( select 42 from Ten as L cross join Ten as R ),
Numbers ( Number ) as ( select Row_Number() over ( order by ( select NULL ) ) from TenUp2 ),
Work as ( -- Split out the date/times into separate date and time columns.
select WorkId, WorkerId,
Cast( Started as Date ) as StartedDate, Cast( Started as Time ) as StartedTime,
Cast( Ended as Date ) as EndedDate, Cast( Ended as Time ) as EndedTime
from @Work ),
WorkOverDates as ( -- Split work across dates into separate rows for each date.
-- Work completed in a single day.
select WorkId, WorkerId, StartedDate, StartedTime, EndedDate, EndedTime
from Work
where StartedDate = EndedDate
union
-- First day of work that spans dates.
select WorkId, WorkerId, StartedDate, StartedTime, StartedDate, @Midnight
from Work
where StartedDate <> EndedDate
union
-- Last day of work that spans dates.
select WorkId, WorkerId, EndedDate, @Midnight, EndedDate, EndedTime
from Work
where StartedDate <> EndedDate and EndedTime <> @Midnight
union
-- Add any intermediate days, just in case someone worked a really long time.
select WorkId, WorkerId, DateAdd( day, N.Number, StartedDate ), @Midnight, DateAdd( day, N.Number, StartedDate ), @Midnight
from Work as W inner join
Numbers as N on N.Number < DateDiff( day, StartedDate, EndedDate )
where DateDiff( day, StartedDate, EndedDate ) > 1 ),
WorkOverRates as ( -- For each work row generate rows for all of the applicable rates (for each date).
select WOD.WorkId, WOD.WorkerId, WOD.StartedDate, WOD.StartedTime, WOD.EndedDate, WOD.EndedTime,
R.RateId, R.Shift, R.StartTime, R.EndTime, R.Rate
from WorkOverDates as WOD inner join
-- The general test for overlapping ranges is: Start1 <= End2 and Start2 <= End1.
@Rates as R on ( WOD.StartedTime < R.EndTime or R.EndTime = @Midnight ) and
( R.StartTime < WOD.EndedTime or WOD.EndedTime = @Midnight ) ),
PaidIntervals as ( -- Determine the hours worked from at each rate (for each date).
select WorkId, WorkerId, StartedDate, StartedTime, EndedDate, EndedTime,
RateId, Shift, StartTime, EndTime, Rate,
DateDiff( millisecond,
-- From the later of the work or rate start time to ...
case when StartedTime < StartTime then StartTime else StartedTime end,
-- ... the earlier of the work or rate end time allowing for midnight.
case
when EndedTime = @Midnight and EndTime = @Midnight then DateAdd( day, 1, 0 )
when EndedTime = @Midnight then EndTime
when EndTime = @Midnight then EndedTime
when EndedTime < EndTime then EndedTime
else EndTime end ) / 3600000.0 as HoursWorked
from WorkOverRates ),
PaySummary as ( -- Summarize all of the rate periods for each WorkId .
select WorkId, Sum( HoursWorked ) as TotalHours, Count( 42 ) as RatePeriods,
Sum( Rate * HoursWorked ) as TotalPay
from PaidIntervals
group by WorkId )
-- To see the intermediate results in the CTE use one of the following select statements instead of the final select :
--select * from Numbers;
--select * from Work order by WorkId;
--select * from WorkOverDates order by WorkId, StartedDate;
--select * from WorkOverRates order by WorkId, StartedDate, StartedTime;
--select * from PaidIntervals order by WorkId, StartedDate, StartedTime;
--select * from PaySummary order by WorkId;
-- Put the summary together with the original work data.
select W.WorkId, W.WorkerId, W.Started, W.Ended, PS.TotalHours, PS.RatePeriods, PS.TotalPay
from @Work as W inner join
PaySummary as PS on PS.WorkId = W.WorkId
order by PS.WorkId;