In the past I’ve written queries to give me the LEN for each column, but again if there are a large number of columns involved this can be very time consuming.
Below is a way of identifying which rows are causing the problem. This doesn’t help if you’ve got a large number of columns, as you still need to work out which field is causing the problem, but it will help if you have a large dataset and the problem rows are very sparse.
For this example I’ll create a couple of tables and generate some data. The source table has a column of VARCHAR(50), whereas the destination has VARCHAR(25):
CREATE TABLE SourceTable
(
RowId INT
,Chars INT
,String VARCHAR(50)
)
GO
CREATE TABLE DestinationTable
(
RowId INT
,Chars INT
,String VARCHAR(25)
)
GO
Next the tables are populated with a random number of ‘X’s, between 0 and 50. In theory you should get about 50% with a length above 25 characters and 50% below.DECLARE @i INT
DECLARE @RandomNumber INT
SET @i=0
WHILE @i <= 50
BEGIN
SET @RandomNumber = ROUND(50 * RAND(), 0)
INSERT INTO SourceTable
SELECT @i, @RandomNumber, REPLICATE('X', @RandomNumber)
SET @i=@i+1
END
GO
Next try inserting from SourceTable to DestinationTable:
INSERT INTO DestinationTable
SELECT * FROM SourceTableGO
This results in the error:Msg 8152, Level 16, State 14, Line 1
String or binary data would be truncated.
The statement has been terminated.
It’s possible to ignore the 'String or binary data would be truncated' message by setting ANSI_WARNINGS to OFF. This will truncate fields where they don’t fit. ANSI_WARNINGS OFF has drawbacks and it is better to correct a problem rather than ignore it.
The following can be used to work out which rows are causing the issue:
1. Take a copy of the destination table:
SELECT * INTO #Destination FROM DestinationTable WHERE 1=2
GO
2. Set ANSI_WARNINGS OFF and perform the insert into the copy of the destination table, then set ANSI_WARNINGS ON again:
SET ANSI_WARNINGS OFF
GO
INSERT INTO #Destination
SELECT * FROM SourceTable
GO
SET ANSI_WARNINGS ON
GO
As ANSI_WARNINGS is off SQL Server truncates the fields rather than produces the warning.
3. Next compare what you would like to insert against what was inserted with the ANSI_WARNINGS OFF truncating. By using EXCEPT you only select the rows that don't match, and have therefore been truncated:
SELECT * FROM SourceTable
EXCEPT
SELECT * FROM #Destination
GO
The rows that have been truncated and are the cause of the ‘String or binary data would be truncated’ error.
(Note - The use of EXCEPT limits this to 2005/2008. The finaly query could be re-written for SQL Server 2000 and below.)
This isn’t the most elegant solution, and as I said if there were a large number of columns you’d still need to hunt through for the offender(s), but at least this gives an idea of where to look. I may have missed some glaringly obvious solution to this problem, so I’d be interested to know if anyone has any other ways of dealing it.
source: http://sqlblogcasts.com/blogs/danny/archive/2008/01/12/scuffling-with-string-or-binary-data-would-be-truncated.aspx
No comments:
Post a Comment