erro, string ou dados binários seriam truncados ao tentar inserir

250

Estou executando o arquivo data.bat com as seguintes linhas:

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

O conteúdo do arquivo data.sql é:

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

Existem mais 8 linhas semelhantes para adicionar registros.

Quando eu executo isso com start> run> cmd> c:\data.bat, eu recebo essa mensagem de erro:

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>

Além disso, eu sou um novato, obviamente, mas o que fazer Level #, e state #média, e como faço para procurar mensagens de erro como a citada acima: 8152?

Karthik
fonte

Respostas:

609

From @ gmmastros's answer

Sempre que você vir a mensagem ....

string ou dados binários seriam truncados

Pense consigo mesmo ... O campo NÃO é grande o suficiente para armazenar meus dados.

Verifique a estrutura da tabela para a tabela customers. Acho que você descobrirá que o comprimento de um ou mais campos NÃO é grande o suficiente para armazenar os dados que você está tentando inserir. Por exemplo, se o campo Telefone for um campo varchar (8) e você tentar inserir 11 caracteres, receberá esse erro.

Karthik
fonte
16
Observe também que os campos impactados podem estar em um gatilho. Espero que eu lembre-se disso na próxima vez que isso acontece ...
Kevin Pope
14
Existe alguma maneira de ver na depuração qual campo seria truncado?
DailyFrankPeter
Esse erro ocorre porque sua coluna não pode conter dados após o comprimento que você corrigiu. Por exemplo; Firstname nvarchar(5) Se você inserir mais de 5 caracteres que você obterá o erro
Prakash
26

Eu tive esse problema, embora o comprimento dos dados fosse menor que o comprimento do campo. O problema era ter outra tabela de log (para trilha de auditoria), preenchida por um gatilho na tabela principal, onde o tamanho da coluna também precisava ser alterado.

alterfox
fonte
1
Obrigado. O meu foi porque a coluna sql na tabela A é varchar (100). Também é inserido em outra tabela, na qual a coluna é varchar (50).
Hnin Htet Htet Aung
1
O mesmo problema também aconteceu no meu caso. Uma operação de gatilho foi o culpado.
piloto automático
19

Em uma das INSERTinstruções, você está tentando inserir uma sequência muito longa em uma coluna de sequência ( varcharou nvarchar).

Se não for óbvio qual INSERTé o ofensor apenas olhando o script, você pode contar as <1 row affected>linhas que ocorrem antes da mensagem de erro. O número obtido mais um fornece o número do extrato. No seu caso, parece ser o segundo INSERT que produz o erro.

Andriy M
fonte
2
Estou tendo o mesmo problema. Como descobrir qual coluna está causando o erro?
Cátia Matos
@ AndréBastos: Talvez você possa enviar isso como uma pergunta (a menos que alguém já tenha feito isso, nesse caso, pode haver uma resposta pronta em algum lugar).
187 Andriy M
11

Alguns dos seus dados não podem caber na coluna do banco de dados (pequena). Não é fácil encontrar o que está errado. Se você usa C # e Linq2Sql, pode listar o campo que seria truncado:

Primeiro crie a classe auxiliar:

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

                }
            }
        }
    }
}

Em seguida, prepare o wrapper para 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;
        }
    }
}

Prepare o manipulador de exceção global e os detalhes de truncamento de log:

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

Por fim, use o código:

Datamodel.SubmitChangesWithDetailException();
Tomas Kubes
fonte
9

Só quero contribuir com informações adicionais: tive o mesmo problema e foi por causa do campo não ser grande o suficiente para os dados recebidos e esse segmento me ajudou a resolvê-lo (a resposta principal esclarece tudo).

MAS é muito importante saber quais são as possíveis razões que podem causar isso.

No meu caso, eu estava criando a tabela com um campo como este:

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

Portanto, o campo "Período" tinha um comprimento zero e fazia com que as operações de inserção falhassem. Alterei para "XXXXXX", que é o comprimento dos dados recebidos e agora funcionava corretamente (porque o campo agora possuía um comprimento de 6).

Espero que isso ajude alguém com o mesmo problema :)

RaRdEvA
fonte
7

Outra situação em que você pode obter esse erro é o seguinte:

Eu tive o mesmo erro e o motivo foi que, em uma instrução INSERT que recebeu dados de um UNION, a ordem das colunas era diferente da tabela original. Se você alterar a ordem na # tabela3 para a, b, c, você corrigirá o erro.

