You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

存储过程直接执行正常,赋值变量时返回值始终为0排查

问题

执行存储过程[dbo].[NumbersToWords]时遇到异常:单独执行该存储过程能返回正确的数字转英文结果,但使用exec @str = NumbersToWords @number = 1520123将返回值赋值给变量@str时,@str始终返回0。

存储过程代码

ALTER PROCEDURE [dbo].[NumbersToWords]
    @Number INT
AS
BEGIN
    SET NOCOUNT ON;

    SET @Number = ABS(@Number)
    DECLARE @vResult NVARCHAR(MAX) = '' 
    
    -- 预定义数字映射表
    DECLARE @tDict TABLE (Num INT NOT NULL, Nam NVARCHAR(255) NOT NULL)
    INSERT 
    INTO    @tDict (Num, Nam)
    VALUES  (1,'one'),(2,'two'),(3,'three'),(4,'four'),(5,'five'),(6,'six'),(7,'seven'),(8,'eight'),(9,'nine'),
            (10,'ten'),(11,'eleven'),(12,'twelve'),(13,'thirteen'),(14,'fourteen'),(15,'fifteen'),(16,'sixteen'),(17,'seventeen'),(18,'eighteen'),(19,'nineteen'),
            (20,'twenty'),(30,'thirty'),(40,'fourty'),(50,'fifty'),(60,'sixty'),(70,'seventy'),(80,'eighty'),(90,'ninety')
    
    DECLARE @ZeroWord       NVARCHAR(10) = 'zero'
    DECLARE @DotWord        NVARCHAR(10) = 'point'
    DECLARE @AndWord        NVARCHAR(10) = 'and'
    DECLARE @HundredWord    NVARCHAR(10) = 'hundred'
    DECLARE @ThousandWord   NVARCHAR(10) = 'thousand'
    DECLARE @MillionWord    NVARCHAR(10) = 'million'
    DECLARE @BillionWord    NVARCHAR(10) = 'billion'
    DECLARE @TrillionWord   NVARCHAR(10) = 'trillion'

    -- 处理小数部分(注:@Number是INT类型,此处逻辑实际不会触发)
    DECLARE @vDecimalNum INT = (@Number - FLOOR(@Number)) * 100
    DECLARE @vLoop SMALLINT = CONVERT(SMALLINT, SQL_VARIANT_PROPERTY(@Number, 'Scale'))
    DECLARE @vSubDecimalResult  NVARCHAR(MAX) = N''
    
    IF @vDecimalNum > 0
    BEGIN
        WHILE @vLoop > 0
        BEGIN
            IF @vDecimalNum % 10 = 0
                SET @vSubDecimalResult = FORMATMESSAGE('%s %s', @ZeroWord, @vSubDecimalResult)
            ELSE
                SELECT  @vSubDecimalResult = FORMATMESSAGE('%s %s', Nam, @vSubDecimalResult)
                FROM    @tDict
                WHERE   Num = @vDecimalNum%10

            SET @vDecimalNum = FLOOR(@vDecimalNum/10)
            SET @vLoop = @vLoop - 1
        END
    END
    
    -- 处理整数部分
    SET @Number = FLOOR(@Number) 
    IF @Number = 0
        SET @vResult = @ZeroWord
    ELSE
    BEGIN
        DECLARE @vSubResult NVARCHAR(MAX) = ''
        DECLARE @v000Num DECIMAL(15,0) = 0
        DECLARE @v00Num DECIMAL(15,0) = 0
        DECLARE @v0Num DECIMAL(15,0) = 0
        DECLARE @vIndex SMALLINT = 0
        
        WHILE @Number > 0
        BEGIN
            -- 从右往左取每三位数字
            SET @v000Num = @Number % 1000
            SET @v00Num = @v000Num % 100
            SET @v0Num = @v00Num % 10
            IF @v000Num = 0
            BEGIN
                SET @vSubResult = ''
            END
            ELSE 
            BEGIN 
                -- 处理两位数字
                IF @v00Num < 20
                BEGIN
                    -- 小于20的数字直接取映射
                    SELECT @vSubResult = Nam FROM @tDict WHERE Num = @v00Num
                    IF @v00Num < 10 AND @v00Num > 0 AND (@v000Num > 99 OR FLOOR(@Number / 1000) > 0)--例如1001:一千和一;或201000:(二百和一)千
                        SET @vSubResult = FORMATMESSAGE('%s %s', @AndWord, @vSubResult)
                END
                ELSE 
                BEGIN
                    -- 大于等于20的数字拆分十位和个位
                    SELECT @vSubResult = Nam FROM @tDict WHERE Num = @v0Num 
                    SET @v00Num = FLOOR(@v00Num/10)*10
                    SELECT @vSubResult = FORMATMESSAGE('%s %s', Nam, @vSubResult) FROM @tDict WHERE Num = @v00Num 
                END

                -- 处理百位数字
                IF @v000Num > 99
                    SELECT @vSubResult = FORMATMESSAGE('%s %s %s', Nam, @HundredWord, @vSubResult) FROM @tDict WHERE Num = CONVERT(INT,@v000Num / 100)
            END
            
            -- 添加量级单位(千、百万等)
            IF @vSubResult <> ''
            BEGIN
                SET @vSubResult = FORMATMESSAGE('%s %s', @vSubResult, CASE 
                                                                        WHEN @vIndex=1 THEN @ThousandWord
                                                                        WHEN @vIndex=2 THEN @MillionWord
                                                                        WHEN @vIndex=3 THEN @BillionWord
                                                                        WHEN @vIndex=4 THEN @TrillionWord
                                                                        WHEN @vIndex>3 AND @vIndex%3=2 THEN @MillionWord + ' ' + RTRIM(LTRIM(REPLICATE(@BillionWord + ' ',@vIndex%3)))
                                                                        WHEN @vIndex>3 AND @vIndex%3=0 THEN RTRIM(LTRIM(REPLICATE(@BillionWord + ' ',@vIndex%3)))
                                                                        ELSE ''
                                                                    END)
                SET @vResult = FORMATMESSAGE('%s %s', @vSubResult, @vResult)
            END

            -- 处理下一组三位数字(向左)
            SET @vIndex = @vIndex + 1
            SET @Number = FLOOR(@Number / 1000)
        END
    END
    SET @vResult = FORMATMESSAGE('%s %s', RTRIM(LTRIM(@vResult)), COALESCE(@DotWord + ' ' + NULLIF(@vSubDecimalResult,''), ''))
    
    -- 返回结果
    SELECT UPPER(@vResult) AS 'Result'
