ошибка, строка или двоичные данные будут обрезаны при попытке вставить - PullRequest
224 голосов
/ 08 апреля 2011

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

Ответы [ 12 ]

563 голосов
/ 08 апреля 2011

Из ответа @ gmmastros

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

string or binary data would be truncated 

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

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

20 голосов
/ 03 июля 2014

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

18 голосов
/ 08 апреля 2011

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

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

11 голосов
/ 29 августа 2015

Некоторые из ваших данных не помещаются в столбец вашей базы данных (маленький). Нелегко найти то, что не так. Если вы используете 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
    /// /3494960/stroka-ili-dvoichnye-dannye-budut-proignorirovany-isklychenie-linq-mogu-naiti-kakoe-pole-prevysilo-maksimalnuy-dlinu
    /// </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)
    {
        ///3494960/stroka-ili-dvoichnye-dannye-budut-proignorirovany-isklychenie-linq-mogu-naiti-kakoe-pole-prevysilo-maksimalnuy-dlinu
        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();
7 голосов
/ 25 октября 2016

на сервере 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();

        }
7 голосов
/ 18 августа 2016

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

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

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

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

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

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

7 голосов
/ 28 июля 2016

Также эта проблема возникала на поверхности веб-приложения.В конце концов выяснилось, что это же сообщение об ошибке исходит из оператора обновления SQL в конкретной таблице.

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

Надеюсь, что этот совет поможет кому-то еще ..;)

7 голосов
/ 24 апреля 2014

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

У меня была такая же ошибка, и причина была в том, что в операторе 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
6 голосов
/ 02 ноября 2017

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

3 голосов
/ 14 февраля 2019

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

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

В моем случае ошибка исходила от службы экспорта данных в Microsoft Dynamics CRM, которая позволяет синхронизировать данные CRM с БД SQL Server или Azure SQL.

После продолжительного расследования я пришел к выводу, что служба экспорта данных должна использовать Табличные параметры :

Вы можете использовать табличные параметры для отправки нескольких строк данных в инструкцию 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;

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...