Ошибка, строковые или двоичные данные будут усечены при попытке вставить

Я запускаю файл 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?

Ответ 1

От @gmmastros ответ

Всякий раз, когда вы видите сообщение....

string or binary data would be truncated 

Подумайте сами... Поле НЕ достаточно большое, чтобы хранить мои данные.

Проверьте структуру таблицы для таблицы клиентов. Я думаю, вы обнаружите, что длина одного или нескольких полей НЕ достаточна для хранения данных, которые вы пытаетесь вставить. Например, если поле "Телефон" является полем varchar (8), и вы пытаетесь поместить в него 11 символов, вы получите эту ошибку.

Ответ 2

У меня была эта проблема, хотя длина данных была меньше длины поля. Оказалось, что проблема связана с другой таблицей журналов (для контрольного журнала), заполненной триггером в главной таблице, где также должен был быть изменен размер столбца.

Ответ 3

В одном из операторов INSERT вы пытаетесь вставить слишком длинную строку в столбец строки (varchar или nvarchar).

Если не очевидно, что INSERT является нарушителем простым просмотром script, вы можете подсчитать строки <1 row affected>, которые возникают до сообщения об ошибке. Полученный номер плюс один дает вам номер выписки. В вашем случае это, по-видимому, второй INSERT, который вызывает ошибку.

Ответ 4

Некоторые ваши данные не могут вписаться в столбец базы данных (маленький). Нелегко найти, что не так. Если вы используете С# и 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();

Ответ 5

Просто хочу внести дополнительную информацию: у меня была та же проблема, и это было из-за того, что поле было недостаточно большим для входящих данных, и этот поток помог мне решить эту проблему (верхний ответ проясняет все это).

НО очень важно знать, каковы возможные причины, которые могут вызвать это.

В моем случае я создавал таблицу с таким полем:

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

Поэтому поле "Период" имеет длину ноль и приводит к сбою операций вставки. Я изменил его на "XXXXXX", то есть длину входящих данных, и теперь он работал правильно (потому что поле теперь имело длину 6).

Я надеюсь, что это поможет любому с тем же вопросом :)

Ответ 6

Другая ситуация, в которой вы можете получить эту ошибку, следующая:

У меня была такая же ошибка, и причина в том, что в инструкции INSERT, которая получала данные из UNION, порядок столбцов отличался от исходной таблицы. Если вы измените порядок в # 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 update в конкретной таблице.

Наконец, тогда выяснилось, что определение colum в таблице (-ях) связанной истории не отображает исходную длину столбца таблицы типов nvarchar в некоторых конкретных случаях.

Надеюсь, этот намек поможет и кому-то другому.;)

Ответ 8

на сервере sql вы можете использовать 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();

        }

Ответ 9

У меня была такая же проблема. Длина длины моей колонки была слишком короткой. То, что вы можете сделать, это либо увеличить длину, либо сократить текст, который вы хотите поместить в базу данных.

Ответ 10

У меня была такая же проблема, даже после увеличения размера проблемных столбцов в таблице.

tl; dr: Длина соответствующих столбцов в соответствующих типах таблиц также может потребоваться увеличить.

В моем случае ошибка исходила от службы экспорта данных в Microsoft Dynamics CRM, которая позволяет синхронизировать данные CRM с БД SQL Server или 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;

После обновления типа таблицы служба экспорта данных снова заработала! :)

Ответ 11

Когда я попытался выполнить свою хранимую процедуру, у меня возникла та же проблема, потому что размер столбца, который мне нужен для добавления некоторых данных, короче, чем данные, которые я хочу добавить. Вы можете увеличить размер типа данных столбца или уменьшить длину ваших данных.

Ответ 12

Другая ситуация, в которой может возникнуть эта ошибка, - в SQL Server Management Studio. Если в вашей таблице есть поля "текст" или "текст", независимо от того, какой тип поля вы обновляете (например, бит или целое число). Кажется, что Studio не загружает целые поля "ntext", а также обновляет ВСЕ поля вместо измененных. Чтобы решить эту проблему, исключите поля "текст" или "текст" из запроса в Management Studio

Ответ 13

Папа Кевина под принятым ответом был тем, что мне было нужно.

Проблема, в моем случае, заключалась в том, что в моей таблице были определены триггеры, которые вставляли бы транзакции обновления/вставки в таблицу аудита, но в таблице аудита было несоответствие типов данных, когда столбец с VARCHAR (MAX) в исходной таблице был хранится как VARCHAR (1) в таблице аудита, поэтому мои триггеры не работают, когда я вставляю в столбец исходной таблицы что-то большее, чем VARCHAR (1), и я получаю это сообщение об ошибке.

Надеюсь, это кому-нибудь поможет!