将FLOAT与RAISERROR一起使用


11

我一直RAISERROR()在提供一些基本的单元测试功能(如此处所示),但是对于无法FLOATs在错误消息中使用感到沮丧。我知道我可以将float转换为字符串,但是我RAISERROR在每个单元测试中都在使用,我不想为每个测试添加另一行代码。(我的单元测试已经足够罗word了!)是否可以在参数列表中执行内联转换/转换RAISERROR?还是有解决这种缺陷的另一种方法?

更新: 所以最终我希望我能做的是:

RAISERROR('Unit Test FAILED! %f', 11, 0, @floatParm)

不幸的是,RAISERROR通常不处理%f或浮点数。所以我必须这样做:

DECLARE @str VARCHAR(40) = CAST(@floatParm AS VARCHAR(40))
RAISERROR('Unit Test FAILED! %s', 11, 0, @str)

...分散在数十个单元测试中时,看起来就像一团糟。因此,我想将其归结为以下内容:

RAISERROR('Unit Test FAILED! %s', 11, 0, CAST(@floatParm AS VARCHAR(40))

但这使我得到了Incorrect syntax near 'CAST'信息。我不明白为什么这是违法的,但是确实如此。我可以在这里使用另一个“衬板”吗?


您能再解释一下吗?
NoChance 2012年

Answers:


12

不幸的是,无论出于何种原因,无论出于何种原因,您都无法在该上下文中进行内联转换,并且RAISERROR也不直接支持float

为了完整地回答此问题,以下是MSDN的相关代码段,我相信您已经看过了(注意:2005年至2012年所有版本的文档中都是相同的文本):

每个替换参数可以是局部变量,也可以是以下任何数据类型:tinyintsmallintintcharvarcharncharnvarcharbinaryvarbinary


我能想到的唯一合理的解决方案是编写一个存储过程以包装RAISERROR调用。这是一个起点:

CREATE PROCEDURE [dbo].[MyRaiserror]
(
    @message nvarchar(2048),
    @severity tinyint,
    @state tinyint,
    @arg0 sql_variant = NULL
)
AS
BEGIN

    DECLARE @msg nvarchar(MAX) = REPLACE(@message, '%f', '%s');
    DECLARE @sql nvarchar(MAX) = N'RAISERROR(@msg, @severity, @state';

    DECLARE @int0 int, @char0 nvarchar(MAX), @bin0 varbinary(MAX);

    IF (@arg0 IS NOT NULL)
    BEGIN
        SET @sql += N', ';

        IF (SQL_VARIANT_PROPERTY(@arg0, 'BaseType') IN ('tinyint', 'smallint', 'int'))
        BEGIN
            SET @int0 = CONVERT(int, @arg0);
            SET @sql += N'@int0';
        END
        ELSE IF (SQL_VARIANT_PROPERTY(@arg0, 'BaseType') IN ('binary', 'varbinary'))
        BEGIN
            SET @bin0 = CONVERT(varbinary(MAX), @arg0);
            SET @sql += N'@bin0';
        END
        ELSE
        BEGIN
            SET @char0 = CONVERT(nvarchar(MAX), @arg0);
            SET @sql += N'@char0';
        END
    END

    SET @sql += N');';

    EXEC sp_executesql
        @sql,
        N'@msg nvarchar(2048), @severity tinyint, @state tinyint, @int0 int, @bin0 varbinary(MAX), @char0 nvarchar(MAX)',
        @msg, @severity, @state, @int0, @bin0, @char0;

END

可悲的是,没有一种简单的方法可以针对任意数量的参数进行缩放……这可能可以使用卷积的嵌套动态SQL来完成,调试起来很有趣。我将其留给读者练习。

sql_variant基于这样的假设:出于代码统一性的原因,即使对于直接由支持的值类型,将在各处使用相同的过程RAISERROR。另外,如果合适的话,可以将其创建为临时存储过程。

使用此过程的结果如下所示:

DECLARE @f float = 0.02345;
DECLARE @i int = 234;
DECLARE @s varchar(20) = 'asdfasdf';
DECLARE @b binary(4) = 0xA0B1C2D3;
DECLARE @d decimal(18, 9) = 152.2323;
DECLARE @n int = NULL;

EXEC [dbo].[MyRaiserror] N'Error message with no params.', 10, 1;
EXEC [dbo].[MyRaiserror] N'Float value = %f', 10, 1, @f;
EXEC [dbo].[MyRaiserror] N'Int value = %i', 10, 1, @i;
EXEC [dbo].[MyRaiserror] N'Character value = %s', 10, 1, @s;
EXEC [dbo].[MyRaiserror] N'Binary value = %#x', 10, 1, @b;
EXEC [dbo].[MyRaiserror] N'Decimal value = %f', 10, 1, @d;
EXEC [dbo].[MyRaiserror] N'Null value = %i', 10, 1, @n;

输出:

Error message with no params.
Float value = 0.02345
Int value = 234
Character value = asdfasdf
Binary value = 0xa0b1c2d3
Decimal value = 152.232300000
Null value = (null)

因此,最终结果是您没有获得浮点数的格式化能力(自己滚动),但是在保留其他类型的格式化能力的同时,您确实获得了输出浮点数的能力(也可以是十进制/数字!)。


哇,真是太好了!我曾经考虑过做类似的事情,但是没有意识到sql_variant,所以我被困在参数列表中,并认为这是不可能的。您教了我一些非常有用的东西。非常感谢你!
kmote 2012年

@kmote:没问题;很高兴我能帮助你。
乔恩·塞格尔
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.