代码之家  ›  专栏  ›  技术社区  ›  SqlRyan

为什么“字符串或二进制数据将被截断”不是更具描述性的错误?

  •  25
  • SqlRyan  · 技术社区  · 15 年前

    首先:我理解这个错误的含义-我没有试图解决它的一个实例。

    众所周知,此错误很难解决,因为如果将一百万行插入到表100列宽的表中,实际上无法确定导致错误的行的哪一列-必须修改流程以一次插入一行,然后查看哪一行失败。委婉地说,那是一种痛苦。

    是否有任何原因导致错误看起来不像这样?

    String or Binary data would be truncated
    Error inserting value "Some 18 char value" into SomeTable.SomeColumn VARCHAR(10)
    

    如果不是表结构本身的话,这将使查找和更正值变得容易得多。如果看到表数据是一个安全问题,那么可能是一些常规问题,比如给出尝试值的长度和失败列的名称?

    7 回复  |  直到 7 年前
        1
  •  15
  •   Evan Carroll    8 年前

    事实证明,在MS Connect上有一个开放的“功能请求”,如果您希望更改功能,我鼓励您投票。

    https://connect.microsoft.com/SQLServer/feedback/details/339410/

    补充:

    事实上,对于这一功能(尽管名字不好)还有另一个要求,自2005年育空开发以来,这一要求一直很突出,我也鼓励人们投票支持:

    https://connect.microsoft.com/SQLServer/feedback/details/125347/

    更新2016

    微软似乎试图删除这个bug真实年龄的证据。够公平的。找到 old site archived here.

        2
  •  6
  •   profMamba    9 年前

    在找不到可接受的答案之后,我想出了以下方法:

    1. 获取导致问题的查询(如果没有源,也可以使用SQL事件探查器)
    2. 删除所有where子句和其他不重要的部分,直到基本上只剩下select和from部分。
    3. 在0=1处添加(这将仅选择表结构)
    4. 在FROM子句之前添加到[MyDettable]

    你最终应该得到

    SELECT
     Col1, Col2, ..., [ColN]
    INTO [MyTempTable]
    FROM
      [Tables etc.]
    WHERE 0 = 1
    

    这将在数据库中创建一个名为my诱人的表,您可以将其与目标表结构进行比较,以查看它们的不同之处,即可以比较两个表上的列。

    编辑:您可以比较原始表中每一列的数据类型和列大小,我想看看它们的不同之处。新表中的所有列名称都将与旧表相同,并且数据类型和大小将相同,但有问题的列除外。换句话说,使用此查询,SQL将自动创建足够大的列,以处理源表中可能最大的条目。

        3
  •  4
  •   RichardTheKiwi    14 年前

    回答一个被关闭的dup,所以在这里回答。这个模式可以被使用,如果有点复杂的话,但是当改变应用程序或者设置探查器来查看正在发生的事情不是很简单的时候,它是有用的。有时,您只需要将错误传播到应用程序本身,这样您就可以从应用程序中看到正确且有用的错误消息。

    在这些情况下,使用此解决方案快速插入数据库将节省大量时间。将其保存为模板,并对其进行快速更改,以在任何表上解决此问题。

    问题

    样品台

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

    示例语句

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

    可怕的无用错误

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

    该示例只显示了两列,其中它可以溢出,但可以想象它是20列还是40列。

    解决方案

    -- 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
    

    测试它

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

    结果

    msg 50000,级别16,状态1,过程触发器,字符串截断,第18行
    列[d]的数据太长,大小10:0s123456789

    (1行受影响)

    笔记

    • 它需要一个镜像触发器来更新
    • 它当前只报告第一个违规记录列。报告多个记录列是可能的,但我认为这实际上适得其反。
        4
  •  0
  •   JC Ford    15 年前

    微软懒惰?

    顺便说一下,您不必分别尝试每行插入。只需为每个文本列查询max(len(field)),从您怀疑可能是罪魁祸首的列开始。

        5
  •  0
  •   Kevin Fairchild    15 年前

    简短回答: 就这样。

    更长的答案: 我可以在显示行数和列时看到值,但显示被截断的实际信息可能没有意义。对于varchar(10)场景,这可能不是什么大问题,但是过大的数据会非常有用。但希望这里没有人能插入超过varchar(max)所能容纳的内容;)

        6
  •  0
  •   Erwin Smout    15 年前

    软件系统中的描述性错误消息和不存在的错误消息一样好。

    这不仅适用于DBMS,而且适用于任何一种可以想象的软件。

    我认为根本原因是“好的描述性错误消息”需要花费太多时间来实现。一般的软件开发人员文化中,花很多时间思考“如果发生这种特殊的异常,用户希望看到哪些信息?”并不是其中的一部分。必须写下代码才能给出“良好的描述性错误消息”的程序员只看到成本(他们的时间),而没有看到好处。

    最近从软件系统收到的一条错误消息是“发生了一些错误”。请稍后再试。”。别开玩笑了。

        7
  •  -1
  •   djole    11 年前

    我也犯了这个错误,但我发现了原因:

    <option>description</option>  <-- this is not error but is wrong
    <option value="option1">option1</option>
    <option value="option2">option2</option>
    <option value="option3">option3</option> 
    

    我的MVC应用程序将“value”作为导致异常的空strig ant接收