Home > Articoli > Message 8152: String or binary data would be truncated

Message 8152: String or binary data would be truncated

Recentemente, ho avuto l’occasione di seguire in prima persona l’aggiornamento di versione del software gestionale presso un cliente. Una delle best practicies da adottare in queste situazioni è la predisposizione di un ambiente di test (con una copia del DB del cliente) su cui installare la nuova versione dell’ERP. Tale ambiente servirà per eseguire gli opportuni test prima di passare in produzione l’aggiornamento.

Il sistema gestionale è dotato anche di un’interfaccia che permette di dialogare con il software di logistica di una società di spedizioni, presso la quale viene stoccato il materiale destinato alla vendita. Lo spedizioniere dovrà quindi essere informato periodicamente circa le spedizioni da eseguire. Si comprende facilmente quanto il modulo di interfaccia diventi un punto critico in sede di aggiornamento e proprio per questo motivo dovrà essere provato in tutte le situazioni.

In questo scenario, durante il test dell’interfaccia tra ERP e software di logistica ci siamo scontrati più volte con il seguente messaggio di errore:

Figura 1 – Messaggio di errore 8152

Il colloquio tra ERP e software di logistica avviene attraverso l’utilizzo di tabelle di scambio dati in un database di frontiera acceduto da entrambi i sistemi.

Una delle situazioni in cui abbiamo riscontrato il problema è stata l’esportazione degli ordini di vendita da evadere, l’errore si verificava durante l’inserimento dei dati nelle tabelle di scambio, nel database di frontiera.

Il seguente script T-SQL permette di creare, sul database di sistema tempdb, le tabelle dbo.OrderHeader e dbo.OrderHExport. Nella prima sono memorizzati tutti gli ordini di vendita, mentre nella seconda vengono inseriti gli ordini da spedire, che rappresentano l’input per il software di logistica. Queste due tabelle di esempio hanno una struttura semplificata rispetto a quella reale e per semplicità vengono create entrambe sul database di sistema tempdb. Nella realtà la tabella dbo.OrderHeader risiede nel database aziendale (ERP), mentre la tabella dbo.OrderHExport risiede nel database di frontiera.

use [tempdb];
go

————————————————————————
— Setup table
————————————————————————

— Drop table dbo.OrderHeader
if (OBJECT_ID(‘dbo.OrderHeader’, ‘U’) is not null)
  drop table dbo.OrderHeader;
go

— Create table dbo.OrderHeader
create table dbo.OrderHeader
(orderid int identity(1, 1) not null,
 orderdate datetime default getdate() not null,
 ordernumber as (isnull(‘SO’ + convert([varchar](23), [orderid], 0), ‘*error*’)),
 customerid int default 1 not null,
 shipname varchar(20) default ‘name’,
 shipaddress varchar(40) default ‘address’,
 shipvia varchar(40) default ‘via’,
 shipcity varchar(20) default ‘city’,
 shipregion varchar(20) default ‘region’,
 shippostalcode varchar(20) default ‘postal code’,
 shipcountry varchar(30) default ‘My country is the best country’,
 shipped bit default 0 — (0=False, 1= True)
 primary key(orderid)
);
go

— Drop table dbo.OrderHExport
if (OBJECT_ID(‘dbo.OrderHExport’, ‘U’) is not null)
  drop table dbo.OrderHExport;
go

— Create table dbo.OrderHExport
create table dbo.OrderHExport
(orderid int identity(1, 1) not null,
 orderdate datetime not null,
 ordernumber varchar(25),
 customerid int not null,
 shipname varchar(20) not null,
 shipaddress varchar(40) not null,
 shipvia varchar(40) not null,
 shipcity varchar(10) not null,      –< Attenzione!!
 shipregion varchar(20) not null,
 shippostalcode varchar(20) not null,
 shipcountry varchar(15) not null    –< Attenzione!!
 primary key(orderid)
);
go

