尝试插入时,错误,字符串或二进制数据将被截断

kar*_*hik 232 sql sql-server

我正在运行data.bat文件,其中包含以下行:

Rem Tis batch file will populate tables

cd\program files\Microsoft SQL Server\MSSQL
osql -U sa -P Password -d MyBusiness -i c:\data.sql
Run Code Online (Sandbox Code Playgroud)

data.sql文件的内容是:

   insert Customers
            (CustomerID, CompanyName, Phone)
             Values('101','Southwinds','19126602729')
Run Code Online (Sandbox Code Playgroud)

还有8个类似的行用于添加记录.

当我跑这跟start> run> cmd> c:\data.bat,我收到此错误信息:

1>2>3>4>5>....<1 row affected>
Msg 8152, Level 16, State 4, Server SP1001, Line 1
string or binary data would be truncated.

<1 row affected>

<1 row affected>

<1 row affected>

<1 row affected>

<1 row affected>

<1 row affected>
Run Code Online (Sandbox Code Playgroud)

此外,我显然是一个新手,但是做什么Level #,并且state #意味着什么,我如何查找错误消息,如上面的那个:8152?

kar*_*hik 581

来自@ gmmastros的回答

每当你看到消息....

__PRE__

想想你自己......这个领域还不足以保存我的数据.

