2011-06-17 101 views
85

我參與了數據遷移項目。我收到以下錯誤,當我嘗試從一個表中的數據插入到另一個表(SQL Server 2005中):SQL Server字符串或二進制數據將被截斷

消息8152,級別16,狀態13,第1個
字符串或二進制數據將被截斷。

源數據列與數據類型匹配,並且位於目標表列的長度定義內,所以我不知道可能導致此錯誤的原因。

+0

你介意發佈一些代碼和每個表的信息嗎? –

+0

這些表格都非常大 - 所以我只會發布表格定義中涉及的部分和代碼 - 是否可以接受? –

+0

表格定義和代碼會很好。 – IAmTimCorey

回答

115

您需要發佈源表和目標表的表格定義,以便我們找出問題所在,但的底線是源表中的某一列比您的目標列大。這可能是因爲你正在以一種你不知道的方式改變格式。您正在從中移動的數據庫模型也很重要。

+1

按照我的評論以上 - 即將上市:) –

+3

我曾經面臨同樣的問題,並不得不比較所有的列類型和大小的兩個表來解決問題。 –

+1

經過您收集部分表格定義的執行情況,然後得到我的sproc代碼,違規的柱子就像閃電般跳出來......感謝所有您的意見。 –

45

問題很簡單:源查詢中的一個或多個列包含的數據超出了其目標列的長度。一個簡單的解決方案是採取您的源查詢並在每列上執行Max(Len(source col))。即,

Select Max(Len(TextCol1)) 
    , Max(Len(TextCol2)) 
    , Max(Len(TextCol3)) 
    , ... 
From ... 

然後將這些長度與目標表中的數據類型長度進行比較。至少有一個超出目標列長度。

如果你是絕對肯定的,這不應該是這樣並不在乎它是不是這樣,那麼另一種解決辦法是強行投源查詢列到其目的地長度(這將截斷任何數據過長):

Select Cast(TextCol1 As varchar(...)) 
    , Cast(TextCol2 As varchar(...)) 
    , Cast(TextCol3 As varchar(...)) 
    , ... 
From ... 
+0

我的日常過程開始打破這個錯誤。我插入的數據總是足夠短,以至於我總是有其他行(在我從中拉出的表格中)使用過大的字符串,因爲我的過濾器從未插入過。也許重建索引或更新統計數據,但機器中的幽靈有一天決定不再喜歡查詢計劃,因爲它將數據(太寬)「可能」作爲一個路徑插入在Where子句中的謂詞過濾之前插入。要解決這個問題,我使用了LEFT()而不是CAST - 只需輸入更少的字符。 – MikeTeeVee

+0

謝謝托馬斯,這很奇怪,即使我沒有太長的數據,我仍然必須將它轉換到新的目標列大小,只要我這樣做了。 – Aviva

1

對於其他人,也檢查您的存儲過程。在我的情況下,在我的存儲過程CustomSearch我意外地聲明沒有足夠的長度爲我的列,所以當我輸入一個大數據時,我收到了錯誤,即使我的數據庫有很大的長度。我只是在自定義搜索中更改了列的長度,錯誤消失了。這只是爲了提醒。謝謝。

1

當你不具有足夠的權限

+1

真的嗎?實際的「字符串或二進制數據會被截斷」錯誤?如果你沒有權限,這似乎是一個非常奇怪的錯誤。是否有權限阻止您寫入超過一定數量的數據? (我很感興趣,因爲當我收到這個錯誤時我想自動檢查字段大小 - 所以如果它可能出於其他原因,這非常有趣!) –

36

正如其他人已經表示,這也有可能發生,一個源表列的數據類型是比你的目標列較大。

因爲這裏沒有人提到過,所以一個簡單的解決方案(類似於Thomas的CAST解決方案)就是簡單地關閉警告並允許截斷髮生。因此,如果您收到此錯誤,但您確定舊數據庫/表中的數據可以被截斷(縮小),則只需執行以下操作即可;

