Використання FLOATs з RAISERROR


11

Я використовую RAISERROR()для надання базової функціональності тестування одиниць (як тут ), але мене засмучує неможливість використання FLOATsу повідомленні про помилку. Я знаю, що я можу надати поплавок на рядок, але я використовую RAISERRORв кожному одиничному тесті, я не хочу додавати інший рядок коду для кожного тесту. (Мої одиничні тести вже досить багатослівні!) Чи є спосіб виконати вбудований перетворення / перетворення в списку 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

Відповіді:


12

На жаль, з будь-якої причини ви не можете здійснити вбудовану конверсію в цьому контексті і , з будь-якої причини, RAISERRORбезпосередньо не підтримуєте float.

Для повноти цієї відповіді ось відповідний фрагмент від MSDN , який я впевнений, ви вже бачили (зверніть увагу: це однаковий текст у всіх версіях документації з 2005 по 2012 роки):

Кожен параметр заміщення може бути локальною змінною або будь-яким з цих типів даних: tinyint , smallint , int , char , varchar , nchar , nvarchar , binary або varbinary .


Єдиним розумним рішенням, про яке я можу придумати, було б написати збережену процедуру для завершення 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

@kmote: Немає проблем; рада, що могла допомогти.
Джон Сейгель
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.