Come posso identificare le colonne responsabili di "Dati stringa o binari verrebbero troncati".


31

Sto generando alcune query automagicamente con il codice che ho scritto a SELECT da un database Pg remoto e inserisco in un database SQL Server locale. Tuttavia, uno di questi sta generando questo errore:

[Microsoft] [Driver ODBC SQL Server] [SQL Server] I dati stringa o binari verrebbero troncati. (SQL-22001) [lo stato era 22001 ora 01000]

[Microsoft] [Driver ODBC SQL Server] [SQL Server] L'istruzione è stata terminata. (SQL-01000) a. \ Insert.pl riga 106.

Come faccio a sapere quale colonna sta generando quell'errore e manca la lunghezza per l'input? C'è un modo per farlo senza indovinare la forza bruta varchar?

Risposte:


35

No, non è registrato da nessuna parte. Vai a votare e indica il tuo caso aziendale; questo è un lungo elenco di cose che dovrebbero essere riparate in SQL Server.

Ciò è stato richiesto anni fa su Connect (probabilmente prima in SQL Server 2000 o 2005), quindi di nuovo sul nuovo sistema di feedback:

E ora è stato consegnato, in SQL Server 2019 , SQL Server 2017 CU12 e apparirà in una futura CU di SQL Server 2016 SP2.

Nel primo CTP pubblico di SQL Server 2019, emerge solo sotto il flag di traccia 460. Sembra un po 'segreto, ma è stato pubblicato in questo white paper di Microsoft . Questo sarà il comportamento predefinito (non è richiesto alcun flag di traccia) in futuro, anche se sarai in grado di controllarlo tramite una nuova configurazione con ambito database VERBOSE_TRUNCATION_WARNINGS.

Ecco un esempio:

USE tempdb;
GO
CREATE TABLE dbo.x(a char(1));

INSERT dbo.x(a) VALUES('foo');
GO

Risultato in tutte le versioni supportate precedenti a SQL Server 2019:

Messaggio 8152, livello 16, stato 30, riga 5
Dati stringa o binari verrebbero troncati.
La dichiarazione è stata chiusa.

Ora, nei CTP di SQL Server 2019, con il flag di traccia abilitato:

DBCC TRACEON(460);
GO

INSERT dbo.x(a) VALUES('foo');
GO
DROP TABLE dbo.x;
DBCC TRACEOFF(460);

Il risultato mostra la tabella, la colonna e il valore ( troncato , non pieno ):

Messaggio 2628, livello 16, stato 1, riga 11
Dati stringa o binari verrebbero troncati nella tabella "tempdb.dbo.x", colonna "a". Valore troncato: 'f'.
La dichiarazione è stata chiusa.

Fino a quando non puoi rilasciare tutto e aggiornare a SQL Server 2019 o passare al database SQL di Azure, puoi modificare il codice "automagic" per estrarre effettivamente la max_length sys.columns, insieme al nome da cui devi arrivare comunque, quindi applicare LEFT(column, max_length)o qualunque sia l'equivalente di PG. Oppure, dal momento che ciò significa solo che perderai silenziosamente i dati, vai a capire quali colonne non corrispondono e correggi le colonne di destinazione in modo che si adattino a tutti i dati dall'origine. Dato l'accesso ai metadati a entrambi i sistemi e il fatto che stai già scrivendo una query che deve corrispondere automagicamente alle colonne di origine -> destinazione (altrimenti questo errore difficilmente sarebbe il tuo problema più grande), non dovresti fare alcuna forza bruta indovinando affatto.


2

Se si ha accesso per eseguire l' importazione / esportazione guidata di SQL Server da SQL Server Management Studio (fare clic con il pulsante destro del mouse su Database> Attività> Importa dati ...), creare un'attività che importa da SQL Client utilizzando la query come origine dati nella destinazione tavolo.