SET ANSI_WARNINGS OFF; 
-- Your insert TSQL here. 
SET ANSI_WARNINGS ON; 

如上所述,請務必記得在之後再次發出警告。我希望這有幫助。

+2

非常好的提示有 – RollRoll

1

我碰到這個問題今天來了,在我尋找的答案,這個最小的錯誤提示信息我也發現了這個鏈接:

https://connect.microsoft.com/SQLServer/feedback/details/339410/please-fix-the-string-or-binary-data-would-be-truncated-message-to-give-the-column-name

因此,似乎微軟並沒有計劃對錯誤擴大消息很快。

所以我轉向其他手段。

我複製錯誤練成:

(受影響1行(S))

(1行(一個或多個)受影響)

(1行(一個或多個)受影響) 消息8152 ,級別16,狀態14,行13 字符串或二進制數據將被截斷。 該聲明已被終止。

(1行(S)的影響)

計算在Excel中的行數,得接近導致問題的記錄計數器...調整了出口代碼打印出來的SQL接近它...然後在問題sql周圍運行5 - 10個sql插入,並設法找出問題之一,查看太長的字符串,增加該列的大小,然後大的導入文件沒有問題。

這是一個黑客和解決方法,但是當你離開時只有很少的選擇,你可以做任何事情。

5

另一個潛在的原因是如果您對超出列長度的列有默認值設置。它似乎有人發了一個長度爲5的列,但默認值超過了5的長度。這讓我瘋狂,因爲我試圖理解爲什麼它不適用於任何插入,即使我插入的是一個整數爲1的列。由於表架構的默認值違反了默認值,因此它將所有事情搞砸了 - 我猜想我們將這些事情帶到了學習的教訓 - 避免在架構中使用具有默認值的表。 :)

+0

我不認爲避免默認值是一個好的解決方案默認值非常有用。我不會通過刪除默認值來解決由拼寫錯誤導致的數據庫「問題」... –

3

這可能是一個具有挑戰性的錯誤。以下是從https://connect.microsoft.com/SQLServer/feedback/details/339410/中尋找AmirCharania的評論。

我已經調整了由AmirCharania給出的選擇到實際表中的數據而不是臨時數據的答案。首先選擇你的數據集到一個開發表中,然後執行以下操作:

WITH CTE_Dev 
AS (
    SELECT C.column_id 
     ,ColumnName = C.NAME 
     ,C.max_length 
     ,C.user_type_id 
     ,C.precision 
     ,C.scale 
     ,DataTypeName = T.NAME 
    FROM sys.columns C 
    INNER JOIN sys.types T ON T.user_type_id = C.user_type_id 
    WHERE OBJECT_ID = OBJECT_ID('YOUR TARGET TABLE NAME HERE, WITH SCHEMA') 
    ) 
    ,CTE_Temp 
AS (
    SELECT C.column_id 
     ,ColumnName = C.NAME 
     ,C.max_length 
     ,C.user_type_id 
     ,C.precision 
     ,C.scale 
     ,DataTypeName = T.NAME 
    FROM sys.columns C 
    INNER JOIN sys.types T ON T.user_type_id = C.user_type_id 
    WHERE OBJECT_ID = OBJECT_ID('YOUR TEMP TABLE NAME HERE, WITH SCHEMA') 
    ) 
SELECT * 
FROM CTE_Dev D 
FULL OUTER JOIN CTE_Temp T ON D.ColumnName = T.ColumnName 
WHERE ISNULL(D.max_length, 0) < ISNULL(T.max_length, 999) 
+0

看起來像MS已關閉Connect網站。這個問題的新鏈接是:https://feedback.azure.com/forums/908035-sql-server/suggestions/32891518-please-fix-the-string-or-binary-data-would-betru。 ..still標記爲無計劃。我認爲您提到的評論(諷刺)在遷移發生時被截斷。 –

+0

