SQL游标问题

时间:2011-08-31 16:24:05

标签: sql sql-server

我收到以下错误但无法弄清楚原因..

  

消息16915,级别16,状态1,过程client_myClientsProc,行   46个
  已存在名为“cur_keywords”的光标   消息16905,级别16,状态1,过程client_myClientsProc,行   47个
  光标已经打开。

然后,如果我再次尝试再次运行,那么

  

消息208,级别16,状态0,过程client_myClientsProc第49行   无效的对象名称'## CLIENTS_KEYWORD。

现在这是我要修复的旧代码,所以请耐心等待......

ALTER PROCEDURE [dbo].[client_myclientsproc]  
   @Keywords varchar(max),  
   @Delimiter varchar(10) = ' '  
AS  
BEGIN  
  SET NOCOUNT ON;  

  DECLARE @MYQUERY NVARCHAR(MAX);    
  DECLARE @tempkeyword varchar(4000)    
  DECLARE @TempCount INT   

  IF OBJECT_ID('TempDB..##CLIENTS_KEYWORD') IS NOT NULL
  BEGIN
     DROP TABLE ##CLIENTS_KEYWORD
  END
  ELSE
  BEGIN
    CREATE TABLE ##CLIENTS_KEYWORD(client_id int)  
  END

  IF OBJECT_ID('TempDB..##TEMP_CLIENTS_KEYWORD') IS NOT NULL
  BEGIN
    DROP TABLE ##TEMP_CLIENTS_KEYWORD
  END
  ELSE
  BEGIN
     CREATE TABLE ##TEMP_CLIENTS_KEYWORD(productid int)
  END  

  SET @MYQUERY = 'SELECT clientID, Client_Name FROM MYCLIENTS WHERE  ClientID IN ';                    

 IF(@Delimiter<>'none')
 BEGIN   
  DECLARE cur_keywords CURSOR FOR  
    select value from SC_Split(@Keywords,@Delimiter)     

  OPEN cur_keywords  

  FETCH NEXT FROM cur_keywords into @tempkeyword  
  INSERT ##CLIENTS_KEYWORD(client_id) exec getClientsByKeyword @tempkeyword  

   WHILE @@FETCH_STATUS = 0     

    FETCH NEXT FROM cur_keywords into @tempkeyword  

     INSERT ##TEMP_CLIENTS_KEYWORD(client_id) exec getClientsByKeyword @tempkeyword 
          select @TempCount=COUNT(client_id) from  ##TEMP_CLIENTS_KEYWORD     
            IF(@TempCount<>0)    
                BEGIN    
                    DELETE FROM ##CLIENTS_KEYWORD WHERE client_id NOT IN(SELECT client_id from ##TEMP_CLIENTS_KEYWORD)     
       INSERT  ##CLIENTS_KEYWORD (client_id) (select client_id from ##TEMP_CLIENTS_KEYWORD)                       
                END  
       CLOSE cur_keywords                              
       DEALLOCATE cur_keywords                                  
 END
 ELSE 
 BEGIN  
   print(@Keywords)
   INSERT ##CLIENTS_KEYWORD(client_id) exec getClientsByKeyword @Keywords      
 END  

 SET @MYQUERY = @MYQUERY + '(SELECT * FROM ##CLIENTS_KEYWORD)'                           
 SET @MYQUERY = @MYQUERY + ' ORDER BY NAME'                    

 print    @MYQUERY   

 EXEC SP_EXECUTESQL @MYQUERY                                           
END  
GO

====================

按关键字代码获取客户

CREATE PROCEDURE [dbo].[getClientsByKeyword]  
 @Keyword varchar(max)  

AS  
BEGIN  
SET NOCOUNT ON;  


 select                     
  DISTINCT(clients.clientID)
 from                     
  Clients_Table clients                               
  left join clientNumber cn on cn.clientid=clients.clientid                    
 where                     
  clients.activeind = 1                     
  and (clients.Name like '%' + @Keyword + '%'                     
  or clients.clientNum LIKE '%' + @Keyword + '%'           
  or cn.clientN like   '%' + @Keyword + '%' )      

