помилка, рядок або двійкові дані будуть врізані при спробі вставки


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?

Відповіді:


609

З відповіді @ gmmastros

Щоразу, коли ви бачите повідомлення ...

рядкові або двійкові дані будуть усічені

Подумайте самі ... Поле НЕ достатньо велике, щоб зберігати мої дані.

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


16
Також зауважте, що порушені поля можуть бути тригером. Сподіваюся, я пам'ятаю це наступного разу, коли це станеться ...
Кевін Папа

14
Чи є якийсь спосіб побачити в налагодженні, яке поле було б усічене?
DailyFrankPeter

Ця помилка пояснюється тим, що ваш стовпець не може зберігати дані після встановленої вами довжини. Наприклад; Firstname nvarchar(5) Якщо ви вставите більше 5 символів, ви отримаєте помилку
Пракаш

26

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


1
Дякую. Моє було тому, що стовпець sql у таблиціA є varchar (100). Він також вставляється до іншої таблиці, у якій стовпець - варчар (50).
Hnin Htet Htet Aung

1
Така ж проблема трапилася і в моєму випадку. Винуватець тригерної операції.
автопілот

19

В одному з INSERTвисловлювань ви намагаєтеся вставити занадто довгий рядок у рядок ( varcharабоnvarchar ).

Якщо не очевидно, хто INSERTє правопорушником простим переглядом сценарію, ви можете порахувати <1 row affected>рядки, що виникають перед повідомленням про помилку. Отримане число плюс одне дає номер виписки. У вашому випадку, здається, це другий ВСТУП, який видає помилку.


2
У мене те саме питання, як знайти, який стовпець викликає помилку?
Катіа Матос

@ AndréBastos: Можливо, ви могли б подати це як запитання (якщо хтось ще не зробив цього, і в цьому випадку десь може бути готовий відповідь на нього).
Андрій М

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

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

Я сподіваюся, що це допоможе будь-кому з тим же питанням :)


7

Ще одна ситуація, в якій можна отримати цю помилку, така:

У мене була така ж помилка, і причина полягала в тому, що в операторі 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 ви можете використовувати 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

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

Нарешті потім з'ясували, що визначення стовпців у відповідних таблицях історії не відображає початкову довжину стовпців таблиці nvarcharу деяких конкретних випадках.


4

У мене була така ж проблема навіть після збільшення розміру проблемних стовпців у таблиці.

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;

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


2

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

Ви можете збільшити розмір типу даних стовпців або зменшити довжину даних.


1

Інша ситуація, в якій може виникнути ця помилка, знаходиться в студії управління SQL Server. Якщо у вашій таблиці є поля "текст" або "ntext", незалежно від того, яке поле ви оновлюєте (наприклад, біт або ціле число). Здається, що Studio не завантажує цілі поля "ntext", а також оновлює ВСІ поля замість модифікованого. Щоб вирішити проблему, виключіть поля "текст" або "ntext" із запиту в студії управління


1
Запропонуйте перефразовувати свою відповідь, додаючи коми, крапки та виправляючи свої граматичні помилки.
Джордж Памфіліс

Ця відповідь допомогла мені - мої поля nvarchar досить великі, але у мене є поле ntext. Здається, це є деякою помилкою в Management Studio / SMSS.
Ша

0

Коментар Кевіна Попа під прийнятою відповіддю було те, що мені було потрібно.

Проблема, в моєму випадку, полягала в тому, що в моїй таблиці були визначені тригери, які б вставляли операції оновлення / вставлення в таблицю аудиту, але таблиця аудиту мала невідповідність типу даних, де стовпчик із 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

Я хотів швидкості, оскільки у мене є 1М загальних записів, і завантажую 28К з них.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.