Click here to Skip to main content
15,881,092 members
Articles / All Topics

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

Rate me:
Please Sign up or sign in to vote.
5.00/5 (2 votes)
9 Mar 2016CPOL2 min read 8.1K   1
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:

SQL
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).

SQL
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.

  1. 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.
    SQL
    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
  2. Use the following query to identify the issue columns:
    Actual Table
    SQL
    ;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
    SQL
    ;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:

    image

The reason to return the above three columns is as follows:

  1. CustId ==> In our destination table, CustId’s data type is TINYINT. Even the select query is returning the results within the boundary, the data type which our insertion query is returning is an INT. So there could be a possibility that there could be large numbers that the destination table could not hold.
  2. CustName ==> ‘Whitacker Jr.’ is exceeding the maximum length of 10 which is in the destination table.
  3. MaxCredit ==> In the destination table, the size of the column is numeric (6,2) which means it can hold values up to 9999.99. But our insertion query contains a record which consists of 15000.00.

Hope this might be helpful to you.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Technical Lead Air Liquide Industrial Services (Singapore)
Singapore Singapore
My passion lies in building business intelligence and data-based solutions, writing about things I work with and talking about it. New technologies relevant to my line of work interest me and I am often seen playing with early releases of such technologies.

My current role involves architecting and building a variety of data solutions, providing database maintenance and administration support, building the organization’s data practice, and training and mentoring peers.

My aspiration over the next several years is to achieve higher competency and recognition in the field of Data Analytics and move into a career of data science.


Specialities: SQL Server, T-SQL Development, SQL Server Administration, SSRS, SSIS, C#, ASP.Net, Crystal Reports

Comments and Discussions

 
GeneralMy vote of 5 Pin
Member 1236439013-Mar-16 22:52
Member 1236439013-Mar-16 22:52 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.