Inseriamo alcuni dati di prova e di seguito li consultiamo:

————————————————————————
— Insert data
————————————————————————
insert into dbo.OrderHeader default values;
insert into dbo.OrderHeader default values;
go

select
  oh.shipped
  ,oh.orderdate
  ,oh.ordernumber
  ,oh.shipname
  ,oh.shipaddress
  ,oh.shipcity
  ,oh.shipregion
  ,oh.shipcountry
from
  dbo.OrderHeader as oh;
go

L’output è illustrato in figura 2.

La figura 2 – Ordini di vendita di esempio

La colonna shipped della tabella dbo.OrderHeader evidenzia che entrambi gli ordini non sono ancora stati spediti, dovranno quindi essere comunicati allo spedizioniere per procedere con la preparazione della spedizione.

Il seguente frammento di codice T-SQL rappresenta il comando di inserimento dei dati nella tabella di frontiera dbo.OrderHExport acceduta dal software di logistica per conoscere le spedizioni da effettuare. Proprio durante l’esecuzione del comando di INSERT il modulo di interfaccia restituiva il messaggio di errore illustrato in figura 1.

————————————————————————
— Error message: String or binary data would be truncated
————————————————————————

insert into dbo.OrderHExport
(
  orderdate,
  ordernumber,
  customerid,
  shipname,
  shipaddress,
  shipvia,
  shipcity,       –< Attenzione!!
  shipregion,
  shippostalcode,
  shipcountry     –< Attenzione!!
)
select
  orderdate,
  ordernumber,
  customerid,
  shipname,
  shipaddress,
  shipvia,
  shipcity,       –< Attenzione!!
  shipregion,
  shippostalcode,
  shipcountry     –< Attenzione!!
from
  dbo.OrderHeader
where
  (shipped = 0);
go

Messaggio 8152, livello 16, stato 14, riga 1
I dati di tipo string o binary verrebbero troncati.
L’istruzione è stata interrotta.

Il messaggio di errore segnala che durante l’operazione di INSERT alcuni dati di tipo stringa o binary verrebbero troncati, per questo motivo il comando di INSERT viene fatto fallire. E’ necessario quindi individuare quale è il campo o i campi nella tabella di destinazione (dbo.OrderHExport), che hanno un tipo di dato con dimensione inferiore rispetto alla dimensione nella tabella sorgente (dbo.OrderHeader).

Questa situazione si verifica quando, per effetto di nuove implementazioni, viene cambiato lo schema della tabella sorgente senza adeguare le tabelle che ricevono dati da questa sorgente, in particolare quando vengono aumentate le dimensioni delle colonne (tipicamente char, nchar, varchar o nvarchar).

Si potrebbe quindi procedere (in modo analitico) confrontando le colonne della tabella sorgente con quelle della tabella destinazione verificandone la dimensione, questo metodo, sicuramente efficace per tabelle con un limitato numero di colonne, perde efficacia qualora le tabelle sorgente e destinazione abbiano centinaia di campi. Abbiamo quindi realizzato il seguente comando T-SQL che interroga e mette a confronto i metadati delle tabelle sorgente e destinazione, attraverso l’utilizzo delle viste INFORMATION_SCHEMA.

Le INFORMATION_SCHEMA offrono una panoramica interna dei metadati di SQL Server in modo indipendente dalle tabelle di sistema, queste viste sono conformi alla definizione dello standard ISO per INFORMATION_SCHEMA.

————————————————————————
— Find the mismatch len field
————————————————————————

select
  t1.TABLE_NAME as t1_table_name
  ,t1.COLUMN_NAME as t1_column_name
  ,t1.DATA_TYPE as t1_data_type
  ,t1.CHARACTER_MAXIMUM_LENGTH as t1_data_size
  ,t2.TABLE_NAME as t2_table_name
  ,t2.COLUMN_NAME as t2_column_name
  ,t2.DATA_TYPE as t2_data_type
  ,t2.CHARACTER_MAXIMUM_LENGTH as t2_data_size
  ,(case when (t1.CHARACTER_MAXIMUM_LENGTH > t2.CHARACTER_MAXIMUM_LENGTH)
    then ‘>’
    else ‘<‘
    end
   ) as segno