Prima di eseguire l'importazione, è possibile rivedere la mappatura dei dati e ti dirà quali colonne hanno tipi di campo incoerenti. E se esegui l'attività di importazione ti dirà quali colonne non sono state importate.

Avviso di convalida del campione:

Avviso 0x802092a7: Attività flusso di dati 1: Il troncamento può verificarsi a causa dell'inserimento di dati dalla colonna del flusso di dati "NARRATIVA" con una lunghezza di 316 alla colonna del database "NARRATIVA" con una lunghezza di 60. (Importazione / Esportazione guidata di SQL Server)


1

Alla fine, non sono riuscito a trovare un modo per ottenere le informazioni sulla colonna senza scriverle da solo.

Questo messaggio di errore è stato generato da DBD::ODBC, ma puoi anche usare sys.columns (max_length)(non so proprio come).

Ho usato codice come questo sul mio elenco di colonne per ottenere un elenco di matrici con due elementi, the COLUMN_NAMEe MAX_LENGTH(documentato in DBIcolumn_info() ).

my @max_lengths = map [ @{$_->fetchall_arrayref->[0]}[3,6] ]
    , map $dbh_mssql->column_info('database', 'dbo', $dest_table, $_)
    , @col_mssql
;

Poi ho colto le eccezioni INSERTe stampato qualcosa di utile. In questo esempio @$rowsono i dati inviati asth->execute()

if ($@) {
        warn "$@\n";
        for ( my $idx=0; $idx <= $#{ $row }; $idx++ ) {
                Dumper {
                        maxlength => $max_lengths[$idx]->[1]
                        , name    => $max_lengths[$idx]->[0]
                        , length  => length( $row->[$idx] )
                        , content => $row->[$idx]
                };
        }
        die;
}

Inoltre, si prega di votare e votare l'altra risposta


2
Non ho inserito alcun riferimento al codice sys.columnsperché non avevo assolutamente idea di quale codice stai attualmente utilizzando per "automagicamente" generare le tue query. Non c'è davvero troppo complesso che potrei immaginare di incorporare nel tuo codice di SELECT name, object_id, max_length FROM sys.columns;. Dal momento che hai già un codice automagico che deve fare questo - o qualcosa di molto simile - non pensavo fosse necessario un esempio.
Aaron Bertrand

Non sono sicuro di come sys.columnsfunzioni con due colonne che hanno lo stesso name. Inoltre, ho fatto funzionare la cosa usando la libreria piuttosto che sys, perché dovrei farlo come la risposta scelta? Microsoft SQL doesn't have x, do y insteadè un valido contributo, ma se il tuo yè inferiore al mio y, farò qualcosa di diverso e lo segnerò come scelto.
Evan Carroll,

1
La tua domanda era, essenzialmente, come faccio a sapere quale colonna stava generando l'errore (presumibilmente, in modo da poter risolvere quel punto, invece di riprogettare la soluzione). Ti ho detto dove cercare: sys.columns. È esattamente dove dovresti cercare di confrontare le lunghezze della colonna di origine con le lunghezze della colonna di destinazione. Come lo fai dipende da te. Non ti ho detto come riparare il tuo codice, perché non ho assolutamente idea di come la tua query automagic sia stata generata in primo luogo, quindi, come ho detto, non avevo idea di come aggiungere le determinazioni della lunghezza a qualsiasi query che avevi già .
Aaron Bertrand

1

Infine, Microsoft ha deciso di fornire informazioni significative a String or binary would be truncatedpartire da SQL Server 2016 SP2 CU, SQL Server 2017 CU12 e in SQL Server 2019.

Le informazioni ora includono sia la colonna della tabella offensiva (nome completo) sia il valore offensivo (troncato a 120 caratteri):

Messaggio 2628, livello 16, stato 1, riga x stringa o dati binari verrebbero troncati nella tabella "TheDb.TheSchema.TheTable", colonna "TheColumn". Valore troncato: '...'. La dichiarazione è stata chiusa.

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.