I dati binari o stringa di SQL Server verrebbero troncati


149

Sono coinvolto in un progetto di migrazione dei dati. Ricevo il seguente errore quando provo a inserire i dati da una tabella in un'altra tabella (SQL Server 2005):

Messaggio 8152, livello 16, stato 13, riga 1
Dati stringa o binari verrebbero troncati.

Le colonne dei dati di origine corrispondono al tipo di dati e rientrano nelle definizioni di lunghezza delle colonne della tabella di destinazione, quindi non riesco a capire cosa potrebbe causare questo errore.


Ti dispiacerebbe pubblicare un po 'di codice e informazioni su ogni tabella?
Kevin Mansel,

Le tabelle sono entrambe abbastanza grandi, quindi pubblicherò solo la parte delle definizioni delle tabelle coinvolte e il codice: è accettabile?
Jim Evans,

Le definizioni della tabella e il codice sarebbero fantastici.
IAmTimCorey,

1
L'ultima volta che ho avuto questo problema, è stato con il trigger, il trigger stava inserendo i dati in una tabella di controllo. vale la pena controllare anche il grilletto.
Sachin Vishwakarma,

Risposte:


185

Dovrai pubblicare le definizioni delle tabelle per le tabelle di origine e di destinazione per consentirci di capire dove si trova il problema, ma la linea di fondo è che una delle tue colonne nella tabella di origine è più grande delle colonne di destinazione . Potrebbe essere che stai modificando i formati in un modo che non eri a conoscenza. Anche il modello di database da cui ci si sta spostando è importante per capirlo.


1
Per il mio commento sopra - verrà presto :)
Jim Evans il

3
Avevo affrontato lo stesso problema e ho dovuto confrontare tutti i tipi di colonna e le dimensioni di entrambe le tabelle per risolvere il problema.
Aziz Shaikh,

1
Dopo aver analizzato l'exececise di raccogliere le definizioni della tabella parziale e poi ottenere il mio codice sproc, la colonna offensiva mi è saltata addosso come un fulmine ... Grazie a tutti per il tuo contributo.
Jim Evans,

Non posso dirti quante volte ho fatto la stessa cosa. Sono contento che tu sia riuscito a risolvere il tuo problema.
IAmTimCorey,

Ti ho contrassegnato come prima risposta come risposta perché è stato ciò che mi ha portato a trovare la risposta :)
Jim Evans,

86

Come altri hanno già detto, uno dei tipi di dati delle colonne nella tabella di origine è più grande delle colonne di destinazione.

Una soluzione semplice è semplicemente disattivare l'avviso e consentire il troncamento. Quindi, se ricevi questo errore ma sei sicuro che sia accettabile che i dati nel tuo vecchio database / tabella vengano troncati (tagliati a misura) puoi semplicemente fare quanto segue;

SET ANSI_WARNINGS  OFF;
-- Your insert TSQL here.
SET ANSI_WARNINGS ON;

Come sopra, ricorda sempre di riattivare gli avvisi in seguito. Spero che aiuti.


1
Mi hai risparmiato alcune ore di lavoro! Prendi tutti i miei ringraziamenti!
Urasquirrel,

Allo stesso modo qui. A volte devo archiviare i dati in una tabella, ad esempio, da un servizio Web, in cui il tipo di dati è definito solo come una "stringa". Non riesco a rendere tutto un Varchar (MAX) ...
Curt

61

Il problema è piuttosto semplice: una o più colonne nella query di origine contengono dati che superano la lunghezza della colonna di destinazione. Una soluzione semplice sarebbe quella di prendere la tua query di origine ed eseguire Max(Len( source col ))su ogni colonna. Vale a dire,

Select Max(Len(TextCol1))
    , Max(Len(TextCol2))
    , Max(Len(TextCol3))
    , ...
From ...

Quindi confrontare tali lunghezze con le lunghezze dei tipi di dati nella tabella di destinazione. Almeno uno, supera la lunghezza della colonna di destinazione.

Se sei assolutamente sicuro che non dovrebbe essere così e non ti importa se non è il caso , un'altra soluzione è quella di eseguire il cast forzato delle colonne della query di origine alla loro lunghezza di destinazione (che troncerà tutti i dati troppo lunghi):

Select Cast(TextCol1 As varchar(...))
    , Cast(TextCol2 As varchar(...))
    , Cast(TextCol3 As varchar(...))
    , ...
From ...

Il mio processo quotidiano ha iniziato a rompersi con questo errore. I dati che inserivo erano sempre abbastanza corti da adattarsi e avevo sempre altre righe (nella tabella da cui stavo estraendo) con stringhe di grandi dimensioni che non venivano mai inserite a causa del mio filtro. Forse un indice è stato ricostruito o le statistiche sono state aggiornate, ma il fantasma nella macchina ha deciso un giorno che non gli piaceva più il piano di query, perché lo portava lungo un percorso in cui i dati (che erano troppo ampi) "potevano" essere inserito prima che fosse filtrato dal Predicato nella clausola Where. Per ovviare a questo, ho usato LEFT () invece di CAST - solo meno caratteri da digitare.
MikeTeeVee,

1
Grazie Thomas, è strano, anche se non ho dati troppo lunghi, devo ancora inviarlo alla nuova dimensione della colonna di destinazione, non appena l'ho fatto ha funzionato.
Michelle

15

SQL Server 2019 restituirà infine un messaggio di errore più significativo.

I dati binari o di stringa verrebbero troncati => miglioramenti del messaggio di errore

se hai quell'errore (in produzione), non è ovvio vedere da quale colonna o riga proviene questo errore e come individuarlo esattamente.