有趣的是,問題在一個略有不同的標題下再次打開:https://feedback.azure.com/forums/908035-sql-server/suggestions/32908417-binary-or-string-data-would-be-truncated-錯誤,它被列爲「審查中」,所以還有希望。 –

2

是的,我也面臨這樣的問題。

REMARKS VARCHAR(500) 
to 
REMARKS VARCHAR(1000) 

在此,我已提出長度變化備註500〜1000

0

我已經建立了一個存儲過程,用於分析源表或查詢與每列的幾個特點。其中的最小長度(MIN_LEN )和最大長度(max_len)。

CREATE PROCEDURE [dbo].[sp_analysetable] (
    @tableName varchar(8000), 
    @deep bit = 0 
) AS 

/* 
sp_analysetable 'company' 
sp_analysetable 'select * from company where name is not null' 
*/ 

DECLARE @intErrorCode INT, @errorMSG VARCHAR(500), @tmpQ NVARCHAR(2000), @column_name VARCHAR(50), @isQuery bit 
SET @intErrorCode=0 

IF OBJECT_ID('tempdb..##tmpTableToAnalyse') IS NOT NULL BEGIN 
    DROP TABLE ##tmpTableToAnalyse 
END 
IF OBJECT_ID('tempdb..##tmpColumns') IS NOT NULL BEGIN 
    DROP TABLE ##tmpColumns 
END 

if CHARINDEX('from', @tableName)>0 
    set @isQuery=1 

IF @intErrorCode=0 BEGIN 
    if @isQuery=1 begin 
    --set @tableName = 'USE '[email protected]+';'+replace(@tableName, 'from', 'into ##tmpTableToAnalyse from') 
    --replace only first occurance. Now multiple froms may exists, but first from will be replaced with into .. from 
    set @tableName=Stuff(@tableName, CharIndex('from', @tableName), Len('from'), 'into ##tmpTableToAnalyse from') 
    exec(@tableName) 
    IF OBJECT_ID('tempdb..##tmpTableToAnalyse') IS NULL BEGIN 
     set @intErrorCode=1 
     SET @errorMSG='Error generating temporary table from query.' 
    end 
    else begin 
     set @tableName='##tmpTableToAnalyse' 
    end 
    end 
end 

IF @intErrorCode=0 BEGIN 
    SET @tmpQ='USE '+DB_NAME()+';'+CHAR(13)+CHAR(10)+' 
    select 
    c.column_name as [column], 
    cast(sp.value as varchar(1000)) as description, 
    tc_fk.constraint_type, 
    kcu_pk.table_name as fk_table, 
    kcu_pk.column_name as fk_column, 
    c.ordinal_position as pos, 
    c.column_default as [default], 
    c.is_nullable as [null], 
    c.data_type, 
    c.character_maximum_length as length, 
    c.numeric_precision as [precision], 
    c.numeric_precision_radix as radix, 
    cast(null as bit) as [is_unique], 
    cast(null as int) as min_len, 
    cast(null as int) as max_len, 
    cast(null as int) as nulls, 
    cast(null as int) as blanks, 
    cast(null as int) as numerics, 
    cast(null as int) as distincts, 
    cast(null as varchar(500)) as distinct_values, 
    cast(null as varchar(50)) as remarks 
    into ##tmpColumns' 
    if @isQuery=1 begin 
    SET @[email protected]+' from tempdb.information_schema.columns c, (select null as value) sp' 
    end 
    else begin 
    SET @[email protected]+' 
     from information_schema.columns c 
     left join sysobjects so on so.name=c.table_name and so.xtype=''U'' 
     left join syscolumns sc on sc.name=c.column_name and sc.id =so.id 
     left join sys.extended_properties sp on sp.minor_id = sc.colid AND sp.major_id = sc.id and sp.name=''MS_Description'' 
     left join information_schema.key_column_usage kcu_fk on kcu_fk.table_name = c.table_name  and c.column_name = kcu_fk.column_name 
     left join information_schema.table_constraints tc_fk on kcu_fk.table_name = tc_fk.table_name and kcu_fk.constraint_name = tc_fk.constraint_name 
     left join information_schema.referential_constraints rc on rc.constraint_name = kcu_fk.constraint_name 
     left join information_schema.table_constraints tc_pk on rc.unique_constraint_name = tc_pk.constraint_name 
     left join information_schema.key_column_usage kcu_pk on tc_pk.constraint_name = kcu_pk.constraint_name 
