我运行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

数据的内容。SQL文件是:

   insert Customers
            (CustomerID, CompanyName, Phone)
             Values('101','Southwinds','19126602729')

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

当我运行这个开始>运行> 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>

此外,我显然是一个新手,但级别#和状态#意味着什么,我如何查找错误消息,如上面的一个:8152?


来自@gmmastros的回答

当您看到消息....时

字符串或二进制数据将被截断

想想自己……字段不够大,容不下我的数据。

检查客户表的表结构。我认为您会发现一个或多个字段的长度不足以容纳您试图插入的数据。例如,如果Phone字段是varchar(8)字段,并且您尝试在其中放入11个字符,则会得到此错误。

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

如果仅仅通过查看脚本还不清楚哪个INSERT是违规者,那么可以计算错误消息之前出现的<1行受影响的>行。得到的数字加1就是陈述号。在您的例子中,似乎是第二个INSERT产生了错误。

你可以得到这个错误的另一种情况是:

我也犯了同样的错误,原因是在一个从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

我有这个问题,尽管数据长度比字段长度短。 事实证明,问题在于有另一个日志表(用于审计跟踪),由主表上的触发器填充,其中的列大小也必须更改。

有些数据无法放入数据库列中(小)。要发现哪里有问题并不容易。如果你使用c#和Linq2Sql,你可以列出将被截断的字段:

首先创建helper类:

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);
                    }

                }
            }
        }
    }
}

然后为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;
        }
    }
}

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

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

最后使用代码:

Datamodel.SubmitChangesWithDetailException();

也有这个问题发生在web应用程序表面。 最终发现相同的错误消息来自特定表中的SQL更新语句。

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

只是想提供额外的信息:我也有同样的问题,这是因为字段对传入的数据不够大,这个线程帮助我解决了这个问题(上面的答案澄清了一切)。

但是,了解可能导致它的可能原因是非常重要的。

在我的情况下,我创建了一个字段像这样的表:

Select '' as  Period, * From Transactions Into #NewTable

因此,字段“Period”的长度为零,导致插入操作失败。我将其更改为“XXXXXX”,这是输入数据的长度,现在它可以正常工作(因为字段现在的长度为6)。

我希望这对有同样问题的人有帮助:)

在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();

        }

我也有同样的问题。我的专栏太短了。

您所能做的就是增加或缩短想要放入数据库中的文本的长度。

这种错误可能发生的另一种情况是 SQL Server Management Studio。如果你的表中有"text"或"ntext"字段, 不管你要更新什么类型的字段(例如位或整数)。 似乎工作室不加载整个“ntext”字段,也更新所有字段,而不是修改的字段。 要解决这个问题,请从Management Studio的查询中排除“text”或“ntext”字段

当我试图执行我的存储过程时,我遇到了同样的问题,因为我需要添加一些数据的列的大小比我想要添加的数据要短。

您可以增加列数据类型的大小或减少数据的长度。

凯文·波普在公认答案下的评论正是我所需要的。

在我的例子中,问题是我在我的表上定义了触发器,将更新/插入事务插入到审计表中,但审计表有一个数据类型不匹配,其中原始表中具有VARCHAR(MAX)的列存储为审计表中的VARCHAR(1),因此当我在原始表列中插入大于VARCHAR(1)的任何内容时,我的触发器失败,并且我会得到这个错误消息。

我使用了不同的策略,在某些地方分配了8K的字段。这里只使用了大约50/100。

declare @NVPN_list as table 
nvpn            varchar(50)
,nvpn_revision  varchar(5)
,nvpn_iteration INT
,mpn_lifecycle  varchar(30)
,mfr            varchar(100)
,mpn            varchar(50)
,mpn_revision   varchar(5)
,mpn_iteration  INT
-- ...
) INSERT INTO @NVPN_LIST 
SELECT  left(nvpn           ,50)    as nvpn
        ,left(nvpn_revision ,10)    as nvpn_revision
        ,nvpn_iteration
        ,left(mpn_lifecycle ,30)
        ,left(mfr           ,100)
        ,left(mpn           ,50)
        ,left(mpn_revision  ,5)
        ,mpn_iteration
        ,left(mfr_order_num ,50)