Per abilitare nuovi comportamenti è necessario utilizzare DBCC TRACEON(460). Nuovo testo di errore da sys.messages:

SELECT * FROM sys.messages WHERE message_id = 2628

2628 - I dati stringa o binari verrebbero troncati nella tabella '%. * Ls', colonna '%. * Ls'. Valore troncato: '%. * Ls'.

I dati stringa o binari verrebbero troncati: sostituendo il famigerato errore 8152

Questo nuovo messaggio è anche backportato in CU12 di SQL Server 2017 (e in una CU di SQL Server 2016 SP2 in arrivo), ma non per impostazione predefinita. È necessario abilitare il flag di traccia 460 per sostituire l'ID messaggio 8152 con 2628, a livello di sessione o server.

Si noti che per ora, anche in SQL Server 2019 CTP 2.0 è necessario abilitare lo stesso flag di traccia 460. In una futura versione di SQL Server 2019, il messaggio 2628 sostituirà il messaggio 8152 per impostazione predefinita.


Anche SQL Server 2017 CU12 supporta questa funzionalità.

Miglioramento: sostituzione facoltativa per il messaggio "Dati binari o troncati verrebbero troncati" con informazioni estese in SQL Server 2017

Questo aggiornamento di SQL Server 2017 introduce un messaggio facoltativo che contiene le seguenti informazioni aggiuntive sul contesto.

Msg 2628, Level 16, State 6, Procedure ProcedureName, Line Linenumber
String or binary data would be truncated in table '%.*ls', column '%.*ls'.
Truncated value: '%.*ls'.

Il nuovo ID messaggio è 2628. Questo messaggio sostituisce il messaggio 8152 in qualsiasi output di errore se il flag di traccia 460 è abilitato.

db <> demo violino


CONFIGURAZIONE SCOPED ALTER DATABASE

VERBOSE_TRUNCATION_WARNINGS = {ON | OFF}

SI APPLICA A: SQL Server (a partire da SQL Server 2019 (15.x)) e Database SQL di Azure

Consente di abilitare o disabilitare la nuova stringa o i dati binari verrebbero troncati messaggio di errore. SQL Server 2019 (15.x) introduce un nuovo messaggio di errore più specifico (2628) per questo scenario:

String or binary data would be truncated in table '%.*ls', column'%.*ls'. Truncated value: '%.*ls'.

Se impostato su ON con livello di compatibilità del database 150, gli errori di troncamento generano il nuovo messaggio di errore 2628 per fornire più contesto e semplificare il processo di risoluzione dei problemi.

Se impostato su OFF nel livello di compatibilità del database 150, gli errori di troncamento generano il precedente messaggio di errore 8152.

Per il livello di compatibilità del database 140 o inferiore, il messaggio di errore 2628 rimane un messaggio di errore di opt-in che richiede l'attivazione del flag di traccia 460 e questa configurazione con ambito database non ha alcun effetto.


1
Questo è ora disponibile anche per SQL Azure: azure.microsoft.com/en-gb/updates/…
Ian Kemp

7

Un altro potenziale motivo di ciò è se si dispone di un'impostazione di valore predefinita per una colonna che supera la lunghezza della colonna. Sembra che qualcuno abbia toccato una colonna con una lunghezza di 5 ma il valore predefinito ha superato la lunghezza di 5. Questo mi ha fatto impazzire mentre stavo cercando di capire perché non funzionava su nessun inserto, anche se tutto quello che stavo inserendo era una singola colonna con un numero intero pari a 1. Poiché il valore predefinito nello schema della tabella aveva quel valore predefinito che violava, ha incasinato tutto - il che immagino ci porti alla lezione appresa - evitare di avere tabelle con valore predefinito nello schema. :)


1
Non credo che evitare i valori predefiniti sia una buona soluzione. I valori predefiniti sono molto utili. Non risolverei i "problemi" del database causati da errori di battitura rimuovendo i valori predefiniti ...
Jacob H,

3

Per gli altri, controlla anche la procedura memorizzata . Nel mio caso nella mia procedura memorizzata CustomSearchho accidentalmente dichiarato una lunghezza non sufficiente per la mia colonna, quindi quando ho inserito un big data ho ricevuto quell'errore anche se ho una grande lunghezza nel mio database. Ho appena cambiato la lunghezza della mia colonna nella mia ricerca personalizzata, l'errore scompare. Questo è solo per il promemoria. Grazie.


questo è esattamente quello che mi succede. le tabelle di origine / destinazione corrispondono bene, ma il proc memorizzato aveva una #table definita con una lunghezza più breve e lì non è riuscita. Grazie!
Joy Walker,

3

Questo può essere un errore impegnativo. Ecco alcune note tratte da https://connect.microsoft.com/SQLServer/feedback/details/339410/ cercare il commento di AmirCharania.

Ho modificato la risposta fornita da AmirCharania per i dati selezionati in una tabella effettiva, anziché in una tabella temporanea. Prima seleziona il tuo set di dati in una tabella di sviluppo, quindi esegui quanto segue:

WITH CTE_Dev
AS (
    SELECT C.column_id
        ,ColumnName = C.NAME
        ,C.max_length
        ,C.user_type_id
        ,C.precision
        ,C.scale
        ,DataTypeName = T.NAME
    FROM sys.columns C
    INNER JOIN sys.types T ON T.user_type_id = C.user_type_id
    WHERE OBJECT_ID = OBJECT_ID('YOUR TARGET TABLE NAME HERE, WITH SCHEMA')
    )
    ,CTE_Temp