检查customers表的表结构.我想你会发现一个或多个字段的长度不足以容纳你想要插入的数据.例如,如果Phone字段是varchar(8)字段,并且您尝试将11个字符添加到其中,则会出现此错误.

  • 另请注意,受影响的字段可能位于触发器中.希望下次发生这种情况时我记得这个...... (16认同)
  • 有没有办法在调试中看到哪个字段会被截断? (12认同)
  • 某些版本的 SQL Server 可以告诉您哪些数据将被截断。使用“DBCC TRACEON(460);”启用此功能。[参见 Aaron Bertrand 的回答](https://dba.stackexchange.com/a/54925/117141) (3认同)
  • 我知道这是一个真正的 SQL 异常。但是,异常消息“字符串或二进制数据将被截断”有点误导?它实际上终止了执行而不是截断字符串。 (2认同)

alt*_*fox 23

虽然数据长度比字段长度短,但我遇到了这个问题.原来,问题是有另一个日志表(用于审计跟踪),由主表上的触发器填充,其中列大小也必须更改.

  • 同样的问题也发生在我的身上。触发操作是罪魁祸首。 (2认同)

And*_*y M 18

在其中一个INSERT语句中,您试图将太长的字符串插入到字符串(varcharnvarchar)列中.

如果INSERT仅通过查看脚本来判断哪个是罪犯并不明显,则可以计算错误消息之前<1 row affected>出现的行.获得的数字加1为您提供声明编号.在您的情况下,它似乎是产生错误的第二个INSERT.

  • 我有同样的问题,如何找到导致错误的列? (2认同)

Tom*_*bes 11

您的某些数据无法放入数据库列(小).找到错误并不容易.如果使用C#和Linq2Sql,则可以列出将被截断的字段:

首先创建助手类:

public class SqlTruncationExceptionWithDetails : ArgumentOutOfRangeException
{
    public SqlTruncationExceptionWithDetails(System.Data.SqlClient.SqlException inner, DataContext context)
        : base(inner.Message + " " + GetSqlTruncationExceptionWithDetailsString(context))
    {
    }

    /// <summary>
    /// PArt of code from following link
    /// http://stackoverflow.com/questions/3666954/string-or-binary-data-would-be-truncated-linq-exception-cant-find-which-fiel
    /// </summary>
    /// <param name="context"></param>
    /// <returns></returns>
    static string GetSqlTruncationExceptionWithDetailsString(DataContext context)
    {
        StringBuilder sb = new StringBuilder();

        foreach (object update in context.GetChangeSet().Updates)
        {
            FindLongStrings(update, sb);
        }

        foreach (object insert in context.GetChangeSet().Inserts)
        {
            FindLongStrings(insert, sb);
        }
        return sb.ToString();
    }

    public static void FindLongStrings(object testObject, StringBuilder sb)
    {
        foreach (var propInfo in testObject.GetType().GetProperties())
        {
            foreach (System.Data.Linq.Mapping.ColumnAttribute attribute in propInfo.GetCustomAttributes(typeof(System.Data.Linq.Mapping.ColumnAttribute), true))
            {
                if (attribute.DbType.ToLower().Contains("varchar"))
                {
                    string dbType = attribute.DbType.ToLower();
                    int numberStartIndex = dbType.IndexOf("varchar(") + 8;
                    int numberEndIndex = dbType.IndexOf(")", numberStartIndex);
                    string lengthString = dbType.Substring(numberStartIndex, (numberEndIndex - numberStartIndex));
                    int maxLength = 0;
                    int.TryParse(lengthString, out maxLength);

                    string currentValue = (string)propInfo.GetValue(testObject, null);

                    if (!string.IsNullOrEmpty(currentValue) && maxLength != 0 && currentValue.Length > maxLength)
                    {
                        //string is too long
                        sb.AppendLine(testObject.GetType().Name + "." + propInfo.Name + " " + currentValue + " Max: " + maxLength);
                    }

                }
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

然后为SubmitChanges准备包装器:

public static class DataContextExtensions
{
    public static void SubmitChangesWithDetailException(this DataContext dataContext)
    {
        //http://stackoverflow.com/questions/3666954/string-or-binary-data-would-be-truncated-linq-exception-cant-find-which-fiel
        try
        {
            //this can failed on data truncation
            dataContext.SubmitChanges();
        }       
        catch (SqlException sqlException) //when (sqlException.Message == "String or binary data would be truncated.")
        {

            if (sqlException.Message == "String or binary data would be truncated.") //only for EN windows - if you are running different window language, invoke the sqlException.getMessage on thread with EN culture
                throw new SqlTruncationExceptionWithDetails(sqlException, dataContext);
            else
                throw;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

准备全局异常处理程序和日志截断详细信息:

protected void Application_Error(object sender, EventArgs e)
{
    Exception ex = Server.GetLastError();
    string message = ex.Message;
    //TODO - log to file
}
Run Code Online (Sandbox Code Playgroud)

最后使用代码:

Datamodel.SubmitChangesWithDetailException();
Run Code Online (Sandbox Code Playgroud)


RaR*_*EvA 8

只是想贡献一些额外的信息:我有同样的问题,这是因为该字段对于传入的数据来说不够大,而且这个线程帮助我解决了它(最重要的答案澄清了一切).

但是,了解可能导致这种情况的可能原因非常重要.

在我的情况下,我用这样的字段创建表:

Select '' as  Period, * From Transactions Into #NewTable
Run Code Online (Sandbox Code Playgroud)

因此,字段"Period"的长度为零,导致Insert操作失败.我将其更改为"XXXXXX",这是传入数据的长度,它现在正常工作(因为字段现在有一个6的lentgh).

我希望这可以帮助任何有同样问题的人:)


小智 7

您可以获得此错误的另一种情况如下:

我有同样的错误,原因是在从UNION接收数据的INSERT语句中,列的顺序与原始表不同.如果将#table3中的顺序更改为a,b,c,则将修复错误.

select a, b, c into #table1
from #table0

insert into #table1
    select a, b, c from #table2
    union
    select a, c, b from #table3
Run Code Online (Sandbox Code Playgroud)


web*_*Mac 7

Web应用程序表面也出现此问题.最终发现相同的错误消息来自特定表中的SQL更新语句.

最后,我们发现相关历史表中的列定义没有映射nvarchar某些特定情况下类型的原始表列长度.

希望这个暗示也可以帮助其他人..;)


Esp*_*o57 7

在SQL Server上你可以像这样使用SET ANSI_WARNINGS OFF:

        using (SqlConnection conn = new SqlConnection("Data Source=XRAYGOAT\\SQLEXPRESS;Initial Catalog='Healthy Care';Integrated Security=True"))
        {
            conn.Open();

            using (var trans = conn.BeginTransaction())
            {
                try
                {
                    using cmd = new SqlCommand("", conn, trans))
                    { 

                    cmd.CommandText = "SET ANSI_WARNINGS OFF";
                    cmd.ExecuteNonQuery();

                    cmd.CommandText = "YOUR INSERT HERE";
                    cmd.ExecuteNonQuery();

                    cmd.Parameters.Clear();

                    cmd.CommandText = "SET ANSI_WARNINGS ON";
                    cmd.ExecuteNonQuery();

                    trans.Commit();
                    }
                }
                catch (Exception)
                {

                    trans.Rollback();
                }

            }

            conn.Close();

        }
Run Code Online (Sandbox Code Playgroud)


use*_*359 7

我遇到过同样的问题.我的专栏的长度太短了.您可以做的是增加长度或缩短要放入数据库的文本.


Mar*_*Roy 5

我遇到了同样的问题,即使增加了表中有问题的列的大小。

tl;dr:对应表类型中匹配列的长度也可能需要增加。

就我而言,错误来自 Microsoft Dynamics CRM 中的数据导出服务,该服务允许将 CRM 数据同步到 SQL Server DB 或 Azure SQL DB。

经过长时间的调查,我得出结论,数据导出服务必须使用表值参数

您可以使用表值参数将多行数据发送到 Transact-SQL 语句或例程,例如存储过程或函数,而无需创建临时表或许多参数。

正如您在上面的文档中看到的,表类型用于创建数据摄取过程:

CREATE TYPE LocationTableType AS TABLE (...);
CREATE PROCEDURE dbo.usp_InsertProductionLocation
  @TVP LocationTableType READONLY
Run Code Online (Sandbox Code Playgroud)

不幸的是,无法更改表类型,因此必须完全删除并重新创建它。由于我的表有 300 多个字段 (),因此我创建了一个查询以方便根据表的列定义创建相应的表类型(只需替换[table_name]为您的表名):

SELECT 'CREATE TYPE [table_name]Type AS TABLE (' + STRING_AGG(CAST(field AS VARCHAR(max)), ',' + CHAR(10)) + ');' AS create_type
FROM (
  SELECT TOP 5000 COLUMN_NAME + ' ' + DATA_TYPE
      + IIF(CHARACTER_MAXIMUM_LENGTH IS NULL, '', CONCAT('(', IIF(CHARACTER_MAXIMUM_LENGTH = -1, 'max', CONCAT(CHARACTER_MAXIMUM_LENGTH,'')), ')'))
      + IIF(DATA_TYPE = 'decimal', CONCAT('(', NUMERIC_PRECISION, ',', NUMERIC_SCALE, ')'), '')
      AS field
  FROM INFORMATION_SCHEMA.COLUMNS
  WHERE TABLE_NAME = '[table_name]'
  ORDER BY ORDINAL_POSITION) AS T;
Run Code Online (Sandbox Code Playgroud)

更新表类型后,数据导出服务再次开始正常运行!:)