' 
    end 
    SET @[email protected]+' where c.table_name = '''[email protected]+'''' 

    exec(@tmpQ) 
end 

IF @intErrorCode=0 AND @deep = 1 BEGIN 
    DECLARE 
    @count_rows int, 
    @count_distinct int, 
    @count_nulls int, 
    @count_blanks int, 
    @count_numerics int, 
    @min_len int, 
    @max_len int, 
    @distinct_values varchar(500) 
    DECLARE curTmp CURSOR LOCAL FAST_FORWARD FOR 
    select [column] from ##tmpColumns; 
    OPEN curTmp 
    FETCH NEXT FROM curTmp INTO @column_name 
    WHILE @@FETCH_STATUS = 0 and @intErrorCode=0 BEGIN 
    set @tmpQ = 'USE '+DB_NAME()+'; SELECT'+ 
     ' @count_rows=count(0), '+char(13)+char(10)+ 
     ' @count_distinct=count(distinct ['[email protected]_name+']),'+char(13)+char(10)+ 
     ' @count_nulls=sum(case when ['[email protected]_name+'] is null then 1 else 0 end),'+char(13)+char(10)+ 
     ' @count_blanks=sum(case when ltrim(['[email protected]_name+'])='''' then 1 else 0 end),'+char(13)+char(10)+ 
     ' @count_numerics=sum(isnumeric(['[email protected]_name+'])),'+char(13)+char(10)+ 
     ' @min_len=min(len(['[email protected]_name+'])),'+char(13)+char(10)+ 
     ' @max_len=max(len(['[email protected]_name+']))'+char(13)+char(10)+ 
     ' from ['[email protected]+']' 
    exec sp_executesql @tmpQ, 
         N'@count_rows int OUTPUT, 
         @count_distinct int OUTPUT, 
         @count_nulls int OUTPUT, 
         @count_blanks int OUTPUT, 
         @count_numerics int OUTPUT, 
         @min_len int OUTPUT, 
         @max_len int OUTPUT', 
         @count_rows  OUTPUT, 
         @count_distinct OUTPUT, 
         @count_nulls OUTPUT, 
         @count_blanks OUTPUT, 
         @count_numerics OUTPUT, 
         @min_len  OUTPUT, 
         @max_len  OUTPUT 

    IF (@count_distinct>10) BEGIN 
     SET @distinct_values='Many ('+cast(@count_distinct as varchar)+')' 
    END ELSE BEGIN 
     set @distinct_values=null 
     set @tmpQ = N'USE '+DB_NAME()+';'+ 
     ' select @distinct_values=COALESCE(@distinct_values+'',''+cast(['[email protected]_name+'] as varchar), cast(['[email protected]_name+'] as varchar))'+char(13)+char(10)+ 
     ' from ('+char(13)+char(10)+ 
     ' select distinct ['[email protected]_name+'] from ['[email protected]+'] where ['[email protected]_name+'] is not null) a'+char(13)+char(10) 
     exec sp_executesql @tmpQ, 
         N'@distinct_values varchar(500) OUTPUT', 
         @distinct_values  OUTPUT 
    END 
    UPDATE ##tmpColumns SET 
     is_unique  =case when @[email protected]_distinct then 1 else 0 end, 
     distincts  [email protected]_distinct, 
     nulls   [email protected]_nulls, 
     blanks   [email protected]_blanks, 
     numerics  [email protected]_numerics, 
     min_len  [email protected]_len, 
     max_len  [email protected]_len, 
     [email protected]_values, 
     remarks  = 
     case when @[email protected]_nulls then 'all null,' else '' end+ 
     case when @[email protected]_distinct then 'unique,' else '' end+ 
     case when @count_distinct=0 then 'empty,' else '' end+ 
     case when @[email protected]_len then 'same length,' else '' end+ 
     case when @[email protected]_numerics then 'all numeric,' else '' end 
    WHERE [column][email protected]_name 

    FETCH NEXT FROM curTmp INTO @column_name 
    END 
    CLOSE curTmp DEALLOCATE curTmp 