FROM [DASHBOARD].[dbo].[mpnAttributes] (NOLOCK) mpna

我想要速度,因为我总共有1M条记录,并加载了28K条记录。

此错误可能是由于字段大小小于您输入的数据。

例如,如果你的数据类型是nvarchar(7),如果你的值是'aaaaddddf',那么错误将显示为:

字符串或二进制数据将被截断

2016/2017更新将向您显示坏值和列。

新的跟踪标志将把旧的错误替换为新的2628错误,并打印出出错的列和值。Traceflag 460在2016年和2017年的最新累积更新中可用:

https://support.microsoft.com/en-sg/help/4468101/optional-replacement-for-string-or-binary-data-would-be-truncated

只要确保在你安装了CU之后,你启用了跟踪标志,或者是全局的或者是永久的在服务器上:

...或使用DBCC TRACEON:

https://learn.microsoft.com/en-us/sql/t-sql/database-console-commands/dbcc-traceon-trace-flags-transact-sql?view=sql-server-ver15

在这方面,你根本无法打败SQL Server。

你可以像这样插入一个新表:

select foo, bar
into tmp_new_table_to_dispose_later
from my_table

并将表定义与要插入数据的实际表进行比较。

有时有用,有时没用。

如果您尝试从临时表插入final/real表,它可能只是工作(例如,由于数据转换的工作方式与SSMS不同)。

另一种替代方法是以块的形式插入数据,而不是立即插入所有内容,插入前1000个,然后重复这个过程,直到找到一个有错误的块。至少您可以更好地了解表中不适合的内容。

如果有人在c#应用程序中遇到这个错误,我创建了一个简单的方法来查找违规字段:

获取要进行插入/更新的表中所有列的列宽。(我直接从数据库中得到这个信息。) 将列的宽度与我们试图插入/更新的值的宽度进行比较。

假设/限制:

数据库中表的列名与c#实体字段匹配。例如:如果你在数据库中有这样一列: 你需要让你的实体具有相同的列名: 公共类SomeTable { //其他字段 公共字符串SourceData{获取;设置;} } 每次插入/更新一个实体。在下面的演示代码中会更清楚。(如果您正在进行批量插入/更新,您可能需要修改它或使用其他解决方案。)

步骤1:

直接从数据库中获取所有列的列宽:

// For this, I took help from Microsoft docs website:
// https://learn.microsoft.com/en-us/dotnet/api/system.data.sqlclient.sqlconnection.getschema?view=netframework-4.7.2#System_Data_SqlClient_SqlConnection_GetSchema_System_String_System_String___
private static Dictionary<string, int> GetColumnSizesOfTableFromDatabase(string tableName, string connectionString)
{
    var columnSizes = new Dictionary<string, int>();
            
    using (var connection = new SqlConnection(connectionString))
    {
        // Connect to the database then retrieve the schema information.  
        connection.Open();

        // You can specify the Catalog, Schema, Table Name, Column Name to get the specified column(s).
        // You can use four restrictions for Column, so you should create a 4 members array.
        String[] columnRestrictions = new String[4];

        // For the array, 0-member represents Catalog; 1-member represents Schema;
        // 2-member represents Table Name; 3-member represents Column Name.
        // Now we specify the Table_Name and Column_Name of the columns what we want to get schema information.
        columnRestrictions[2] = tableName;

        DataTable allColumnsSchemaTable = connection.GetSchema("Columns", columnRestrictions);

        foreach (DataRow row in allColumnsSchemaTable.Rows)
        {
            var columnName = row.Field<string>("COLUMN_NAME");
            //var dataType = row.Field<string>("DATA_TYPE");
            var characterMaxLength = row.Field<int?>("CHARACTER_MAXIMUM_LENGTH");

            // I'm only capturing columns whose Datatype is "varchar" or "char", i.e. their CHARACTER_MAXIMUM_LENGTH won't be null.
            if(characterMaxLength != null)
            {
                columnSizes.Add(columnName, characterMaxLength.Value);
            }
        }

        connection.Close();
    }

    return columnSizes;
}

步骤2:

将列的宽度与我们试图插入/更新的值的宽度进行比较:

public static Dictionary<string, string> FindLongBinaryOrStringFields<T>(T entity, string connectionString)
{
    var tableName = typeof(T).Name;
    Dictionary<string, string> longFields = new Dictionary<string, string>();
    var objectProperties = GetProperties(entity);
    //var fieldNames = objectProperties.Select(p => p.Name).ToList();

    var actualDatabaseColumnSizes = GetColumnSizesOfTableFromDatabase(tableName, connectionString);
            
    foreach (var dbColumn in actualDatabaseColumnSizes)
    {
        var maxLengthOfThisColumn = dbColumn.Value;
        var currentValueOfThisField = objectProperties.Where(f => f.Name == dbColumn.Key).First()?.GetValue(entity, null)?.ToString();

        if (!string.IsNullOrEmpty(currentValueOfThisField) && currentValueOfThisField.Length > maxLengthOfThisColumn)
        {
            longFields.Add(dbColumn.Key, $"'{dbColumn.Key}' column cannot take the value of '{currentValueOfThisField}' because the max length it can take is {maxLengthOfThisColumn}.");
        }
    }

    return longFields;
}

public static List<PropertyInfo> GetProperties<T>(T entity)
{
    //The DeclaredOnly flag makes sure you only get properties of the object, not from the classes it derives from.
    var properties = entity.GetType()
                            .GetProperties(System.Reflection.BindingFlags.Public
                            | System.Reflection.BindingFlags.Instance
                            | System.Reflection.BindingFlags.DeclaredOnly)
                            .ToList();

    return properties;
}

演示:

假设我们试图插入SomeTable类的someTableEntity,它在我们的应用中是这样建模的:

public class SomeTable
{
    [Key]
    public long TicketID { get; set; }
    public string SourceData { get; set; }
}

它在我们的SomeDbContext中,像这样:

public class SomeDbContext : DbContext
{
    public DbSet<SomeTable> SomeTables { get; set; }
}

Db中的表SourceData字段为varchar(16),如下所示:

现在,我们将尝试在这个字段中插入一个长度超过16个字符的值,并捕获以下信息:

public void SaveSomeTableEntity()
{
    var connectionString = "server=SERVER_NAME;database=DB_NAME;User ID=SOME_ID;Password=SOME_PASSWORD;Connection Timeout=200";
        
    using (var context = new SomeDbContext(connectionString))
    {
        var someTableEntity = new SomeTable()
        {
            SourceData = "Blah-Blah-Blah-Blah-Blah-Blah"
        };
        
        context.SomeTables.Add(someTableEntity);
        
        try
        {
            context.SaveChanges();
        }
        catch (Exception ex)
        {
            if (ex.GetBaseException().Message == "String or binary data would be truncated.\r\nThe statement has been terminated.")
            {
                var badFieldsReport = "";
                List<string> badFields = new List<string>();
                
                // YOU GOT YOUR FIELDS RIGHT HERE:
                var longFields = FindLongBinaryOrStringFields(someTableEntity, connectionString);

                foreach (var longField in longFields)
                {
                    badFields.Add(longField.Key);
                    badFieldsReport += longField.Value + "\n";
                }
            }
            else
                throw;
        }
    }
}

badFieldsReport会有这样的值:

“SourceData”列不能接受的值 "啥啥啥"因为它能承受的最大长度是 16.

此错误仅当任何字段长度大于sql server数据库表结构中指定的字段长度时出现。

为了克服这个问题,你必须减少字段值的长度。 或者增加数据库表字段的长度。