Come faccio a identificare le colonne responsabili di “ La stringa o i dati binari verrebbero troncati. ”

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

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

[Microsoft] [Driver ODBC SQL Server] [SQL Server] Listruzione è stata terminata. (SQL-01000) in. \ Insert.pl riga 106.

Come faccio a sapere quale colonna sta generando quellerrore e non ha la lunghezza per il ingresso? Esiste un modo per farlo senza indovinare con la forza bruta tutti i varchar?

Risposta

No, non è registrato da nessuna parte. Vai a votare e dichiara il tuo business case; questo è uno del lungo elenco di cose che dovrebbero essere risolte in SQL Server.

Questo è stato richiesto anni fa su Connect (probabilmente prima nel periodo di tempo di SQL Server 2000 o 2005), poi di nuovo sul nuovo sistema di feedback:

E ora è stato fornito nelle seguenti versioni:

Nel primo CTP pubblico di SQL Server 2019, viene visualizzato 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 (nessun flag di traccia richiesto) in futuro, sebbene sarai in grado di controllarlo tramite una nuova configurazione con ambito database VERBOSE_TRUNCATION_WARNINGS.

Qui è 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:

Msg 8152, livello 16, stato 30, riga 5, stringa o dati binari verrebbero troncati.
Listruzione è stata terminata.

Ora, sui 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 ( truncated , non full ) valore:

Msg 2628, livello 16, stato 1, riga 11
La stringa o i dati binari verrebbero troncati nella tabella “tempdb.dbo.x”, colonna “a”. Valore troncato: “f”.
Listruzione è stata terminata.

Fino a quando non sarà possibile passare a una versione / CU supportata o passare al database SQL di Azure, è possibile modificare il codice “automagic” per estrarre effettivamente max_length da sys.columns, insieme al nome che devi comunque arrivarci, quindi applicare LEFT(column, max_length) o qualunque sia lequivalente di PG. Oppure, dal momento che questo significa semplicemente che perderai i dati silenziosamente, cerca di capire quali colonne non corrispondono e aggiusta le colonne di destinazione in modo che si adattino a tutti i dati della sorgente. Dato laccesso ai metadati a entrambi i sistemi e il fatto che stai già scrivendo una query che deve corrispondere automaticamente alle colonne sorgente -> destinazione (altrimenti questo errore difficilmente sarebbe il tuo problema più grande), non dovresti fare forza bruta indovinare del tutto.

Risposta

Se hai accesso per eseguire Importazione ed esportazione guidata di SQL Server da SQL Server Management Studio (fare clic con il pulsante destro del mouse su database> Attività> Importa dati …), creare unattività che importi dal client SQL utilizzando la query come origine dati nella tabella di destinazione.

Prima di eseguire limportazione, puoi esaminare la mappatura dei dati e ti dirà quali colonne hanno tipi di campo incoerenti. E se esegui lattività di importazione, ti dirà quale colonna non è stata importata.

Avviso di convalida di esempio:

Avviso 0x802092a7: flusso di dati Attività 1: potrebbe verificarsi un troncamento a causa dellinserimento 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 ed esportazione guidata di SQL Server)

Risposta

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

Le informazioni ora include sia la colonna della tabella incriminata (nome completo) che il valore incriminato (troncato a 120 caratteri):

Msg 2628, livello 16, stato 1, Riga x Stringa o dati binari verrebbero troncati nella tabella “TheDb.TheSchema.TheTable “, colonna” TheColumn “. Valore troncato:” … “. Listruzione è stata terminata.

Risposta

In definitiva, 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 , tuttavia puoi anche utilizzare sys.columns (max_length) (non so come fare).

Ho utilizzato un codice come questo nel mio elenco di colonne per ottenere un elenco di array con due elementi, COLUMN_NAME e MAX_LENGTH (documentato in DBI column_info() ).

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

Poi ho rilevato le eccezioni su INSERT e ho stampato qualcosa di utile. In questo esempio @$row sono i dati inviati a sth->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, vota e vota a favore dellaltra risposta

Commenti

  • I non ‘ ha inserito alcun codice che faccia riferimento a sys.columns perché non avevo assolutamente idea di quale codice stai attualmente utilizzando per ” automagicamente ” genera le tue query. Non cè davvero ‘ t troppo più complesso che potrei immaginare di incorporare nel tuo codice rispetto a SELECT name, object_id, max_length FROM sys.columns;. Dato che hai già un codice automagic che deve eseguire questa operazione, o qualcosa di molto simile, ‘ non pensavo fosse necessario un esempio.
  • I ‘ Non sono sicuro di come sys.columns funzioni con due colonne che hanno lo stesso name. Inoltre, ho ottenuto la cosa funzionante utilizzando la libreria anziché sys, perché dovrei utilizzarla come risposta scelta? Microsoft SQL doesn't have x, do y instead è un contributo valido, ma se il tuo y è inferiore al mio y, io ‘ farò qualcosa di diverso e lo contrassegnerò come scelto.
  • La tua domanda era, essenzialmente, come faccio a scoprire quale colonna ha generato lerrore (presumibilmente , quindi potresti correggere quellunico punto, invece di riprogettare la soluzione). Ti ho detto dove cercare: sys.columns. Che è esattamente dove dovresti guardare per confrontare le lunghezze delle colonne di origine con le lunghezze delle colonne di destinazione. Come farlo dipende da te. ‘ non ti ho detto come correggere il tuo codice, perché non ho assolutamente idea di come sia stata generata la tua query automagic in primo luogo quindi, come ho detto, non avevo idea di come per aggiungere le determinazioni della lunghezza a qualsiasi query che hai già.

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *