String or Binary Data Would Be Truncated / Arithmetic Overflow Error Converting Numeric to Data Type Numeric – Workaround





5.00/5 (2 votes)
String or binary data would be truncated / arithmetic overflow error converting numeric to data type numeric – workaround
There’s nothing more annoying than getting the error ‘String or binary data would be truncated
’ or ‘Arithmetic overflow error converting numeric to data type numeric
’, when you need to insert data to a table using a SELECT
statement. To make it more interesting, the SQL won’t be providing us the name of the column (or columns) which is causing this issue. (This is due to the SQL architecture on how it executes queries).
To illustrate this, I will use a small sample.
Suppose we have a table to store some Customer
details:
CREATE TABLE Customer_Data(
CustId TINYINT
,CustFName VARCHAR(10)
,CustLName VARCHAR(10)
,MaxCredit NUMERIC(6,2)
)
We will try to insert details to the above table. (In reality, the SELECT
statement will be very complex and could fetch lots of rows).
INSERT INTO dbo.Customer_Data(
CustId
,CustFName
,CustLName
,MaxCredit
)
SELECT 1 AS CustId,'John' AS CustFName,'Doe' AS CustLName,_
1000.00 AS MaxCredit UNION ALL
SELECT 2,'Jane','Doe',1000.00 UNION ALL
SELECT 3,'James','Whitacker Jr.',15000.00
This will result in the following error:
Msg 8152, Level 16, State 14, Line 48
String or binary data would be truncated.
The statement has been terminated.
The challenge here is to find out actually which columns are having this issue. (As mentioned, in reality the number of columns could be very large).
However, there is a small workaround which we can use to find out the columns which is causing the insertion to fail. You need to do the following in order to find out these columns.
- First, create a table using the same
select
statement. (You can either create a temporary table or an actual table based on the environment and your need). I will create two tables, one actual and one temporary to illustrate both the options.SELECT A.* INTO Temp_Customer_Data FROM( SELECT 1 AS CustId,'John' AS CustFName,'Doe' AS CustLName,1000.00 AS MaxCredit UNION ALL SELECT 2,'Jane','Doe',1000.00 UNION ALL SELECT 3,'James','Whitacker Jr.',15000.00 ) AS A SELECT A.* INTO #Customer_Data FROM( SELECT 1 AS CustId,'John' AS CustFName,'Doe' AS CustLName,1000.00 AS MaxCredit UNION ALL SELECT 2,'Jane','Doe',1000.00 UNION ALL SELECT 3,'James','Whitacker Jr.',15000.00 ) AS A
- Use the following query to identify the issue columns:
Actual Table
;WITH Cte_Source AS ( SELECT C.COLUMN_NAME ,C.DATA_TYPE ,C.CHARACTER_MAXIMUM_LENGTH ,C.NUMERIC_PRECISION ,C.NUMERIC_SCALE FROM INFORMATION_SCHEMA.TABLES AS T JOIN INFORMATION_SCHEMA.COLUMNS AS C ON C.TABLE_CATALOG = T.TABLE_CATALOG AND C.TABLE_NAME = T.TABLE_NAME AND C.TABLE_SCHEMA = T.TABLE_SCHEMA WHERE T.TABLE_NAME = 'Temp_Customer_Data' -- Source Table AND T.TABLE_SCHEMA = 'dbo' ) ,Cte_Destination AS ( SELECT C.COLUMN_NAME ,C.DATA_TYPE ,C.CHARACTER_MAXIMUM_LENGTH ,C.NUMERIC_PRECISION ,C.NUMERIC_SCALE FROM INFORMATION_SCHEMA.TABLES AS T JOIN INFORMATION_SCHEMA.COLUMNS AS C ON C.TABLE_CATALOG = T.TABLE_CATALOG AND C.TABLE_NAME = T.TABLE_NAME AND C.TABLE_SCHEMA = T.TABLE_SCHEMA WHERE T.TABLE_NAME = 'Customer_Data' -- Destination Table AND T.TABLE_SCHEMA = 'dbo' ) SELECT S.COLUMN_NAME ,S.DATA_TYPE ,S.CHARACTER_MAXIMUM_LENGTH ,S.NUMERIC_PRECISION ,S.NUMERIC_SCALE ,D.COLUMN_NAME ,D.DATA_TYPE ,D.CHARACTER_MAXIMUM_LENGTH ,D.NUMERIC_PRECISION ,D.NUMERIC_SCALE FROM Cte_Source AS S JOIN Cte_Destination AS D ON D.COLUMN_NAME = S.COLUMN_NAME WHERE S.CHARACTER_MAXIMUM_LENGTH > D.CHARACTER_MAXIMUM_LENGTH OR S.NUMERIC_PRECISION > D.NUMERIC_PRECISION
Temporary Table
;WITH Cte_Source AS ( SELECT C.COLUMN_NAME ,C.DATA_TYPE ,C.CHARACTER_MAXIMUM_LENGTH ,C.NUMERIC_PRECISION ,C.NUMERIC_SCALE FROM tempdb.sys.objects so JOIN tempdb.INFORMATION_SCHEMA.TABLES AS T ON so.name = T.TABLE_NAME AND so.[object_id] = OBJECT_ID('tempdb..#Customer_Data') JOIN tempdb.INFORMATION_SCHEMA.COLUMNS AS C ON C.TABLE_CATALOG = T.TABLE_CATALOG AND C.TABLE_NAME = T.TABLE_NAME AND C.TABLE_SCHEMA = T.TABLE_SCHEMA WHERE T.TABLE_SCHEMA = 'dbo' ) ,Cte_Destination AS ( SELECT C.COLUMN_NAME ,C.DATA_TYPE ,C.CHARACTER_MAXIMUM_LENGTH ,C.NUMERIC_PRECISION ,C.NUMERIC_SCALE FROM INFORMATION_SCHEMA.TABLES AS T JOIN INFORMATION_SCHEMA.COLUMNS AS C ON C.TABLE_CATALOG = T.TABLE_CATALOG AND C.TABLE_NAME = T.TABLE_NAME AND C.TABLE_SCHEMA = T.TABLE_SCHEMA WHERE T.TABLE_NAME = 'Customer_Data' -- Destination Table AND T.TABLE_SCHEMA = 'dbo' ) SELECT S.COLUMN_NAME ,S.DATA_TYPE ,S.CHARACTER_MAXIMUM_LENGTH ,S.NUMERIC_PRECISION ,S.NUMERIC_SCALE ,D.COLUMN_NAME ,D.DATA_TYPE ,D.CHARACTER_MAXIMUM_LENGTH ,D.NUMERIC_PRECISION ,D.NUMERIC_SCALE FROM Cte_Source AS S JOIN Cte_Destination AS D ON D.COLUMN_NAME = S.COLUMN_NAME WHERE S.CHARACTER_MAXIMUM_LENGTH > D.CHARACTER_MAXIMUM_LENGTH OR S.NUMERIC_PRECISION > D.NUMERIC_PRECISION
Both the aforementioned queries will return the following result:
The reason to return the above three columns is as follows:
CustId
==> In our destination table,CustId
’s data type isTINYINT
. Even theselect
query is returning the results within the boundary, the data type which our insertion query is returning is anINT
. So there could be a possibility that there could be large numbers that the destination table could not hold.CustName
==> ‘Whitacker Jr.
’ is exceeding the maximum length of10
which is in the destination table.MaxCredit
==> In the destination table, the size of the column is numeric (6,2) which means it can hold values up to9999.99
. But our insertion query contains a record which consists of15000.00
.
Hope this might be helpful to you.