SQL 游标循环冻结没有错误

SQL Cursor loop freezing with no error

我知道游标不好,但我认为我有一个需要游标的用例。我有一个 table (tbl_Items),其中有一列 (Item_Code),我希望它是一个唯一的、随机生成的字母数字代码(6 个字符)。我有一个带有循环的函数,它生成一个随机代码,检查它是否已经存在于 table 中,一旦找到一个未使用的代码,return 就是 6 字符代码。

tbl_Items table 中的新记录从 Item_Code 开始为 NULL。我需要 运行 更新所有这些新记录,并将 Item_Code 设置为函数的 return 值。我显然不能用一个 UPDATE 语句来完成这一切,因为在整个事务完成之前,函数将无法准确检查每个新行的 Item_Code 的唯一性。

因此是 CURSOR。这是我现在拥有的:

CREATE PROCEDURE [dbo].[tmp_UPDATE_ITEM_CODE]
AS
BEGIN
    SET NOCOUNT ON;

    DECLARE @item_id BIGINT
    DECLARE @item_code varchar(5)
    DECLARE @new_code VARCHAR(5)

    DECLARE db_cursor CURSOR
    FORWARD_ONLY 
    FOR
        SELECT Item_ID, Item_Code
        FROM tbl_Items
        WHERE Item_Code IS NULL
    FOR UPDATE OF Item_Code

    OPEN db_cursor
    FETCH NEXT FROM db_cursor INTO @item_id, @item_code

    WHILE (@@FETCH_STATUS = 0)
    BEGIN
        SET @new_code = dbo.generate_unique_code(@item_id)

        UPDATE tbl_Items
        SET Item_Code = @new_code
        WHERE CURRENT OF db_cursor

        print CAST(@item_id AS VARCHAR) + ' - New Code = ' + @new_code + ' (' + CAST(@@FETCH_STATUS AS VARCHAR) + ')'

        FETCH NEXT FROM db_cursor INTO @item_id, @item_code
    END

    CLOSE db_cursor
    DEALLOCATE db_cursor

END

我添加打印行只是为了看看发生了什么。我始终获得大约 10 个成功更新的行,然后它就完全停止了。没有错误或任何错误,它只是保持 "Executing..." 但 tbl_Items table 不再更新,消息 window.[=13= 中没有其他内容打印出来]

谁能给我指出正确的方向? CURSOR 的初始查询中大约有 40,000 条记录。谢谢!

更新: 这是 return 唯一的 5 字符代码(5,不是 6)的函数。 "random_view" 是一个只有一列的视图,该列是 0 到 1 之间的随机值。

CREATE FUNCTION [dbo].[generate_unique_code]
(
    @ItemId bigint
)
RETURNS varchar(5)
AS
BEGIN
    DECLARE @Length int
    DECLARE @CharPool varchar(36)
    DECLARE @PoolLength int
    DECLARE @LoopCount int
    DECLARE @RandomString varchar(5)
    DECLARE @RandomInt decimal(18,18)
    DECLARE @IsUnique bit
    DECLARE @CodeExists bigint = NULL

    SET @Length = 6
    SET @CharPool = 'abcdefghijklmnopqrstuvwxyz0123456789'
    SET @PoolLength = Len(@CharPool)

    SET @LoopCount = 0
    SET @RandomString = ''
    SET @IsUnique = 0

    WHILE (@IsUnique = 0) BEGIN
        -- GENERATE UNIQUE 5 CHARACTER STRING
        WHILE (@LoopCount < @Length) BEGIN
            SELECT @RandomInt = rnd
            FROM random_view
            SELECT @RandomString = @RandomString + SUBSTRING(@Charpool, CONVERT(int, @RandomInt * @PoolLength), 1)
            SELECT @LoopCount = @LoopCount + 1
        END
        -- CHECK IF CODE ALREADY EXISTS IN THE DATABASE
        SELECT @CodeExists = Item_ID
        FROM tbl_Items
        WHERE Item_Code = LEFT(@RandomString,5)

        -- IF CODE IS NOT ALREADY IN THE DATABASE, BREAK LOOP TO USE IT
        IF @CodeExists IS NULL BEGIN
            SET @IsUnique = 1
        END
    END

    RETURN LEFT(@RandomString,5)
END

你的功能有问题。它会运行进入死循环。因为您在退出内部 while 循环后没有将 LoopCount 的值重置为 0,所以内部 while 循环只会 运行 一次。这意味着如果您无法在第一个 运行 中获得唯一代码,则外部 while 循环将无限地保持 运行ning 我认为这就是正在发生的事情,因为它找不到唯一代码代码。如果你只想生成随机的唯一代码,你可以这样做:SELECT @randomString = CONVERT(varchar(255), NEWID())。您只需要增加 Item_Code.

的长度