select a, b, c into #table1
from #table0

insert into #table1
    select a, b, c from #table2
    union
    select a, c, b from #table3
hola77
fonte
7

no servidor sql, você pode usar SET ANSI_WARNINGS OFF assim:

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

        }
Esperento57
fonte
7

Eu tive o mesmo problema. O comprimento da minha coluna era muito curto.

O que você pode fazer é aumentar o tamanho ou diminuir o texto que você deseja colocar no banco de dados.

bizimunda
fonte
7

Também ocorreu esse problema na superfície do aplicativo da web. Eventualmente, descobriu que a mesma mensagem de erro vem da instrução de atualização SQL na tabela específica.

Finalmente, descobrimos que a definição da coluna nas tabelas de histórico relacionadas não mapeia o comprimento dos nvarchartipos originais da coluna da tabela em alguns casos específicos.

webMac
fonte
4

Eu tive o mesmo problema, mesmo depois de aumentar o tamanho das colunas problemáticas na tabela.

tl; dr: O comprimento das colunas correspondentes nos tipos de tabela correspondentes também pode precisar ser aumentado.

No meu caso, o erro ocorreu no serviço de exportação de dados no Microsoft Dynamics CRM, que permite que os dados do CRM sejam sincronizados com um banco de dados do SQL Server ou com o Azure SQL DB.

Após uma longa investigação, concluí que o serviço de exportação de dados deve estar usando parâmetros com valor de tabela :

Você pode usar parâmetros com valor de tabela para enviar várias linhas de dados para uma instrução ou rotina do Transact-SQL, como um procedimento ou função armazenada, sem criar uma tabela temporária ou muitos parâmetros.

Como você pode ver na documentação acima, os Tipos de tabela são usados ​​para criar o procedimento de ingestão de dados:

CREATE TYPE LocationTableType AS TABLE (...);
CREATE PROCEDURE dbo.usp_InsertProductionLocation
  @TVP LocationTableType READONLY

Infelizmente, não há como alterar um Tipo de tabela, portanto, ele deve ser descartado e recriado inteiramente. Como minha tabela possui mais de 300 campos (😱), criei uma consulta para facilitar a criação do tipo de tabela correspondente com base na definição de colunas da tabela (basta substituir [table_name]pelo nome da tabela):

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;

Após atualizar o Tipo de tabela, o serviço de exportação de dados voltou a funcionar corretamente! :)

Marco Roy
fonte
2

Quando tentei executar meu procedimento armazenado, tive o mesmo problema, porque o tamanho da coluna que eu preciso adicionar alguns dados é menor que os dados que eu quero adicionar.

Você pode aumentar o tamanho do tipo de dados da coluna ou reduzir o comprimento dos seus dados.

Chamila Maddumage
fonte
1

Outra situação na qual esse erro pode ocorrer está no SQL Server Management Studio. Se você tiver campos "text" ou "ntext" em sua tabela, não importa que tipo de campo você esteja atualizando (por exemplo, bit ou número inteiro). Parece que o Studio não carrega campos inteiros "ntext" e também atualiza TODOS os campos em vez do modificado. Para resolver o problema, exclua os campos "texto" ou "ntext" da consulta no Management Studio

Sevast
fonte
1
Considere reformular sua resposta adicionando vírgulas, pontos e corrigindo seus erros gramaticais.
George Pamfilis
Essa resposta me ajudou - meus campos nvarchar são grandes o suficiente, mas eu tenho um campo ntext. Parece haver algum erro no Management Studio / SMSS.
Sha
0

O comentário de Kevin Pope sob a resposta aceita foi o que eu precisava.

O problema, no meu caso, era que eu tinha gatilhos definidos na minha tabela que inseriam transações de atualização / inserção em uma tabela de auditoria, mas a tabela de auditoria tinha uma incompatibilidade de tipo de dados em que uma coluna VARCHAR(MAX)na tabela original era armazenada como VARCHAR(1)na tabela tabela de auditoria, então meus gatilhos falharam quando eu inseria algo maior que VARCHAR(1)na coluna da tabela original e recebia essa mensagem de erro.

Irmãos
fonte
0

Eu usei uma tática diferente, campos que são alocados 8K em alguns lugares. Aqui apenas 50/100 são usados.

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

Eu queria velocidade, já que tenho 1 milhão de registros totais e carrego 28 mil deles.

Hans Schulze
fonte