END 

IF @intErrorCode=0 BEGIN 
    select * from ##tmpColumns order by pos 
end 

IF @intErrorCode=0 BEGIN --Clean up temporary tables 
    IF OBJECT_ID('tempdb..##tmpTableToAnalyse') IS NOT NULL BEGIN 
    DROP TABLE ##tmpTableToAnalyse 
    END 
    IF OBJECT_ID('tempdb..##tmpColumns') IS NOT NULL BEGIN 
    DROP TABLE ##tmpColumns 
    END 
end 

IF @intErrorCode<>0 BEGIN 
    RAISERROR(@errorMSG, 12, 1) 
END 
RETURN @intErrorCode 

我保存這個過程中的主數據庫,這樣我可以像這樣在每個數據庫中使用它:

sp_analysetable 'table_name', 1 
// deep=1 for doing value analyses 

,輸出是:

column description constraint_type fk_table fk_column pos default null data_type length precision radix is_unique min_len max_len nulls blanks numerics distincts distinct_values remarks
id_individual NULL PRIMARY KEY NULL NULL 1 NULL NO int NULL 10 10 1 1 2 0 0 70 70 Many (70) unique,all numeric,
id_brand NULL NULL NULL NULL 2 NULL NO int NULL 10 10 0 1 1 0 0 70 2 2,3 same length,all numeric, guid NULL NULL NULL NULL 3 (newid()) NO uniqueidentifier NULL NULL NULL 1 36 36 0 0 0 70 Many (70) unique,same length,
customer_id NULL NULL NULL NULL 4 NULL YES varchar 50 NULL NULL 0 NULL NULL 70 0 0 0 NULL all null,empty,
email NULL NULL NULL NULL 5 NULL YES varchar 100 NULL NULL 0 4 36 0 0 0 31 Many (31)
mobile NULL NULL NULL NULL 6 NULL YES varchar 50 NULL NULL 0 NULL NULL 70 0 0 0 NULL all null,empty,
initials NULL NULL NULL NULL 7 NULL YES varchar 50 NULL NULL 0 NULL NULL 70 0 0 0 NULL all null,empty,
title_short NULL NULL NULL NULL 8 NULL YES varchar 50 NULL NULL 0 NULL NULL 70 0 0 0 NULL all null,empty,
title_long NULL NULL NULL NULL 9 NULL YES varchar 50 NULL NULL 0 NULL NULL 70 0 0 0 NULL all null,empty,
firstname NULL NULL NULL NULL 10 NULL YES varchar 50 NULL NULL 0 NULL NULL 70 0 0 0 NULL all null,empty,
lastname NULL NULL NULL NULL 11 NULL YES varchar 50 NULL NULL 0 NULL NULL 70 0 0 0 NULL all null,empty,
address NULL NULL NULL NULL 12 NULL YES varchar 100 NULL NULL 0 NULL NULL 70 0 0 0 NULL all null,empty,
pc NULL NULL NULL NULL 13 NULL YES varchar 10 NULL NULL 0 NULL NULL 70 0 0 0 NULL all null,empty,
kixcode NULL NULL NULL NULL 14 NULL YES varchar 20 NULL NULL 0 NULL NULL 70 0 0 0 NULL all null,empty,
date_created NULL NULL NULL NULL 15 (getdate()) NO datetime NULL NULL NULL 1 19 19 0 0 0 70 Many (70) unique,same length,
created_by NULL NULL NULL NULL 16 (user_name()) NO varchar 50 NULL NULL 0 13 13 0 0 0 1 loyalz-public same length,
id_location_created NULL FOREIGN KEY location id_location 17 NULL YES int NULL 10 10 0 1 1 0 0 70 2 1,2 same length,all numeric, id_individual_type NULL FOREIGN KEY individual_type id_individual_type 18 NULL YES int NULL 10 10 0 NULL NULL 70 0 0 0 NULL all null,empty,
optin NULL NULL NULL NULL 19 NULL YES int NULL 10 10 0 1 1 39 0 31 2 0,1 same length,