AS (
    SELECT C.column_id
        ,ColumnName = C.NAME
        ,C.max_length
        ,C.user_type_id
        ,C.precision
        ,C.scale
        ,DataTypeName = T.NAME
    FROM sys.columns C
    INNER JOIN sys.types T ON T.user_type_id = C.user_type_id
    WHERE OBJECT_ID = OBJECT_ID('YOUR TEMP TABLE NAME HERE, WITH SCHEMA')
    )
SELECT *
FROM CTE_Dev D
FULL OUTER JOIN CTE_Temp T ON D.ColumnName = T.ColumnName
WHERE ISNULL(D.max_length, 0) < ISNULL(T.max_length, 999)

Sembra che MS abbia chiuso il sito Connect. Il nuovo collegamento a questo problema è: feedback.azure.com/forums/908035-sql-server/suggestions/… ... ancora contrassegnato come non pianificato. Penso che il commento a cui ti riferisci sia stato (ironicamente) troncato quando si è verificata la migrazione.
SWalters - Ripristina Monica

È interessante notare che il problema è stato riaperto con un titolo leggermente diverso: feedback.azure.com/forums/908035-sql-server/suggestions/… ed è stato elencato come "In revisione", quindi c'è ancora speranza.
SWalters - Ripristina Monica

3

Ecco una risposta leggermente diversa. I nomi e le lunghezze delle colonne potrebbero corrispondere, ma forse stai specificando le colonne nell'ordine sbagliato nell'istruzione SELECT. Supponiamo che tableX e tableY abbiano colonne con lo stesso nome, ma in ordine diverso


2

Oggi ho riscontrato questo problema e nella mia ricerca di una risposta a questo messaggio di errore informativo minimo ho trovato anche questo link:

https://connect.microsoft.com/SQLServer/feedback/details/339410/please-fix-the-string-or-binary-data-would-be-truncated-message-to-give-the-column-name

Quindi sembra che Microsoft non abbia in programma di espandersi presto sul messaggio di errore.

Quindi mi sono rivolto ad altri mezzi.

Ho copiato gli errori per eccellere:

