使用游标时SQL Server过程中的变量范围

时间:2012-03-26 07:12:52

标签: sql-server-2005

我正在尝试将从DB检索到的数据存储到一个变量中并将其返回到java代码。

返回NULL值。这是因为游标中的变量范围。任何人都可以提出解决方案吗?

这是我的程序:

ALTER PROCEDURE [dbo].[rml_ups_profilerscheduler] @RuleIds varchar(200) output
    -- Add the parameters for the stored procedure here
    --<@Param1, sysname, @p1> <Datatype_For_Param1, , int> = <Default_Value_For_Param1, , 0>, 
    --<@Param2, sysname, @p2> <Datatype_For_Param2, , int> = <Default_Value_For_Param2, , 0>
AS
BEGIN
    -- SET NOCOUNT ON added to prevent extra result sets from
    -- interfering with SELECT statements.
    SET NOCOUNT ON;

    DECLARE @rulescheduleid varchar(50), @scheduletype varchar(50),@finalop varchar(50)
    DECLARE cursorName CURSOR GLOBAL
    FOR
    select distinct rulescheduleid,scheduletype
    from rml_ups_ruleschedulemaster 
    OPEN cursorName -- open the cursor
    FETCH NEXT FROM cursorName
    INTO @rulescheduleid, @scheduletype
     set @finalop=''
     if(lower(@scheduletype) ='daily')
     set @finalop=@finalop+','+(SELECT CONVERT(varchar(150),
    (select ruleid from rml_ups_ruleschedulemaster  a,rml_ups_rulescheduletimemapping b
     where a.rulescheduleid=b.rulescheduleid and b.schedulestarthour <= (SELECT DATEPART(hh, GETDATE()))
     and scheduleendhour >=(SELECT DATEPART(hh, GETDATE()))
     and a.rulescheduleid=1)))

    -- PRINT @rulescheduleid + ' ' + @scheduletype -- print the name
     if(lower(@scheduletype) ='weekly')

     set @finalop=@finalop+','+(SELECT CONVERT(varchar(150),
    (select ruleid from rml_ups_ruleschedulemaster  a,rml_ups_rulescheduletimemapping b
     where a.rulescheduleid=b.rulescheduleid and b.schedulestarthour <= (SELECT DATEPART(hh, GETDATE()))
     and scheduleendhour >=(SELECT DATEPART(hh, GETDATE())) and a.scheduledayofweek =(SELECT DATEPART(dw, GETDATE())) 
     and a.rulescheduleid=@rulescheduleid)))

     if(lower(@scheduletype) ='monthly')

      set @finalop=@finalop+','+(SELECT CONVERT(varchar(150),
    (select ruleid from rml_ups_ruleschedulemaster  a,rml_ups_rulescheduletimemapping b
     where a.rulescheduleid=b.rulescheduleid and b.schedulestarthour <= (SELECT DATEPART(hh, GETDATE()))
     and scheduleendhour >=(SELECT DATEPART(hh, GETDATE())) and a.scheduledayofmonth =(SELECT DATEPART(dd, GETDATE())) 
     and a.rulescheduleid=@rulescheduleid)))

     if(lower(@scheduletype) ='yearly')

      set @finalop=@finalop+','+(SELECT CONVERT(varchar(150),
    (select ruleid from rml_ups_ruleschedulemaster  a,rml_ups_rulescheduletimemapping b
     where a.rulescheduleid=b.rulescheduleid and b.schedulestarthour <= (SELECT DATEPART(hh, GETDATE()))
     and scheduleendhour >=(SELECT DATEPART(hh, GETDATE())) and a.scheduledayofmonth =(SELECT DATEPART(dd, GETDATE()))  and 
     a.schedulemonth=(SELECT DATEPART(mm, GETDATE())) 
     and a.rulescheduleid=@rulescheduleid)))

     if(lower(@scheduletype) ='on at time')

     set @finalop=@finalop+','+(SELECT CONVERT(varchar(150),
    (select ruleid from rml_ups_ruleschedulemaster  a,rml_ups_rulescheduletimemapping b
    where a.rulescheduleid=b.rulescheduleid and b.schedulestarthour <= (SELECT DATEPART(hh, GETDATE()))
    and scheduleendhour >=(SELECT DATEPART(hh, GETDATE())) and a.scheduledayofmonth =(SELECT DATEPART(dd, GETDATE()))
    and schedulemonth=(SELECT DATEPART(mm, GETDATE()))  and 
    a.scheduleyear=(SELECT DATEPART(yy, GETDATE())) 
    and a.rulescheduleid=@rulescheduleid)))

    --PRINT @rulescheduleid + ' ' + @scheduletype -- print the name
    --PRINT @@FETCH_STATUS
    WHILE @@FETCH_STATUS = 0
    BEGIN
    ---PRINT @@FETCH_STATUS

     FETCH NEXT FROM cursorName
     INTO @rulescheduleid, @scheduletype

     if(lower(@scheduletype) ='daily')

     set @finalop=@finalop+','+(SELECT CONVERT(varchar(150),
    (select ruleid from rml_ups_ruleschedulemaster  a,rml_ups_rulescheduletimemapping b
     where a.rulescheduleid=b.rulescheduleid and b.schedulestarthour <= (SELECT DATEPART(hh, GETDATE()))
     and scheduleendhour >=(SELECT DATEPART(hh, GETDATE()))
     and a.rulescheduleid=@rulescheduleid)))

    -- PRINT @rulescheduleid + ' ' + @scheduletype -- print the name
     if(lower(@scheduletype) ='weekly')

     set @finalop=@finalop+','+(SELECT CONVERT(varchar(150),
    (select ruleid from rml_ups_ruleschedulemaster  a,rml_ups_rulescheduletimemapping b
     where a.rulescheduleid=b.rulescheduleid and b.schedulestarthour <= (SELECT DATEPART(hh, GETDATE()))
     and scheduleendhour >=(SELECT DATEPART(hh, GETDATE())) and a.scheduledayofweek =(SELECT DATEPART(dw, GETDATE())) 
     and a.rulescheduleid=@rulescheduleid)))

     if(lower(@scheduletype) ='monthly')

     set @finalop=@finalop+','+(SELECT CONVERT(varchar(150),
    (select ruleid from rml_ups_ruleschedulemaster  a,rml_ups_rulescheduletimemapping b
     where a.rulescheduleid=b.rulescheduleid and b.schedulestarthour <= (SELECT DATEPART(hh, GETDATE()))
     and scheduleendhour >=(SELECT DATEPART(hh, GETDATE())) and a.scheduledayofmonth =(SELECT DATEPART(dd, GETDATE())) 
     and a.rulescheduleid=@rulescheduleid)))

     if(lower(@scheduletype) ='yearly')

     set @finalop=@finalop+','+(SELECT CONVERT(varchar(150),
    (select ruleid from rml_ups_ruleschedulemaster  a,rml_ups_rulescheduletimemapping b
     where a.rulescheduleid=b.rulescheduleid and b.schedulestarthour <= (SELECT DATEPART(hh, GETDATE()))
     and scheduleendhour >=(SELECT DATEPART(hh, GETDATE())) and a.scheduledayofmonth =(SELECT DATEPART(dd, GETDATE()))  and 
     a.schedulemonth=(SELECT DATEPART(mm, GETDATE())) 
     and a.rulescheduleid=@rulescheduleid)))

     if(lower(@scheduletype) ='on at time')

     set @finalop=@finalop+','+(SELECT CONVERT(varchar(150),
    (select ruleid from rml_ups_ruleschedulemaster  a,rml_ups_rulescheduletimemapping b
    where a.rulescheduleid=b.rulescheduleid and b.schedulestarthour <= (SELECT DATEPART(hh, GETDATE()))
    and scheduleendhour >=(SELECT DATEPART(hh, GETDATE())) and a.scheduledayofmonth =(SELECT DATEPART(dd, GETDATE()))
    and schedulemonth=(SELECT DATEPART(mm, GETDATE()))  and 
    a.scheduleyear=(SELECT DATEPART(yy, GETDATE())) 
    and a.rulescheduleid=@rulescheduleid)))
    PRINT @finalop 
    set @RuleIds=@finalop
    PRINT  @RuleIds 
    -- print the name

    END
    --set @RuleIds=@finalop
    --PRINT @RuleIds 
    CLOSE cursorName
    -- close the cursor
    --PRINT  @RuleIds  
    DEALLOCATE cursorName
    -- Deallocate the cursor


