ใช้ 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 , ถ่าน , varchar , nchar , nvarchar , ไบนารีหรือ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

น่าเศร้าที่ไม่มีวิธีง่ายๆในการปรับขนาดนี้สำหรับพารามิเตอร์ตามอำเภอใจ ... มันอาจจะทำได้โดยใช้ Dynamic 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: ไม่มีปัญหา ดีใจที่ฉันสามารถช่วย
Jon Seigel
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.