存储过程中的T-SQL游标

Son*_*ner 1 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
Run Code Online (Sandbox Code Playgroud)

我的表名tblGatewayConnection有以下列:

resellerID
gwResellerID
userName
password
url
serviceType
serviceDesc
feedFromMain
publicKey
Run Code Online (Sandbox Code Playgroud)

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

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

我错过了什么 ?

任何帮助将不胜感激.

谢谢.

mar*_*c_s 6

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

说真的 - 尽可能避免使用 RBAR(逐行编排)处理,这里使用游标真是完全没有意义 - 只需使用这个漂亮而干净的基于集合的语句:

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 
Run Code Online (Sandbox Code Playgroud)

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


Gar*_*thD 5

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

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

您正在从中选择所有reseller_profiles

declare gateway cursor for
     select * 
     from reseller_profiles 
     where main_reseller_ID = @ResellerID
Run Code Online (Sandbox Code Playgroud)

并尝试将它们放入单个变量中:

FETCH NEXT FROM gateway INTO @ResellerID
Run Code Online (Sandbox Code Playgroud)

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

declare gateway cursor for
     select reseller_id
     from reseller_profiles 
     where main_reseller_ID = @ResellerID
Run Code Online (Sandbox Code Playgroud)

但是,您不应该为此使用游标,您可以使用相同的东西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;
Run Code Online (Sandbox Code Playgroud)

如前所述,您应该不惜一切代价避免使用游标,如果绝对必须使用游标,则可以声明最轻量的游标。以您的情况为例,您仅在游标内前进,仅读取数据,未修改数据,并且仅在本地访问游标,因此您将声明游标,如下所示:

DECLARE gateway CURSOR LOCAL STATIC FAST_FORWARD
FOR
    SELECT  ...
    FROM ..
Run Code Online (Sandbox Code Playgroud)

尽管游标在最佳情况下表现出色,但懒惰的声明却给它们带来了更糟糕的声誉。

最后,您应该摆脱使用的习惯SELECT *