END

4 个答案:

答案 0 :(得分:1)

这一位:

WHILE @@FETCH_STATUS = 0
BEGIN
---PRINT @@FETCH_STATUS

 FETCH NEXT FROM cursorName
 INTO @rulescheduleid, @scheduletype

肯定是错误的 - @@FETCH_STATUS会根据之前FETCH声明的结果进行更新 - 但是在您到达此循环之前,您已经使用了FETCH的结果,并且然后你立即执行另一个FETCH并且在你使用它之前不要检查它是否成功。

通常的形式是:

DECLARE <cursor>
OPEN <cursor>

FETCH NEXT FROM <cursor>
WHILE @@FETCH_STATUS = 0
BEGIN
    <process result from previous fetch>

    FETCH NEXT FROM <cursor>
END

CLOSE <cursor>
DEALLOCATE <cursor>

猜测,无论何时超过结果集的末尾,它都会将局部变量(例如@rulescheduleid)设置为NULL,然后使用NULL执行串联,从而产生NULL结果。< / p>

话虽如此,我还没有通过代码墙的其余部分来阅读你想要做的事情以及是否需要光标。

答案 1 :(得分:0)

基本上,光标的组织方式如下:

open cursor

fetch first row into vars

process the fetched values

while @@fetch_status = 0

  fetch next row into vars
  process the fetched values

