Sử dụng FLOAT với RAISERROR


11

Tôi đang sử dụng RAISERROR()để cung cấp một số chức năng Kiểm tra đơn vị cơ bản (như ở đây ), nhưng tôi cảm thấy thất vọng vì không thể sử dụng FLOATstrong thông báo lỗi. Tôi biết tôi có thể chuyển float thành một chuỗi, nhưng tôi đang sử dụng RAISERRORtrong mỗi bài kiểm tra đơn vị, tôi không muốn thêm một dòng mã khác cho mỗi bài kiểm tra. (Các bài kiểm tra đơn vị của tôi đã đủ dài rồi!) Có cách nào để thực hiện chuyển đổi / chuyển đổi nội tuyến trong RAISERRORdanh sách tham số không? Hoặc có một cách khác xung quanh sự thiếu hụt này?

Cập nhật: Vì vậy, cuối cùng những gì tôi muốn tôi có thể làm là:

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

Thật không may, RAISERRORnói chung không xử lý% f hoặc float. Vì vậy, tôi phải làm điều này thay vào đó:

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

... Trông giống như một mớ hỗn độn khi nó nằm rải rác trong hàng tá Bài kiểm tra đơn vị. Vì vậy, tôi muốn đun sôi nó xuống một cái gì đó như thế này:

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

Nhưng điều đó cho tôi một Incorrect syntax near 'CAST'tin nhắn. Tôi không hiểu tại sao điều đó là bất hợp pháp, nhưng nó là. Có một "lót" nào khác mà tôi có thể sử dụng ở đây không?


Bạn có thể giải thích thêm xin vui lòng?
NoChance

Câu trả lời:


12

Thật không may, vì bất kỳ lý do gì, bạn không thể thực hiện chuyển đổi nội tuyến trong bối cảnh đó và RAISERRORkhông hỗ trợ trực tiếp float, vì bất kỳ lý do gì.

Để hoàn thiện câu trả lời này, đây là đoạn trích có liên quan từ MSDN , tôi chắc chắn bạn đã thấy (lưu ý: đó là cùng một văn bản trong tất cả các phiên bản của tài liệu từ năm 2005 đến 2012):

Mỗi tham số thay thế có thể là một biến cục bộ hoặc bất kỳ loại dữ liệu nào: tinyint , smallint , int , char , varchar , nchar , nvarchar , binary hoặc varbinary .


Giải pháp hợp lý duy nhất tôi có thể nghĩ đến là viết một thủ tục được lưu trữ để kết thúc RAISERRORcuộc gọi. Đây là điểm khởi đầu:

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

Đáng buồn thay, không có cách nào dễ dàng để mở rộng quy mô này cho số lượng tham số tùy ý ... Có thể được thực hiện bằng cách sử dụng SQL động được lồng ghép phức tạp, sẽ rất thú vị khi gỡ lỗi. Tôi sẽ để nó như một bài tập cho người đọc.

Tôi đã sử dụng sql_variantgiả định rằng vì lý do thống nhất mã, quy trình tương tự sẽ được sử dụng ở mọi nơi, ngay cả đối với các loại giá trị được hỗ trợ trực tiếp bởi RAISERROR. Ngoài ra, điều này có thể được tạo ra như một thủ tục lưu trữ tạm thời nếu phù hợp.

Đây là những gì sử dụng thủ tục này sẽ như thế nào:

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;

Đầu ra:

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)

Vì vậy, kết quả cuối cùng là bạn không có khả năng định dạng cho số float (tự cuộn), nhưng bạn cũng có được khả năng xuất chúng (số thập phân / số!) Trong khi vẫn giữ được khả năng định dạng cho các loại khác.


Wow, thật tuyệt vời! Tôi đã cân nhắc làm một việc như thế này, nhưng không biết sql_variant, vì vậy tôi bị kẹt trong danh sách tranh luận và cho rằng điều đó là không thể. Bạn đã dạy tôi một cái gì đó rất hữu ích ngày hôm nay. Cảm ơn rât nhiều!
kmote

@kmote: Không vấn đề gì; rất vui vì tôi có thể giúp.
Jon Seigel
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.