END

测试情况

  • 单独执行时结果正常:
declare @number INT = 1520123
exec NumbersToWords @number = 1520123

执行后会返回正确的英文数字字符串。

  • 赋值给变量时返回0:
declare @number INT = 1520123
declare @str nvarchar(max)
exec @str = NumbersToWords @number = 1520123
select @str as 'Word'

执行后@str的值始终为0。

原因与解决方法

原因

exec @变量 = 存储过程名这种语法获取的是存储过程的返回状态码,不是存储过程内部SELECT输出的结果。默认情况下,如果存储过程没有显式使用RETURN语句返回值,SQL Server会返回0表示执行成功,这就是@str始终为0的原因。

你的存储过程是通过SELECT UPPER(@vResult) AS 'Result'输出结果,而非通过返回值或输出参数传递,因此无法通过这种方式捕获结果。

解决方法

有两种常用方式可以捕获存储过程的输出结果:

方法1:修改存储过程,添加输出参数

修改存储过程定义,新增一个输出参数传递结果,替代原来的SELECT语句:

ALTER PROCEDURE [dbo].[NumbersToWords]
    @Number INT,
    @Result NVARCHAR(MAX) OUTPUT -- 新增输出参数
AS
BEGIN
    SET NOCOUNT ON;

    -- 保留原有所有逻辑不变,直到最后一步
    
    -- 替换原来的SELECT语句,将结果赋值给输出参数
    SET @Result = UPPER(RTRIM(LTRIM(@vResult)) + ' ' + COALESCE(@DotWord + ' ' + NULLIF(@vSubDecimalResult,''), ''))
END

调用时使用OUTPUT关键字获取结果:

declare @number INT = 1520123
declare @str nvarchar(max)
exec NumbersToWords @number = 1520123, @Result = @str OUTPUT
select @str as 'Word'

方法2:使用表变量/临时表捕获查询结果

如果不想修改存储过程,可以在调用时用表变量或临时表存储存储过程的输出:

declare @number INT = 1520123
declare @resultTable TABLE (Result NVARCHAR(MAX)) -- 定义表变量
declare @str nvarchar(max)

-- 将存储过程的SELECT结果插入表变量
INSERT INTO @resultTable
exec NumbersToWords @number = 1520123

-- 从表变量中取出结果赋值给@str
SELECT @str = Result FROM @resultTable

select @str as 'Word'

内容的提问来源于stack exchange,提问作者Ruchira

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.16 03:33:10