end

close cursor

现在,process the fetched values部分在您的程序中相当可观,并且在您的代码中重复两次,这是一回事。另一个更重要的是,当你在循环体中处理获取的值时,你实际上是在获取值之后立即执行它。但如果它是最后一次迭代,它将获取NULL,并且由于您处理NULL,您的输出变量也会以NULL结束。

那么,在这种情况下你应该怎么做?只需在循环前删除process the fetched values阶段,然后将另一个阶段(在fetch next row into vars步骤之后)移动到之前的位置,以便光标的结构变为像这样:

open cursor

fetch first row into vars

while @@fetch_status = 0

  process the fetched values
  fetch next row into vars

end

这样,只有一个地方处理值,只有当值不为NULL时才会这样做,因为只要另一个FETCH NEXT带来了NULL,退出循环,保留累积输出。

答案 2 :(得分:0)

i had modified my code procedure is running without any error but at the end of the loop values(retrived from db based on conditoins) asaigned to a variable is becoming empty after the loop is completed here is my modified code 

设置@ RuleIds =''     DECLARE @RuleIds     DECLARE cName CURSOR     对于     选择不同的id,stype     来自table1     OPEN cursorName - 打开光标     FETCH NEXT FROM cName     INTO @ rul,@ sche

WHILE @@FETCH_STATUS = 0
BEGIN
 if(lower(@sched) ='daily')
 set @RuleIds=@RuleIds+','+(SELECT CONVERT(varchar(150),
(select ruleid from rml_ups_ruleschedulemaster  a,rml_ups_rulescheduletimemapping b
 where a.rulescheduleid=b.rulescheduleid and b.schedulestarthour <= (SELECT DATEPART(hh, GETDATE()))
 and scheduleendhour >=(SELECT DATEPART(hh, GETDATE()))
 and a.rulescheduleid=@rulescheduleid)))
-- here iam trying to store retreved values in to variable and returning to the java code it is retuning null values
PRINT @RuleIds 
-- it prints the values assaigned to @RuleIds variable ex values(13,12,2)
 FETCH NEXT FROM cName
 INTO @rul, @sche
END
CLOSE cName
DEALLOCATE cName
--after deaalocating of cursor the valuse stored in  @RuleIds(variable) is becoming empty
PRINT @RuleIds 
---this print statement printing  nothing 

答案 3 :(得分:0)

就个人而言,我根本不会使用光标。我会在select中使用CASE语句来获取要发送回应用程序的字段并返回整个数据集。然后我将循环应用程序端的数据集,以根据应用程序的需要设置参数值。