from
  INFORMATION_SCHEMA.COLUMNS t1
join
  INFORMATION_SCHEMA.COLUMNS t2 on (t2.TABLE_CATALOG=t1.TABLE_CATALOG)
                               and (t2.TABLE_SCHEMA=t1.TABLE_SCHEMA)
                               and (t2.COLUMN_NAME=t1.COLUMN_NAME)
where
  — from table
  rtrim(t1.TABLE_SCHEMA) + ‘.’ + rtrim(t1.TABLE_NAME) = ‘dbo.OrderHeader’
  and t1.DATA_TYPE IN (‘char’, ‘varchar’, ‘nchar’, ‘nvarchar’)
  — to table
  and rtrim(t2.TABLE_SCHEMA) + ‘.’ + rtrim(t2.TABLE_NAME) = ‘dbo.OrderHExport’
  — column condition
  and ((t1.DATA_TYPE <> t2.DATA_TYPE) or
       (t1.CHARACTER_MAXIMUM_LENGTH <> t2.CHARACTER_MAXIMUM_LENGTH));
go

L’output, illustrato in figura 3, evidenzia le colonne incriminate:

Figura 3 – Colonne varchar con dimensione differente in dbo.OrderHeader e dbo.OrderHExport

Nell’esempio si è tentato di inserire la stringa ‘My country is the best country’ di lunghezza pari a 30 caratteri nella colonna shipcountry della tabella dbo.OrderHExport che però non può contenerla perché ha una dimensione massima di 15 caratteri.

 

Approfondimento

Il comando di selezione dati (SELECT) citato in una istruzione INSERT INTO può contenere svariate tabelle in JOIN e comporre, dinamicamente, le stringhe di caratteri che si desidera inserire in altrettante colonne nella tabella di destinazione.

In questa situazione non avremo una tabella sorgente persistita sul DB perché la tabella sorgente sarà la virtual-table restituita dall’esecuzione del comando di SELECT.

In questo caso, per adottare la soluzione descritta sarà necessario materializzare sul DB (ed esempio come tabella temporanea) la virtual-table restituita dal comando di SELECT; sarà sufficiente utilizzare la clausola INTO del comando SELECT.

Chi è Sergio Govoni

Sergio Govoni è laureato in Scienze e Tecnologie Informatiche. Da oltre 16 anni lavora presso una software house che produce un noto sistema ERP, distribuito a livello nazionale ed internazionale, multi azienda client/server su piattaforma Win32. Attualmente si occupa di progettazione e analisi funzionale, coordina un team di sviluppo ed è responsabile tecnico di prodotto. Lavora con SQL Server dalla versione 7.0 e si è occupato d'implementazione e manutenzione di database relazionali in ambito gestionale, ottimizzazione delle prestazioni e problem solving. Nello staff di UGISS si dedica alla formazione e alla divulgazione in ambito SQL Server e tecnologie a esso collegate, scrivendo articoli e partecipando come speaker ai workshop e alle iniziative del primo e più importante User Group Italiano sulla tecnologia SQL Server. Ha conseguito la certificazione MCP, MCTS SQL Server. Per il suo contributo nelle comunità tecniche e per la condivisione della propria esperienza con altri, dal 2010 riceve il riconoscimento SQL Server MVP (Microsoft Most Valuable Professional). Nel corso dell'anno 2011 ha contribuito alla scrittura del libro SQL Server MVP Deep Dives Volume 2 (http://www.manning.com/delaney/).

Leggi Anche

Automazione delle attività di manutenzione in Azure SQL Database

Introduzione Azure SQL Database non possiede un servizio di schedulazione nativo paragonabile a SQL Agent …