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


250

我正在运行以下行的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

data.sql文件的内容为:

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

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

另外,我显然是新手,但是Level #,它的state #意思和含义是什么,以及如何查找错误消息,例如上面的错误消息:8152?

Answers:


609

来自@gmmastros的答案

每当您看到消息时...

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

想一想...这个领域还不够大,无法保存我的数据。

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


16
另请注意,受影响的字段可能在触发器中。希望我下次记得这件事...
Kevin Pope

14
有什么办法可以在调试中看到哪个字段会被截断吗?
DailyFrankPeter '17

此错误是因为您的列在固定长度后无法保存数据。例如; Firstname nvarchar(5) 如果您输入的字符超过5个,则会出现错误
-Prakash

26

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


1
谢谢。我的原因是因为tableA中的sql列是varchar(100)。它还插入到另一个表中,该列为varchar(50)。
Hnin Htet Htet Aung 2015年

1
我的情况也发生了同样的问题。触发操作是罪魁祸首。
自动驾驶

19

在其中一种INSERT语句中,您试图在字符串(varcharnvarchar)列中插入太长的字符串。

如果INSERT仅通过查看脚本就不知道是哪个罪犯,则可以计算出错误消息之前<1 row affected>出现的行数。所获得的数字加一会为您提供对帐单编号。在您的情况下,似乎是第二个INSERT产生了错误。


2
我遇到了同样的问题,如何查找导致错误的列?
卡蒂亚·马托斯

@AndréBastos:也许您可以提出一个问题(除非其他人已经这样做了,在这种情况下,某个地方可能已经准备好了答案)。
Andriy M

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

                }
            }
        }
    }
}

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

9

只是想提供更多信息:我遇到了同样的问题,这是因为字段不够大,无法容纳传入的数据,并且该线程帮助我解决了问题(最重要的答案将其全部弄清楚了)。

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

在我的情况下,我正在使用如下字段创建表:

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

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

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


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

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

        }

7

我遇到过同样的问题。该长度我柱过短。

您可以做的是增加长度或缩短要放入数据库中的文本。


7

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

最后,然后确定nvarchar在某些特定情况下,相关历史记录表中的列定义未映射类型的原始表列长度。


4

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

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

不幸的是,无法更改表类型,因此必须完全删除并重新创建它。由于我的表有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;

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


2

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

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


1

可能发生此错误的另一种情况是在SQL Server Management Studio中。如果表中有“文本”或“ ntext”字段,则无论您要更新哪种字段(例如,位或整数)。似乎Studio不会加载整个“ ntext”字段,并且还会更新ALL字段而不是修改后的字段。要解决此问题,请从Management Studio中的查询中排除“ text”或“ ntext”字段


1
请考虑通过添加逗号,句号并修复语法错误来改写答案。
乔治·潘菲利斯

这个答案对我有所帮助-我的nvarchar字段足够大,但是我有一个ntext字段。似乎是Management Studio / SMSS中的某些错误。

0

凯文·波普(Kevin Pope)在被接受的答案下评论就是我所需要的。

这个问题,在我而言,是我对我的表定义的触发器会插入更新/插入交易到一个审计表,但审计表有其中与列数据类型不匹配VARCHAR(MAX)的原始表被存储VARCHAR(1)在审计表,因此当我插入比VARCHAR(1)原始表列更大的内容时,触发器将失败,并且会显示此错误消息。


0

我使用了不同的策略,在某些地方分配了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条记录。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.