【问题标题】:CURSOR with a stored procedure with OUTPUT parameters带有 OUTPUT 参数的存储过程的 CURSOR
【发布时间】:2019-12-24 00:17:05
【问题描述】:

我必须一次向表中插入一条记录,然后通过传递输出变量来执行存储过程。

插入部分实际上是这样做的,我在目标表中看到了两条不同的记录。但是存储过程似乎使用了与插入目标表的第一条记录相同的输出参数。所以基本上,当一个存储过程被循环调用时,对于插入到目标表中的每个不同的 ID,一次又一次地循环使用相同的输出参数。

在我下面的伪代码中,它打印 3 次以下 5, 10, 15 。这是正确的,因为它需要dbo.Table_Test 中的每个新 ID。但在我的实际代码中,实际上它只需要第一个 ID 重复循环相同 ID 三次。

-------- CREATING STORED PROCEDURE --------
USE MyDB;
GO

DROP PROCEDURE IF EXISTS dbo.sp_Testing

USE MyDB;
GO

CREATE PROCEDURE dbo.sp_Testing
    @QueueId INT,
    -- response
    @MainId INT OUT,  -- this allows null
    @MessageTx VARCHAR(500) OUT,
    @SuccessIn BIT OUT
AS
BEGIN
    SET NOCOUNT ON;

    IF NOT EXISTS (SELECT * FROM MyDB.sys.tables WHERE name = 'Table_Test') --print 1

    CREATE TABLE dbo.Table_Test 
    (
        ID INT NOT NULL PRIMARY KEY IDENTITY(5,5),
        name VARCHAR(10) NULL,
        Phone INT NULL,
        category VARCHAR(10) NULL
    )

    INSERT INTO dbo.Table_Test (name)
    VALUES ('Andrew')

    SET @MainId = SCOPE_IDENTITY()
    PRINT @MainId
END

-------- END OR STORED PROCEDURE --------
GO

-------- INSERT STATEMENTS ---------
USE MyDB;

IF OBJECT_ID('tempdb..#MainTable') IS NOT NULL
    DROP TABLE #MainTable

IF OBJECT_ID('tempdb..#Queue') IS NOT NULL
    DROP TABLE #Queue

DECLARE @MessageTx VARCHAR(30)
DECLARE @SuccessIn BIT
DECLARE @QueueId INT
DECLARE @MainId INT
DECLARE @ParentId INT

SET @MainId = NULL
SET @SuccessIn = 1

CREATE TABLE #MainTable 
(
        ID INT NOT NULL PRIMARY KEY IDENTITY(1,1),
        name VARCHAR(10) NULL,
        Phone INT NOT NULL,
        category VARCHAR(10) NULL
)

INSERT INTO #MainTable (name, Phone, category)
VALUES ('Adam', 123433, 'new'),
       ('John', 222222, 'new'),
       ('Samuel', 123123313, 'new')

-- SELECT * FROM #MainTable 
-- SELECT * FROM  #Queue
-- SELECT * FROM  #Test

DECLARE Cursor_test CURSOR LOCAL FOR  
    SELECT id
    FROM #MainTable         

-- get relationships for next level 
OPEN Cursor_test  

FETCH NEXT FROM Cursor_test INTO @ParentId   

WHILE @@FETCH_STATUS = 0   
BEGIN
    IF OBJECT_ID('tempdb..#Queue') IS NOT NULL
        DROP TABLE #Queue

    CREATE TABLE #Queue
    (
        PK INT NOT NULL PRIMARY KEY identity (3,2), 
        ID INT NOT NULL
    )

    INSERT INTO #Queue (id)
        SELECT id
        FROM #MainTable

    SET @QueueId = SCOPE_IDENTITY()

    -- real-time creation
    EXEC dbo.sp_Testing @QueueId, @MainId, @MessageTx OUT, @SuccessIn OUT

    FETCH NEXT FROM Cursor_test INTO @ParentId
END

CLOSE Cursor_test   
DEALLOCATE Cursor_test

【问题讨论】:

  • 有什么可以帮助您的吗?
  • 显然,执行此操作的代码存在某种问题。你知道的,你更愿意留给自己的那个。
  • 嗨@Squirrel,请参考我的评论和我回答中的代码
  • 旁注:您应该为您的存储过程使用sp_ 前缀。微软有reserved that prefix for its own use (see Naming Stored Procedures),你确实会在未来某个时候冒着名称冲突的风险。 It's also bad for your stored procedure performance。最好只是简单地避免 sp_ 并使用其他东西作为前缀 - 或者根本不使用前缀!
  • 嗨@RogerWolf,在我上面的伪代码中,它打印了以下 5, 10, 15 的 3 次。这是正确的,因为它需要 dbo.Table_Test 中的每个新 ID。但在我的实际代码中,实际上它只需要第一个 ID 重复循环相同 ID 三次。

标签: sql-server loops stored-procedures cursor output-parameter


【解决方案1】:

这有点太长了,不能在评论中。

首先你必须明白temp#test只存在于存储过程中。它在您的存储过程中创建并在存储过程退出后删除。

所以每次执行存储过程时,它都会创建临时表,当你插入行时,它会返回相同的标识种子值,即5

【讨论】:

  • 其实我只是改了。存储过程中的表是物理的,和实际的insert语句一样。
  • 是的。物理表很好,因为它不像存储过程中的临时表createdrop
猜你喜欢
  • 2018-07-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-02-12
  • 1970-01-01
相关资源
最近更新 更多