(1 riga (e) interessate

(1 riga (e) interessate

(1 riga / e interessata / e) Msg 8152, Level 16, State 14, Line 13 String o binary data verrebbero troncati. La dichiarazione è stata chiusa.

(1 riga (e) interessate

contò il numero di righe in Excel, arrivò vicino al contatore dei record che causava il problema ... aggiustò il mio codice di esportazione per stampare l'SQL vicino ad esso ... quindi eseguì gli inserti di 5-10 sql attorno al problema sql e riuscito a individuare il problema uno, vedere la stringa che era troppo lunga, aumentare le dimensioni di quella colonna e quindi il file di importazione di grandi dimensioni non ha funzionato.

Un po 'di un trucco e una soluzione alternativa, ma quando sei partito con pochissima scelta fai quello che puoi.


2

Sì, ho anche questo tipo di problema.

REMARKS VARCHAR(500)
to
REMARKS VARCHAR(1000)

Qui, ho cambiato la lunghezza di REMARKS archiviata da 500 a 1000


2

Ho intenzione di aggiungere un'altra possibile causa di questo errore solo perché nessuno l'ha menzionato e potrebbe aiutare qualche persona futura (poiché l'OP ha trovato la sua risposta). Se la tabella in cui si sta inserendo ha dei trigger, potrebbe essere il trigger a generare l'errore. Ho visto questo accadere quando le definizioni dei campi delle tabelle sono state modificate, ma le tabelle di controllo no.


2

Sì - "una pinta in una pentola da mezza pinta non andrà". Non ho avuto molta fortuna (per qualsiasi motivo) con i vari SP suggeriti dalla gente, MA fintanto che le due tabelle sono nello stesso DB (o puoi inserirle nello stesso DB), puoi usare INFORMATION_SCHEMA. COLONNE per individuare i campi erranti, quindi:

select c1.table_name,c1.COLUMN_NAME,c1.DATA_TYPE,c1.CHARACTER_MAXIMUM_LENGTH,c2.table_name,c2.COLUMN_NAME, c2.DATA_TYPE,c2.CHARACTER_MAXIMUM_LENGTH
from [INFORMATION_SCHEMA].[COLUMNS] c1
left join [INFORMATION_SCHEMA].[COLUMNS] c2 on 
c1.COLUMN_NAME=c2.COLUMN_NAME
where c1.TABLE_NAME='MyTable1'
and c2.TABLE_NAME='MyTable2'
--and c1.DATA_TYPE<>c2.DATA_TYPE
--and c1.CHARACTER_MAXIMUM_LENGTH <> c2.CHARACTER_MAXIMUM_LENGTH
order by c1.COLUMN_NAME

Questo ti permetterà di scorrere su e giù, confrontando le lunghezze dei campi mentre procedi. Le sezioni commentate ti permettono di vedere (una volta decommentato, ovviamente) se ci sono discrepanze tra i tipi di dati, o mostrano specificamente quelle che differiscono nella lunghezza del campo - perché sono troppo pigro per scorrere - basta essere consapevoli del fatto che l'intera cosa è basata sulla fonte nomi di colonne corrispondenti a quelli del target.


Stavo per scrivere qualcosa del genere, ma hai appena reso facile. molto utile e ha funzionato come un fascino. Sono stato in grado di usarlo per confrontare una tabella con oltre 90 colonne e due di loro sono saltate fuori subito. Grazie!
Joy Walker,

1

Stavo usando una stringa vuota "" durante la creazione della tabella e quindi ricevevo l'errore "Messaggio 8152, i dati stringa o binari venivano troncati" al successivo aggiornamento. Ciò stava accadendo a causa del valore di aggiornamento contenente 6 caratteri e maggiore della definizione di colonna prevista. Ho usato "SPACE" per ovviare a questo solo perché sapevo che mi sarei aggiornato in blocco dopo la creazione iniziale dei dati, cioè la colonna non sarebbe rimasta vuota a lungo.

COSÌ GRANDE CAVEAT QUI: Questa non è una soluzione particolarmente brillante ma è utile nel caso in cui si stiano riunendo un set di dati, ad esempio per richieste di intelligence una tantum in cui si sta creando una tabella per il data mining, applicando l'elaborazione / interpretazione di massa e memorizzazione dei risultati prima e dopo per un successivo confronto / mining. Questo è un evento frequente nella mia linea di lavoro.

Inizialmente puoi popolare usando la parola chiave SPACE, ad es

    select 
           Table1.[column1]
          ,Table1.[column2]
          ,SPACE(10) as column_name
    into table_you_are_creating
    from Table1
    where ...

Saranno consentiti gli aggiornamenti successivi a "nome_colonna" di 10 caratteri o meno (sostituisci come applicabile) senza causare errori di troncamento. Ancora una volta, lo userei solo in scenari simili a quelli descritti nel mio avvertimento.


1

Ho creato una procedura memorizzata che analizza una tabella di origine o una query con diverse caratteristiche per colonna tra cui la lunghezza minima (min_len) e la lunghezza massima (max_len).

CREATE PROCEDURE [dbo].[sp_analysetable] (
  @tableName varchar(8000),
  @deep bit = 0
) AS

/*
sp_analysetable 'company'
sp_analysetable 'select * from company where name is not null'
*/

DECLARE @intErrorCode INT, @errorMSG VARCHAR(500), @tmpQ NVARCHAR(2000), @column_name VARCHAR(50), @isQuery bit
SET @intErrorCode=0

IF OBJECT_ID('tempdb..##tmpTableToAnalyse') IS NOT NULL BEGIN
  DROP TABLE ##tmpTableToAnalyse
END
IF OBJECT_ID('tempdb..##tmpColumns') IS NOT NULL BEGIN
  DROP TABLE ##tmpColumns
END

if CHARINDEX('from', @tableName)>0
  set @isQuery=1

IF @intErrorCode=0 BEGIN
  if @isQuery=1 begin
    --set @tableName = 'USE '+@db+';'+replace(@tableName, 'from', 'into ##tmpTableToAnalyse from')
    --replace only first occurance. Now multiple froms may exists, but first from will be replaced with into .. from
    set @tableName=Stuff(@tableName, CharIndex('from', @tableName), Len('from'), 'into ##tmpTableToAnalyse from')
    exec(@tableName)
    IF OBJECT_ID('tempdb..##tmpTableToAnalyse') IS NULL BEGIN
      set @intErrorCode=1
      SET @errorMSG='Error generating temporary table from query.'
    end
    else begin
      set @tableName='##tmpTableToAnalyse'
    end
  end
end

IF @intErrorCode=0 BEGIN
  SET @tmpQ='USE '+DB_NAME()+';'+CHAR(13)+CHAR(10)+'
  select
    c.column_name as [column],
    cast(sp.value as varchar(1000)) as description,
    tc_fk.constraint_type,
    kcu_pk.table_name as fk_table,
    kcu_pk.column_name as fk_column,
    c.ordinal_position as pos,
    c.column_default as [default],
    c.is_nullable as [null],
    c.data_type,
    c.character_maximum_length as length,
    c.numeric_precision as [precision],
    c.numeric_precision_radix as radix,
    cast(null as bit) as [is_unique],
    cast(null as int) as min_len,
    cast(null as int) as max_len,
    cast(null as int) as nulls,
    cast(null as int) as blanks,
    cast(null as int) as numerics,
    cast(null as int) as distincts,
    cast(null as varchar(500)) as distinct_values,
    cast(null as varchar(50)) as remarks
  into ##tmpColumns'
  if @isQuery=1 begin
    SET @tmpQ=@tmpQ+' from tempdb.information_schema.columns c, (select null as value) sp'
  end
  else begin
    SET @tmpQ=@tmpQ+'
      from information_schema.columns c
      left join sysobjects so    on so.name=c.table_name  and so.xtype=''U''
      left join syscolumns sc    on sc.name=c.column_name and sc.id  =so.id 
      left join sys.extended_properties sp on sp.minor_id = sc.colid AND sp.major_id = sc.id and sp.name=''MS_Description''  
      left join information_schema.key_column_usage kcu_fk    on kcu_fk.table_name = c.table_name     and c.column_name = kcu_fk.column_name
      left join information_schema.table_constraints tc_fk    on kcu_fk.table_name = tc_fk.table_name and kcu_fk.constraint_name = tc_fk.constraint_name
      left join information_schema.referential_constraints rc on rc.constraint_name = kcu_fk.constraint_name
      left join information_schema.table_constraints tc_pk    on rc.unique_constraint_name = tc_pk.constraint_name
      left join information_schema.key_column_usage kcu_pk    on tc_pk.constraint_name = kcu_pk.constraint_name
 '
  end
  SET @tmpQ=@tmpQ+' where c.table_name = '''+@tableName+''''

  exec(@tmpQ)
end

IF @intErrorCode=0 AND @deep = 1 BEGIN
  DECLARE
    @count_rows int,
    @count_distinct int,
    @count_nulls int,
    @count_blanks int,
    @count_numerics int,
    @min_len int,
    @max_len int,
    @distinct_values varchar(500)
  DECLARE curTmp CURSOR LOCAL FAST_FORWARD FOR
    select [column] from ##tmpColumns;
  OPEN curTmp
  FETCH NEXT FROM curTmp INTO @column_name
  WHILE @@FETCH_STATUS = 0 and @intErrorCode=0 BEGIN
    set @tmpQ = 'USE '+DB_NAME()+'; SELECT'+
      '  @count_rows=count(0), '+char(13)+char(10)+
      '  @count_distinct=count(distinct ['+@column_name+']),'+char(13)+char(10)+
      '  @count_nulls=sum(case when ['+@column_name+'] is null then 1 else 0 end),'+char(13)+char(10)+
      '  @count_blanks=sum(case when ltrim(['+@column_name+'])='''' then 1 else 0 end),'+char(13)+char(10)+
      '  @count_numerics=sum(isnumeric(['+@column_name+'])),'+char(13)+char(10)+
      '  @min_len=min(len(['+@column_name+'])),'+char(13)+char(10)+
      '  @max_len=max(len(['+@column_name+']))'+char(13)+char(10)+
      ' from ['+@tableName+']'
    exec sp_executesql @tmpQ,
                       N'@count_rows int OUTPUT,
                         @count_distinct int OUTPUT,
                         @count_nulls int OUTPUT,
                         @count_blanks int OUTPUT,
                         @count_numerics int OUTPUT,
                         @min_len int OUTPUT,
                         @max_len int OUTPUT',
                       @count_rows     OUTPUT,
                       @count_distinct OUTPUT,
                       @count_nulls    OUTPUT,
                       @count_blanks    OUTPUT,
                       @count_numerics OUTPUT,
                       @min_len        OUTPUT,
                       @max_len        OUTPUT

    IF (@count_distinct>10) BEGIN
      SET @distinct_values='Many ('+cast(@count_distinct as varchar)+')'
    END ELSE BEGIN
      set @distinct_values=null
      set @tmpQ = N'USE '+DB_NAME()+';'+
        '  select @distinct_values=COALESCE(@distinct_values+'',''+cast(['+@column_name+'] as varchar),  cast(['+@column_name+'] as varchar))'+char(13)+char(10)+
        '  from ('+char(13)+char(10)+
        '    select distinct ['+@column_name+'] from ['+@tableName+'] where ['+@column_name+'] is not null) a'+char(13)+char(10)
      exec sp_executesql @tmpQ,
                         N'@distinct_values varchar(500) OUTPUT',
                         @distinct_values        OUTPUT
    END
    UPDATE ##tmpColumns SET
      is_unique      =case when @count_rows=@count_distinct then 1 else 0 end,
      distincts      =@count_distinct,
      nulls          =@count_nulls,
      blanks         =@count_blanks,
      numerics       =@count_numerics,
      min_len        =@min_len,
      max_len        =@max_len,
      distinct_values=@distinct_values,
      remarks       =
        case when @count_rows=@count_nulls then 'all null,' else '' end+
        case when @count_rows=@count_distinct then 'unique,' else '' end+
        case when @count_distinct=0 then 'empty,' else '' end+
        case when @min_len=@max_len then 'same length,' else '' end+
        case when @count_rows=@count_numerics then 'all numeric,' else '' end
    WHERE [column]=@column_name

    FETCH NEXT FROM curTmp INTO @column_name
  END
  CLOSE curTmp DEALLOCATE curTmp
END

IF @intErrorCode=0 BEGIN
  select * from ##tmpColumns order by pos
end

IF @intErrorCode=0 BEGIN --Clean up temporary tables
  IF OBJECT_ID('tempdb..##tmpTableToAnalyse') IS NOT NULL BEGIN
    DROP TABLE ##tmpTableToAnalyse
  END
  IF OBJECT_ID('tempdb..##tmpColumns') IS NOT NULL BEGIN
    DROP TABLE ##tmpColumns
  END
end

IF @intErrorCode<>0 BEGIN
  RAISERROR(@errorMSG, 12, 1)
END
RETURN @intErrorCode

Conservo questa procedura nel database principale in modo da poterla utilizzare in ogni database in questo modo:

sp_analysetable 'table_name', 1
// deep=1 for doing value analyses

E l'output è:

column description constraint_type fk_table fk_column pos default null data_type length precision radix is_unique min_len max_len nulls blanks numerics distincts distinct_values remarks
id_individual NULL PRIMARY KEY NULL NULL 1 NULL NO int NULL 10 10 1 1 2 0 0 70 70 Many (70) unique,all numeric,
id_brand NULL NULL NULL NULL 2 NULL NO int NULL 10 10 0 1 1 0 0 70 2 2,3 same length,all numeric, guid NULL NULL NULL NULL 3 (newid()) NO uniqueidentifier NULL NULL NULL 1 36 36 0 0 0 70 Many (70) unique,same length,
customer_id NULL NULL NULL NULL 4 NULL YES varchar 50 NULL NULL 0 NULL NULL 70 0 0 0 NULL all null,empty,
email NULL NULL NULL NULL 5 NULL YES varchar 100 NULL NULL 0 4 36 0 0 0 31 Many (31)
mobile NULL NULL NULL NULL 6 NULL YES varchar 50 NULL NULL 0 NULL NULL 70 0 0 0 NULL all null,empty,
initials NULL NULL NULL NULL 7 NULL YES varchar 50 NULL NULL 0 NULL NULL 70 0 0 0 NULL all null,empty,
title_short NULL NULL NULL NULL 8 NULL YES varchar 50 NULL NULL 0 NULL NULL 70 0 0 0 NULL all null,empty,
title_long NULL NULL NULL NULL 9 NULL YES varchar 50 NULL NULL 0 NULL NULL 70 0 0 0 NULL all null,empty,
firstname NULL NULL NULL NULL 10 NULL YES varchar 50 NULL NULL 0 NULL NULL 70 0 0 0 NULL all null,empty,
lastname NULL NULL NULL NULL 11 NULL YES varchar 50 NULL NULL 0 NULL NULL 70 0 0 0 NULL all null,empty,
address NULL NULL NULL NULL 12 NULL YES varchar 100 NULL NULL 0 NULL NULL 70 0 0 0 NULL all null,empty,
pc NULL NULL NULL NULL 13 NULL YES varchar 10 NULL NULL 0 NULL NULL 70 0 0 0 NULL all null,empty,
kixcode NULL NULL NULL NULL 14 NULL YES varchar 20 NULL NULL 0 NULL NULL 70 0 0 0 NULL all null,empty,
date_created NULL NULL NULL NULL 15 (getdate()) NO datetime NULL NULL NULL 1 19 19 0 0 0 70 Many (70) unique,same length,
created_by NULL NULL NULL NULL 16 (user_name()) NO varchar 50 NULL NULL 0 13 13 0 0 0 1 loyalz-public same length,
id_location_created NULL FOREIGN KEY location id_location 17 NULL YES int NULL 10 10 0 1 1 0 0 70 2 1,2 same length,all numeric, id_individual_type NULL FOREIGN KEY individual_type id_individual_type 18 NULL YES int NULL 10 10 0 NULL NULL 70 0 0 0 NULL all null,empty,
optin NULL NULL NULL NULL 19 NULL YES int NULL 10 10 0 1 1 39 0 31 2 0,1 same length,


Nota a margine: è necessario non utilizzare il sp_prefisso per stored procedure. Microsoft ha riservato quel prefisso per il proprio uso (consultare Naming Stored Procedures ) e si corre il rischio di uno scontro di nomi in futuro. Fa anche male alle prestazioni della procedura memorizzata . È meglio semplicemente evitare sp_e usare qualcos'altro come prefisso - o nessun prefisso!
marc_s,

1

Ho scritto un'utile procedura di archivio per aiutare a identificare e risolvere il problema del troncamento del testo (i dati stringa o binari verrebbero troncati) quando viene utilizzata l'istruzione INSERT SELECT. Confronta i campi CHAR, VARCHAR, NCHAR E NVARCHAR e restituisce un campo di valutazione campo per campo nel caso in cui sia la possibile causa dell'errore.

EXEC dbo.GetFieldStringTruncate SourceTableName, TargetTableName

Questa procedura memorizzata è orientata al problema del troncamento del testo quando viene effettuata un'istruzione INSERT SELECT.

Il funzionamento di questa procedura memorizzata dipende dall'utente che ha precedentemente identificato l'istruzione INSERT con il problema. Quindi inserendo i dati di origine in una tabella temporanea globale. Si consiglia l'istruzione SELECT INTO.

È necessario utilizzare lo stesso nome del campo della tabella di destinazione nell'alias di ciascun campo dell'istruzione SELECT.

CODICE FUNZIONE:

DECLARE @strSQL nvarchar(1000)
IF NOT EXISTS (SELECT * FROM dbo.sysobjects where id = OBJECT_ID(N'[dbo].[GetFieldStringTruncate]'))
    BEGIN
        SET @strSQL = 'CREATE PROCEDURE [dbo].[GetFieldStringTruncate] AS RETURN'
        EXEC sys.sp_executesql @strSQL
    END

GO

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO

/*
------------------------------------------------------------------------------------------------------------------------
    Description:    
                    Syntax 
                    ---------------
                    dbo.GetFieldStringTruncate(SourceTable, TargetTable)
                    +---------------------------+-----------------------+
                    |   SourceTableName         |   VARCHAR(255)        |
                    +---------------------------+-----------------------+
                    |   TargetTableName         |   VARCHAR(255)        |
                    +---------------------------+-----------------------+

                    Arguments
                    ---------------
                    SourceTableName
                    The name of the source table. It should be a temporary table using double charp '##'. E.g. '##temp'

                    TargetTableName
                    The name of the target table. It is the table that receives the data used in the INSERT INTO stament.

                    Return Type
                    ----------------
                    Returns a table with a list of all the fields with the type defined as text and performs an evaluation indicating which field would present the problem of string truncation.

                    Remarks
                    ----------------
                    This stored procedure is oriented to the problem of text truncation when an INSERT SELECT statement is made.
                    The operation of this stored procedure depends on the user previously identifying the INSERT statement with the problem. Then inserting the source data into a global temporary table. The SELECT INTO statement is recommended.
                    You must use the same name of the field of the destination table in the alias of each field of the SELECT statement.

                    Examples
                    ====================================================================================================

                    --A. Test basic

                        IF EXISTS (SELECT * FROM sys.objects  WHERE OBJECT_ID = OBJECT_ID(N'[dbo].[tblDestino]') AND TYPE IN (N'U'))
                            DROP TABLE tblDestino

                        CREATE TABLE tblDestino
                        (
                            Id INT IDENTITY,
                            Field1 VARCHAR(10),
                            Field2 VARCHAR(12),
                            Field3 VARCHAR(11),
                            Field4 VARCHAR(16),
                            Field5 VARCHAR(5),
                            Field6 VARCHAR(1),
                            Field7 VARCHAR(1),
                            Field8 VARCHAR(6),
                            Field9 VARCHAR(6),
                            Field10 VARCHAR(50),
                            Field11 VARCHAR(50),
                            Field12 VARCHAR(50)
                        )

                        INSERT INTO dbo.tblDestino
                        (
                             Field1 ,
                             Field2 ,
                             Field3 ,
                             Field4 ,
                             Field5 ,
                             Field6 ,
                             Field7 ,
                             Field8 ,
                             Field9 ,
                             Field10 ,
                             Field11 ,
                             Field12
                            )
                        SELECT 
                             '123456789' , -- Field1 - varchar(10)
                             '123456789' , -- Field2 - varchar(12)
                             '123456789' , -- Field3 - varchar(11)
                             '123456789' , -- Field4 - varchar(16)
                             '123456789' , -- Field5 - varchar(5)
                             '123456789' , -- Field6 - varchar(1)
                             '123456789' , -- Field7 - varchar(1)
                             '123456789' , -- Field8 - varchar(6)
                             '123456789' , -- Field9 - varchar(6)
                             '123456789' , -- Field10 - varchar(50)
                             '123456789' , -- Field11 - varchar(50)
                             '123456789'  -- Field12 - varchar(50)
                        GO  

                    Result:
                        String or binary data would be truncated


                    *Here you get the truncation error. Then, we proceed to save the information in a global temporary table. 
                    *IMPORTANT REMINDER: You must use the same name of the field of the destination table in the alias of each field of the SELECT statement.


                    Process:

                        IF OBJECT_ID('tempdb..##TEMP') IS NOT NULL DROP TABLE ##TEMP
                        go
                        SELECT 
                             [Field1] = '123456789' ,
                             [Field2] = '123456789' ,
                             [Field3] = '123456789' ,
                             [Field4] = '123456789' ,
                             [Field5] = '123456789' ,
                             [Field6] = '123456789' ,
                             [Field7] = '123456789' ,
                             [Field8] = '123456789' ,
                             [Field9] = '123456789' ,
                             [Field10] = '123456789' ,
                             [Field11] = '123456789' ,
                             [Field12] = '123456789'  
                        INTO ##TEMP

                    Result:
                    (1 row(s) affected)

                    Test:
                        EXEC dbo.GetFieldStringTruncate @SourceTableName = '##TEMP', @TargetTableName = 'tblDestino'

                    Result:

                        (12 row(s) affected)
                        ORIGEN Nombre Campo        ORIGEN Maximo Largo  DESTINO Nombre Campo     DESTINO Tipo de campo   Evaluación
                        -------------------------- -------------------- ------------------------ ----------------------- -------------------------
                        Field1                     9                    02 - Field1              VARCHAR(10)             
                        Field2                     9                    03 - Field2              VARCHAR(12)             
                        Field3                     9                    04 - Field3              VARCHAR(11)             
                        Field4                     9                    05 - Field4              VARCHAR(16)             
                        Field5                     9                    06 - Field5              VARCHAR(5)              possible field with error
                        Field6                     9                    07 - Field6              VARCHAR(1)              possible field with error
                        Field7                     9                    08 - Field7              VARCHAR(1)              possible field with error
                        Field8                     9                    09 - Field8              VARCHAR(6)              possible field with error
                        Field9                     9                    10 - Field9              VARCHAR(6)              possible field with error
                        Field10                    9                    11 - Field10             VARCHAR(50)             
                        Field11                    9                    12 - Field11             VARCHAR(50)             
                        Field12                    9                    13 - Field12             VARCHAR(50)             

                    ====================================================================================================

    ------------------------------------------------------------------------------------------------------------

    Responsible:    Javier Pardo 
    Date:           October 19/2018
    WB tests:       Javier Pardo 

    ------------------------------------------------------------------------------------------------------------

*/

ALTER PROCEDURE dbo.GetFieldStringTruncate
(
    @SourceTableName AS VARCHAR(255)
    , @TargetTableName AS VARCHAR(255)
)
AS
BEGIN
    BEGIN TRY

        DECLARE @colsUnpivot AS NVARCHAR(MAX),
            @colsUnpivotConverted AS NVARCHAR(MAX),
           @query  AS NVARCHAR(MAX)

        SELECT @colsUnpivot = stuff((
                    SELECT DISTINCT ',' + QUOTENAME(col.NAME)
                    FROM tempdb.sys.tables tab
                    INNER JOIN tempdb.sys.columns col
                        ON col.object_id = tab.object_id
                    INNER JOIN tempdb.sys.types typ
                        ON col.system_type_id = TYP.system_type_id
                    WHERE tab.NAME = @SourceTableName
                    FOR XML path('')
                    ), 1, 1, '')
                ,@colsUnpivotConverted = stuff((
                    SELECT DISTINCT ',' + 'CONVERT(VARCHAR(MAX),' + QUOTENAME(col.NAME) + ') AS ' + QUOTENAME(col.NAME)
                    FROM tempdb.sys.tables tab
                    INNER JOIN tempdb.sys.columns col
                        ON col.object_id = tab.object_id
                    INNER JOIN tempdb.sys.types typ
                        ON col.system_type_id = TYP.system_type_id
                    WHERE tab.NAME = @SourceTableName
                    FOR XML path('')
                    ), 1, 1, '')


        --/programming/11158017/column-conflicts-with-the-type-of-other-columns-in-the-unpivot-list
        IF OBJECT_ID('tempdb..##TablaConMaximos') IS NOT NULL DROP TABLE ##TablaConMaximos

        set @query 
          = 'SELECT u.d AS colname, MAX(LEN(u.data)) as [maximo_largo]
            INTO ##TablaConMaximos
            FROM 
            (
                SELECT ' + @colsUnpivotConverted + '
                FROM ' + @SourceTableName + '
            ) T
            UNPIVOT
             (
                data
                for d in ('+ @colsunpivot +')
             ) u
             GROUP BY u.d'

        PRINT @query

        exec sp_executesql @query;

        ------------------------------------------------------------------------------------------------------------
        SELECT --'Nombre de campo' = RIGHT('00' + ISNULL(CONVERT(VARCHAR,col.column_id),''),2) + ' - ' + col.name + ' '
            --, 'Tipo de campo' = ISNULL(CONVERT(VARCHAR,upper(typ.name)),'') + '(' + ISNULL(CONVERT(VARCHAR,col.max_length),'') + ')'
            [ORIGEN Nombre Campo] = tcm.colname
            , [ORIGEN Maximo Largo] = tcm.maximo_largo
            , [DESTINO Nombre Campo] = DESTINO.[Nombre de campo]
            , [DESTINO Tipo de campo] = DESTINO.[Tipo de campo]
            , [Evaluación] = CASE WHEN DESTINO.maximo_largo < tcm.maximo_largo THEN 'possible field with error' ELSE '' END
            --, * 
        FROM tempdb.sys.tables tab
            INNER JOIN tempdb.sys.columns col
                ON col.object_id = tab.object_id
            INNER JOIN tempdb.sys.types typ
                ON col.system_type_id = TYP.system_type_id
            RIGHT JOIN 
                (
                    SELECT column_id
                        , [Nombre de campo] = RIGHT('00' + ISNULL(CONVERT(VARCHAR,col.column_id),''),2) + ' - ' + col.name + ' '
                        , [Tipo de campo] = ISNULL(CONVERT(VARCHAR,upper(typ.name)),'') + '(' + ISNULL(CONVERT(VARCHAR,col.max_length),'') + ')'
                        , [maximo_largo] = col.max_length
                        , [colname] = col.name
                    FROM sys.tables tab
                        INNER JOIN sys.columns col
                            ON col.object_id = tab.object_id
                        INNER JOIN sys.types typ
                            ON col.system_type_id = TYP.system_type_id
                    WHERE tab.NAME = @TargetTableName
                ) AS DESTINO
                    ON col.name = DESTINO.colname
            INNER JOIN ##TablaConMaximos tcm
                ON tcm.colname = DESTINO.colname

        WHERE tab.NAME = @SourceTableName
            AND typ.name LIKE '%char%'
        ORDER BY col.column_id

    END TRY
    BEGIN CATCH
        SELECT 'Internal error ocurred' AS Message
    END CATCH   

END

Per ora supporta solo i tipi di dati CHAR, VARCHAR, NCHAR e NVARCHAR . Puoi trovare l'ultima versione di questo codice nel seguente link seguente e ci aiutiamo a vicenda per migliorarlo. GetFieldStringTruncate.sql

https://gist.github.com/jotapardo/210e85338f87507742701aa9d41cc51d


1

Se sei su SQL Server 2016-2017: per risolverlo, attiva il flag di traccia 460

DBCC TRACEON(460, 1);
GO

e assicurati di spegnerlo dopo:

DBCC TRACEOFF(460, 1);
GO

fonte


0

questo può accadere anche quando non si dispone di autorizzazioni adeguate


2
Veramente? Un vero errore "Dati stringa o binari verrebbero troncati"? Sembra un errore molto strano se non si dispone delle autorizzazioni. Esiste un'autorizzazione che ti impedisce di scrivere più di una certa quantità di dati ?? (Sono interessato perché voglio verificare automaticamente la dimensione del campo quando ricevo questo errore - quindi se potrebbe verificarsi per qualche altro motivo è molto interessante!)
Ian Grainger

0

Ho avuto un problema simile. Stavo copiando i dati da una tabella a una tabella identica in tutto tranne che nel nome.

Alla fine ho scaricato la tabella di origine in una tabella temporanea usando un'istruzione SELECT INTO.

SELECT *
INTO TEMP_TABLE
FROM SOURCE_TABLE;

Ho confrontato lo schema della tabella di origine con la tabella temporanea. Ho scoperto che una delle colonne era una varchar(4000)quando mi aspettavo unavarchar(250) .

AGGIORNAMENTO: Il problema varchar (4000) può essere spiegato qui nel caso siate interessati:

Per Nvarchar (Max) sto ricevendo solo 4000 caratteri in TSQL?

Spero che questo ti aiuti.


0

Questo errore viene generato quando la colonna di una tabella mette un vincolo [principalmente lunghezza]. . Ad esempio, se lo schema del database per la colonna myColumn è CHAR (2), quando la chiamata da una qualsiasi applicazione per inserire un valore, è necessario passare String di lunghezza due.

L'errore sostanzialmente lo dice; la stringa di lunghezza tre e superiore non è coerente per adattarsi alla limitazione di lunghezza specificata dallo schema del database. Ecco perché SQL Server avverte e genera perdita di dati / errore di troncamento.


0

Prova il seguente codice:

CREATE TABLE [dbo].[Department](
    [Department_name] char(10) NULL
)

INSERT INTO [dbo].[Department]([Department_name]) VALUES  ('Family Medicine')
--error will occur

 ALTER TABLE [Department] ALTER COLUMN [Department_name] char(50)

INSERT INTO [dbo].[Department]([Department_name]) VALUES  ('Family Medicine')

select * from [Department]
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.