END  



GO

3 个答案:

答案 0 :(得分:4)

  • 您的OPENFETCHWHILECLOSEDEALLOCATE放错地方了。
  • 您的临时表每次都需要创建。

试试这个重构的脚本。根据需要进行修改:

DECLARE @tempkeyword varchar(4000)    
DECLARE @TempCount INT   

IF OBJECT_ID('TempDB..##CLIENTS_KEYWORD') IS NOT NULL
    DROP TABLE ##CLIENTS_KEYWORD

CREATE TABLE ##CLIENTS_KEYWORD(client_id int)  

IF OBJECT_ID('TempDB..##TEMP_CLIENTS_KEYWORD') IS NOT NULL
    DROP TABLE ##TEMP_CLIENTS_KEYWORD

CREATE TABLE ##TEMP_CLIENTS_KEYWORD(productid int)

SET @MYQUERY = 'SELECT clientID, Client_Name FROM MYCLIENTS WHERE  ClientID IN ';                    

IF(@Delimiter<>'none')
BEGIN       
     DECLARE cur_keywords CURSOR FOR  
        SELECT value FROM SC_Split(@Keywords,@Delimiter)     

      OPEN cur_keywords  
      FETCH NEXT FROM cur_keywords into @tempkeyword  
      WHILE @@FETCH_STATUS = 0     
      BEGIN
         FETCH NEXT FROM cur_keywords into @tempkeyword  

         INSERT ##CLIENTS_KEYWORD(client_id) exec getClientsByKeyword @tempkeyword               
         INSERT ##TEMP_CLIENTS_KEYWORD(client_id) exec getClientsByKeyword @tempkeyword 
         SELECT @TempCount=COUNT(client_id) from  ##TEMP_CLIENTS_KEYWORD     
         IF(@TempCount<>0)    
         BEGIN    
              DELETE FROM ##CLIENTS_KEYWORD 
                  WHERE client_id NOT IN(SELECT client_id from ##TEMP_CLIENTS_KEYWORD);

                  INSERT  ##CLIENTS_KEYWORD (client_id) 
                  SELECT  client_id from ##TEMP_CLIENTS_KEYWORD;
         END  
      END

     CLOSE cur_keywords                              
     DEALLOCATE cur_keywords                                  
END
ELSE 
BEGIN  
   print(@Keywords)
   INSERT ##CLIENTS_KEYWORD(client_id) exec getClientsByKeyword @Keywords      
END  

SELECT @MYQUERY=@MYQUERY + '(SELECT * FROM ##CLIENTS_KEYWORD) ORDER BY NAME'                           
print    @MYQUERY   
EXEC SP_EXECUTESQL @MYQUERY                                           
END  

答案 1 :(得分:2)

之前存储过程是否有错误?看起来CLOSEDEALLOCATE语句没有运行,如果代码遇到错误,可能会发生这种情况,因为代码中没有TRY..CATCH或其他方法来确保游标已被妥善清除。尝试断开连接(或在同一连接中手动运行CLOSEDEALLOCATE)并再次运行。

第二个错误可能是出于类似原因 - 清理不善。当您输入存储过程时,代码DROP是临时表(如果它已存在)。 CREATE虽然位于该声明的ELSE部分。这意味着如果表已经存在,那么它将是DROP ped并且永远不会重新创建。

答案 2 :(得分:1)

如果没有设置测试表,我不确定你的代码在做什么,但我认为你可以避免使用基于以下内容的光标。

;WITH C
     AS (select clients.clientID,
                clients.Name,
                clients.clientNum,
                cn.clientN
         from   Clients_Table clients
                left join clientNumber cn
                  on cn.clientid = clients.clientid
                     AND clients.activeind = 1)
select value,
       clients.clientID
from   SC_Split(@Keywords, @Delimiter)
       JOIN C
         ON ( C.Name like '%' + value + '%'
               or C.clientNum LIKE '%' + value + '%'
               or C.clientN like '%' + value + '%' )