+0

注意事項:你不應該爲存儲過程使用'sp_'前綴。微軟已經保留了這個前綴以供自己使用(參見*命名存儲過程*)](http://msdn.microsoft.com/en-us/library/ms190669%28v=sql.105%29.aspx),以及你將來有可能冒着名字衝突的風險。 [這對您的存儲過程性能也是不利的](http:// www。sqlperformance.com/2012/10/t-sql-queries/sp_prefix)。最好只是簡單地避免使用'sp_'並將其他內容用作前綴 - 或者根本沒有前綴! –

0

我在創建表時使用空字符串'',然後在後續更新中接收錯誤'Msg 8152,字符串或二進制數據將被截斷'。這是由於更新值包含6個字符並且大於預期的列定義而發生的。我使用「SPACE」來解決這個問題,只是因爲我知道在初始數據創建後我會進行批量更新,即列不會長時間保持空白。

SO BIG CAVEAT HERE:這不是一個特別流暢的解決方案,但對於將數據集合在一起的情況非常有用,例如在您創建數據挖掘表的一次性智能請求中,應用一些批量處理/解釋並在結果之前和之後存儲以供稍後比較/挖掘。這是我工作中經常發生的事情。

可以最初填充用空間關鍵字即到10個字符或更少(替代如適用)「欄」然後將而不引起截斷錯誤被允許

select 
      Table1.[column1] 
      ,Table1.[column2] 
      ,SPACE(10) as column_name 
    into table_you_are_creating 
    from Table1 
    where ... 

後續更新。再次,我只會在類似於我的警告中所描述的場景中使用它。

0

我有類似的問題。我只是將名字中的數據從一張表複製到一張相同的表中。

最終我使用SELECT INTO語句將源錶轉儲到臨時表中。

SELECT * 
INTO TEMP_TABLE 
FROM SOURCE_TABLE; 

我將源表的模式與臨時表進行了比較。當我期待varchar(250)時,我發現其中一列是varchar(4000)

UPDATE: 的VARCHAR(4000)的問題都可以在這裏的情況下,說明你有興趣:

For Nvarchar(Max) I am only getting 4000 characters in TSQL?

希望這有助於。

1

我打算爲這個錯誤添加另一個可能的原因,僅僅是因爲沒有人提到它,它可能會幫助未來的人(因爲OP已經找到了他的答案)。如果您插入的表具有觸發器,則可能是觸發器正在生成錯誤。當表字段定義發生變化時,我看到了這種情況,但審計表不是。

0

CREATE TABLE [DBO]。[部門]( [DEPARTMENT_NAME] CHAR(10)NULL )

INSERT INTO [DBO]。部VALUES( '家庭醫學') --error將發生

ALTER TABLE [部門] ALTER COLUMN [DEPARTMENT_NAME]炭(50)

INSERT INTO [DBO] .Department VALUES( '家庭醫學')

SELECT * FROM [處]

0

當一個表的列提出約束[大多長]這個錯誤被拋出。 。例如。如果用於列myColumn的數據庫模式是CHAR(2),那麼當你的任何應用程序調用插入值時,必須傳遞長度爲2的字符串。

這個錯誤基本上就是這樣說的;長度爲3及以上的字符串不一致以適合數據庫模式指定的長度限制。這就是SQL Server發出警告並拋出數據丟失/截斷錯誤的原因。

相關問題