存储过程中的T-SQL游标

时间:2015-02-16 14:39:04

标签: sql-server stored-procedures cursor

我正在使用存储过程,我想使用游标来插入新数据(如果数据存在,我想更新)

ALTER Procedure [dbo].[conn]
    @ResellerID int,
    @GWResellerID int,
    @UserName varchar(50),
    @Password varchar(50),
    @URL varchar(100),
    @ServiceType int,
    @ServiceDesc varchar(50),
    @FeedFrom bit,
    @PublicKey varchar(max)
AS
    declare gateway cursor for
         select * 
         from reseller_profiles 
         where main_reseller_ID = @ResellerID

    OPEN gateway

    FETCH NEXT FROM gateway INTO @ResellerID

    WHILE @@FETCH_STATUS = 0
    BEGIN
       INSERT INTO [dbo].tblGatewayConnection([ResellerID],[GWResellerID], [UserName], [Password], [URL], [ServiceType], [ServiceDesc],[feedFromMain], publicKey)
       VALUES (@ResellerID, @GWResellerID, @UserName, @Password, @URL, @ServiceType, @ServiceDesc, @FeedFrom, @PublicKey)

       FETCH NEXT FROM gateway INTO @ResellerID
    END

    CLOSE gateway
    DEALLOCATE gateway

我的表名tblGatewayConnection包含以下列:

resellerID
gwResellerID
userName
password
url
serviceType
serviceDesc
feedFromMain
publicKey

当我使用存储过程插入数据时,我得到一个异常

  

Cursorfetch:INTO列表中声明的变量数必须与所选列的变量数相匹配。

我错过了什么?

任何帮助将不胜感激。

感谢。

2 个答案:

答案 0 :(得分:6)

为什么甚至打扰光标?!?!?!?!?我不会告诉你光标有什么问题 - 因为你不应该固定光标,而应该首先学习以避免它

严肃地说 - 避免 RBAR( row-by-agonizing-row )处理,只要你可以,这里使用游标真是完全没有意义 - 只需使用这个漂亮而干净的基于集合的语句:

ALTER PROCEDURE [dbo].[conn] @ResellerID   INT,
                             @GWResellerID INT,
                             @UserName     VARCHAR(50),
                             @Password     VARCHAR(50),
                             @URL          VARCHAR(100),
                             @ServiceType  INT,
                             @ServiceDesc  VARCHAR(50),
                             @FeedFrom     BIT,
                             @PublicKey    VARCHAR(max)
AS
    INSERT INTO dbo.tblGatewayConnection
                (ResellerID, GWResellerID, UserName, Password,
                 URL, ServiceType, ServiceDesc, feedFromMain,
                 publicKey)
       SELECT 
          ResellerID, GWResellerID, UserName, Password,
          URL, ServiceType, ServiceDesc, feedFromMain,
          publicKey
       FROM   
          dbo.reseller_profiles
       WHERE  
          main_reseller_ID = @ResellerID 

你完成了!!没有杂乱的光标,没有不必要的局部变量 - 只是一个简单的INSERT ... SELECT,你已经实现了你想要的!

答案 1 :(得分:4)

我不确定错误消息是否可以更加自我解释:

  

Cursorfetch:INTO列表中声明的变量数必须与所选列的变量数相匹配。

您正在从reseller_profiles

中选择所有
declare gateway cursor for
     select * 
     from reseller_profiles 
     where main_reseller_ID = @ResellerID

试图将它们放入一个变量中:

FETCH NEXT FROM gateway INTO @ResellerID

您在光标中选择的列数必须与要插入的变量数相匹配,因此您需要类似

的内容
declare gateway cursor for
     select reseller_id
     from reseller_profiles 
     where main_reseller_ID = @ResellerID

HOWEVER 你不应该使用游标,你可以使用INSERT .. SELECT使用相同的东西:

INSERT INTO [dbo].tblGatewayConnection
(   [ResellerID],[GWResellerID], [UserName], [Password], [URL], 
    [ServiceType], [ServiceDesc],[feedFromMain], publicKey
)
SELECT  Resellerid, @GWResellerID, @UserName, @Password, 
        @URL, @ServiceType, @ServiceDesc, @FeedFrom, @PublicKey
FROM    reseller_profiles 
WHERE   main_reseller_ID = @ResellerID;

如前所述,你应该不惜一切代价避免游标,如果你必须使用光标,你可以声明最轻的光标。例如,在您的情况下,您只是在光标内向前移动,只读取数据,不修改它,只在本地访问游标,因此您可以按如下方式声明游标:

DECLARE gateway CURSOR LOCAL STATIC FAST_FORWARD
FOR
    SELECT  ...
    FROM ..

尽管游标在最好的时候表现得非常糟糕,但是懒惰的声明给它们带来了更糟糕的声誉。

最后,You should get out of the habit of using SELECT *