Utilizzo di FLOATs con RAISERROR


11

Sto utilizzando RAISERROR()per fornire alcune funzionalità di base di unit test (come qui ), ma sono frustrato dall'impossibilità di utilizzare FLOATsnel messaggio di errore. So che posso lanciare il float su una stringa, ma sto usando RAISERRORin ogni test unitario, non voglio aggiungere un'altra riga di codice per ogni test. (I miei test unitari sono già abbastanza prolissi!) Esiste un modo per eseguire un cast / convert inline all'interno RAISERRORdell'elenco dei parametri? O c'è un altro modo per aggirare questa carenza?

Aggiornamento: Quindi alla fine quello che vorrei poter fare è questo:

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

Sfortunatamente, RAISERRORnon gestisce% f o float in generale. Quindi devo fare questo invece:

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

... che sembra un disastro quando è sparso attraverso dozzine di Test di unità. Quindi vorrei ridurlo a qualcosa del genere:

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

Ma questo mi dà un Incorrect syntax near 'CAST'messaggio. Non capisco perché sia ​​illegale, ma lo è. C'è un altro "one liner" che potrei usare qui invece?


Potresti spiegare di più per favore?
NoChance,

Risposte:


12

Sfortunatamente, per qualsiasi motivo, non puoi fare una conversione in linea in quel contesto e RAISERRORnon supporta direttamente float, ancora una volta, per qualunque motivo.

Per completezza di questa risposta, ecco il frammento pertinente di MSDN , che sono sicuro che hai già visto (nota: è lo stesso testo in tutte le versioni della documentazione dal 2005 al 2012):

Ogni parametro di sostituzione può essere una variabile locale o uno di questi tipi di dati: tinyint , smallint , int , char , varchar , nchar , nvarchar , binary o varbinary .


L'unica soluzione ragionevole che mi viene in mente sarebbe quella di scrivere una procedura memorizzata per concludere la RAISERRORchiamata. Ecco un punto di partenza:

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

Purtroppo, non esiste un modo semplice per ridimensionarlo per un numero arbitrario di parametri ... Probabilmente potrebbe essere fatto usando l'SQL dinamico nidificato contorto, che sarebbe divertente eseguire il debug. Lo lascerò come esercizio per il lettore.

Ho sql_variantipotizzato che per ragioni di uniformità del codice, la stessa procedura sarebbe stata usata ovunque, anche per i tipi di valore che sono supportati direttamente da RAISERROR. Inoltre, questo potrebbe essere creato come una procedura temporanea memorizzata, se appropriato.

Ecco come sarebbe usare questa procedura:

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;

Produzione:

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)

Quindi il risultato netto è che non ottieni l'abilità di formattazione per i float (fai il tuo), ma ottieni la possibilità di emetterli (anche decimali / numerici!) Mantenendo la capacità di formattazione per gli altri tipi.


Wow, è semplicemente fantastico! Avevo preso in considerazione l'idea di fare qualcosa del genere, ma non ero a conoscenza sql_variant, quindi ero bloccato nella lista degli argomenti e supponevo che non fosse possibile. Mi hai insegnato qualcosa di molto utile oggi. Grazie mille!
kmote

@kmote: nessun problema; felice di poterti aiutare.
Jon Seigel,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.