我这里有一个使用游标的存储过程,我怀疑它为什么会慢慢执行。
任何人都可以帮我优化或删除名为sp_tmpupd_sht_ind的存储过程中的游标。我还附上了上述程序提到的其他脚本。提前谢谢。
--main proc
alter procedure dbo.sp_tmpupd_sht_ind
@sEmp varchar(10),
@dtStart datetime,
@dtend datetime
as
declare
@hSql cursor,
@sRecStat varchar(1),
@dtFocus datetime,
@dtSchedIn datetime,
@dtSchedOut datetime,
@dtTimeIn datetime,
@dtTimeOut datetime,
@dtNext datetime,
@dtNextStamp datetime,
@sStatus varchar(1),
@sStat varchar(1)
update dbo.tmpcard set stat = 'N'
where emp_id = @sEmp
and ( stamp between @dtStart and dateadd( day, 1, @dtend ) or focus_date between @dtStart and @dtend )
set @hSql = cursor static local for
select distinct focus_date, sched_in, sched_out, rec_stat
from dbo.tmsht
where emp_id = @sEmp and focus_date between @dtStart and @dtend
for read only
Open @hSql
Fetch next from @hSql into @dtFocus, @dtSchedIn, @dtSchedOut, @sRecStat
While @@Fetch_Status = 0
begin
If @dtSchedIn is null and @dtSchedOut is null
begin --non-working
set @dtTimeIn = Null
select @dtTimeIn = min(stamp) from dbo.tmpcard
where emp_id= @sEmp
and status = 'I'
and stat= 'N'
and dbo.datevalue(stamp) = @dtFocus
If @dtTimeIn is not null
begin
update dbo.tmpcard set stat = 'Y' where emp_id = @sEmp and stamp = @dtTimeIn
update dbo.tmsht set time_in = dbo.datevalue(@dtTimeIn) + dbo.time( datepart(hour, @dtTimeIn ), datepart(minute, @dtTimeIn ), 0) where emp_id = @sEmp and focus_date = @dtFocus
end
set @dtTimeOut = Null
select @dtTimeOut = max(stamp) from dbo.tmpcard
where emp_id= @sEmp
and status = 'O'
and stat = 'N'
and stamp between @dtTimeIn and dateadd(hour, 15, @dtTimeIn)
If @dtTimeOut is not null
begin
update dbo.tmpcard set stat = 'Y' where emp_id = @sEmp and stamp = @dtTimeOut
update dbo.tmsht set time_out = dbo.datevalue(@dtTimeOut)+ dbo.time(datepart(hour, @dtTimeOut ), datepart(minute, @dtTimeOut ), 0 )
where emp_id = @sEmp and focus_date = @dtFocus
end
If @dtTimeIn is not null and @dtTimeOut is not null
begin
execute dbo.SP_TMPUPD_NEW @sEmp, @dtFocus, @dtTimeIn, @dtTimeOut
end
end --end non-working
Else begin
--working
set @dtTimeOut = Null
execute dbo.SC_SEL_TIMEOUT @sEmp, @dtSchedIn, @dtSchedOut, @dtTimeOut OUTPUT
If @dtTimeOut is not null
begin
update dbo.tmpcard set stat = 'Y' where emp_id = @sEmp and stamp = @dtTimeOut
update dbo.tmsht set time_out = dbo.datevalue(@dtTimeOut) + dbo.time( datepart(hour, @dtTimeOut), datepart(minute, @dtTimeOut), 0)
where emp_id = @sEmp and focus_date = @dtFocus
end
set @dtTimeIn = Null
execute dbo.SC_SEL_TIMEIN @sEmp, @dtSchedIn, @dtSchedOut, @dtTimeIn OUTPUT
If @dtTimeIn is not null
begin
update dbo.tmpcard set stat = 'Y' where emp_id = @sEmp and stamp = @dtTimeIn
update dbo.tmsht set time_in = dbo.datevalue(@dtTimeIn)+ dbo.time( datepart(hour, @dtTimeIn), datepart(minute, @dtTimeIn), 0) where emp_id = @sEmp and focus_date = @dtFocus
end
If @dtTimeIn is not null and @dtTimeOut is not null
begin
execute dbo.SP_TMPUPD_NEW @sEmp, @dtFocus, @dtTimeIn, @dtTimeOut
end
Else begin
-- Second Pass
set @dtTimeIn = Null
select @dtTimeIn = min(stamp) from dbo.tmpcard
where emp_id= @sEmp
and status = 'I'
and stat= 'N'
and dbo.datevalue(stamp) = @dtFocus
If @dtTimeIn is not null
begin
update dbo.tmpcard set stat = 'Y' where emp_id = @sEmp and stamp = @dtTimeIn
update dbo.tmsht set time_in = dbo.datevalue(@dtTimeIn) + dbo.time( datepart(hour, @dtTimeIn ), datepart(minute, @dtTimeIn ), 0)
where emp_id = @sEmp and focus_date = @dtFocus
end
If @dtTimeOut is null and @dtTimeIn is not null
begin
set @dtNext = dateadd( day, 1, @dtFocus )
set @dtNextStamp = null
select @dtNextStamp = min(stamp) from tmpcard where emp_id= @sEmp and stat= 'N' and status = 'I' and dbo.datevalue(stamp) = @dtNext
If @dtNextStamp is null begin
select @dtTimeOut = max(stamp) from tmpcard where emp_id= @sEmp and stat = 'N' and status = 'O' and stamp >= @dtTimeIn and stamp <= @dtNextStamp
end
Else begin
select @dtTimeOut = max(stamp) from tmpcard where emp_id= @sEmp
and stat = 'N'
and status = 'O'
and stamp between @dtTimeIn and ( dateadd( day,1,dbo.datevalue(@dtTimeIn)) + dbo.timevalue(@dtTimeIn) )
end
If @dtTimeOut is not null
begin
update tmpcard set stat = 'Y' where emp_id = @sEmp and stamp = @dtTimeOut
update dbo.tmsht set time_out = dbo.datevalue(@dtTimeOut) + dbo.time( datepart(hour, @dtTimeOut), datepart(minute, @dtTimeOut), 0)
where emp_id = @sEmp and focus_date = @dtFocus
end
end
If @dtTimeIn is not null and @dtTimeOut is not null
begin
execute dbo.SP_TMPUPD_NEW @sEmp, @dtFocus, @dtTimeIn, @dtTimeOut
end
end-- Second Pass
end -- working
fetch next from @hSql into @dtFocus, @dtSchedIn, @dtSchedOut, @sRecStat
end
close @hSql
deallocate @hSql
GO
ALTER procedure [dbo].[sp_tmpupd_new]
@sID varchar(10),
@dtFocus datetime,
@dtStart datetime,
@dtEnd datetime
as
declare
@hSql cursor,
@sStat varchar(1),
@dtStamp datetime,
@sRow bigint,
@nCtr_In int,
@nCtr_Out int
Set @nCtr_In = 0
Set @nCtr_Out = 0
set @hSql = cursor for
select recgid, status
from tmpcard
where emp_id = @sID
and stamp between @dtStart and @dtEnd
order by stamp, status
for read only
Open @hSql
set @sRow = null
set @sStat = null
Fetch next from @hSql into @sRow, @sStat
While @@Fetch_Status = 0 begin
If @sStat = 'I' begin
set @nCtr_In = @nCtr_In + 1
update tmpcard set seq = @nCtr_In, focus_date = @dtFocus where rowid = @sRow
end
Else If @sStat = 'O' begin
set @nCtr_Out = @nCtr_Out + 1
update tmpcard set seq = @nCtr_Out, focus_date = @dtFocus where rowid = @sRow
end
set @sRow = null
set @sStat = null
fetch next from @hSql into @sRow, @sStat
end
close @hSql
deallocate @hSql
GO
alter procedure [dbo].[sc_sel_timein]
@sEmp varchar(10),
@dtSchedIn datetime,
@dtSchedOut datetime,
@dtStamp datetime OUTPUT
as
select @dtStamp = min(stamp)
from tmpcard
where emp_id = @sEmp
and status = 'I'
and stat != 'Y'
and stamp between dateadd( hour, -6, @dtSchedIn ) and @dtSchedOut
go
alter procedure [dbo].[sc_sel_timeout]
@sEmp varchar(10),
@dtSchedIn datetime,
@dtSchedOut datetime,
@dtStamp datetime OUTPUT
as
select @dtStamp = max( stamp ) from tmpcard
where emp_id = @sEmp
and status = 'O'
and stat != 'Y'
and stamp between @dtSchedIn and dateadd( hour, 12, @dtSchedOut )
go