Why isn't “String or Binary data would be truncated” a more descriptive error?

前端 未结 7 1600
眼角桃花
眼角桃花 2020-12-30 22:34

To start: I understand what this error means - I\'m not attempting to resolve an instance of it.

This error is notoriously difficult to troubleshoot

相关标签:
7条回答
  • 2020-12-30 23:27

    Answering a DUP that got closed, so answering here instead. This pattern can be used, if somewhat elaborate, but it can be useful when it is not trivial to change the application, or set up profiler to see what is happening. Sometimes, you just need the error to propagate to the APP itself so you can see right from the APP, the correct and useful error message.

    In those cases, a quick poke into the DB with this solution will save you lots of time. Save it as a template, and make quick changes to it to solve this problem on any table.

    The problem

    Sample table

    create table StringTruncation
    (A int, B varchar(10), C nvarchar(5), D nvarchar(max), E datetime)
    

    Sample statement

    insert StringTruncation values
    (1, '0123456789', 'abcdef', 'This overflows on C', GETDATE())
    

    The dreaded useless error

    Msg 8152, Level 16, State 4, Line 1
    String or binary data would be truncated.
    The statement has been terminated.
    

    The example shows only 2 columns where it could overflow, but imagine if it were 20 columns, or 40.

    The solution

    -- First move the table out of the way
    exec sp_rename StringTruncation, StringTruncation_;
    
    -- cover it with a query
    create view dbo.StringTruncation
    with schemabinding
    as
    select
        A,
        convert(Nvarchar(max),B) B,
        convert(Nvarchar(max),C) C,
        D, E
    from dbo.StringTruncation_
    GO
    
    -- use a trigger to allow INSERTs, with the length checks thrown in
    create trigger dbo.trig_ioi_StringTruncation
    on StringTruncation
    instead of insert
    as
    set nocount on
    declare @offending nvarchar(max)
    select TOP 1 @offending = case
        when len(C) > 5 then 'Data too long for Column [C] Size 5: ' + C
        when len(B) > 10 then 'Data too long for Column [D] Size 10: ' + B
        end
    from inserted
    where len(C) > 5 or len(B) > 10
    GO
    
    -- keep good data
    if @@rowcount = 0
        insert StringTruncation_
        select * from inserted
    else
        raiserror(@offending,16,1)
    GO
    

    Test it

    insert StringTruncation values
    (1, '0s123456789', 'abcde', 'This overflows on C', GETDATE())
    

    Result

    Msg 50000, Level 16, State 1, Procedure trig_ioi_StringTruncation, Line 18
    Data too long for Column [D] Size 10: 0s123456789

    (1 row(s) affected)

    Notes

    • It needs a mirror trigger for UPDATEs
    • It will currently only report on the first offending record-column. It is possible to report more than one record-column, but I believe that is actually counter-productive.
    0 讨论(0)
提交回复
热议问题