如何优化基于游标的存储过程

时间:2015-01-08 10:16:38

标签: sql-server cursor

我这里有一个使用游标的存储过程,我怀疑它为什么会慢慢执行。

任何人都可以帮我优化或删除名为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

0 个答案:

没有答案