我参与了一个数据迁移项目。当我试图将数据从一个表插入到另一个表(SQL Server 2005)时,我得到以下错误:
编号8152,16层,状态13,1线 字符串或二进制数据将被截断。
源数据列与数据类型匹配,并且在目标表列的长度定义内,因此我不知道是什么原因导致了这个错误。
我参与了一个数据迁移项目。当我试图将数据从一个表插入到另一个表(SQL Server 2005)时,我得到以下错误:
编号8152,16层,状态13,1线 字符串或二进制数据将被截断。
源数据列与数据类型匹配,并且在目标表列的长度定义内,因此我不知道是什么原因导致了这个错误。
当前回答
这可能是一个具有挑战性的错误。以下是AmirCharania在https://connect.microsoft.com/SQLServer/feedback/details/339410/网站上发表的评论。
我调整了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)
其他回答
您需要发布源表和目标表的表定义,以便我们找出问题所在,但底线是源表中的一列比目标列大。这可能是您正在以一种您没有意识到的方式更改格式。要弄清楚这一点,您要使用的数据库模型也很重要。
我将添加另一个可能导致这个错误的原因,因为没有人提到过它,它可能会帮助一些未来的人(因为OP已经找到了他的答案)。如果要插入的表有触发器,则可能是触发器正在生成错误。我曾在更改表字段定义时看到过这种情况,但审计表没有更改。
问题很简单:源查询中的一个或多个列包含的数据超过了目标列的长度。一个简单的解决方案是使用源查询并在每一列上执行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 ...
SQL Server 2019将最终返回更有意义的错误消息。
二进制或字符串数据将被截断=>错误消息增强 如果您(在生产环境中)出现了该错误,则不太容易看到该错误来自哪一列或哪一行,以及如何准确定位它。
要启用新行为,需要使用DBCC TRACEON(460)。sys.messages中的新错误文本:
SELECT * FROM sys.messages WHERE message_id = 2628
2628 -字符串或二进制数据将在表' %中被截断。*ls ',列' %.*ls '。截断值:' %.*ls '。
字符串或二进制数据将被截断:替换臭名昭著的错误8152
这个新消息也会被反向移植到SQL Server 2017 CU12(以及即将发布的SQL Server 2016 SP2 CU),但不是默认情况下。您需要启用跟踪标志460,以便在会话级别或服务器级别将消息ID 8152替换为2628。 请注意,目前即使在SQL Server 2019 CTP 2.0中也需要启用相同的跟踪标志460。在未来的SQL Server 2019版本中,默认情况下,消息2628将取代消息8152。
SQL Server 2017 CU12也支持该特性。
改进:在SQL Server 2017中用扩展信息替换“字符串或二进制数据将被截断”消息
此SQL Server 2017更新引入了一条可选消息,其中包含以下附加上下文信息。 Msg 2628,级别16,状态6,程序程序命名,行Linenumber 字符串或二进制数据将在表'%中被截断。*ls',列'%.*ls'。 截断值:'%.*ls'。 新的消息ID是2628。如果启用了跟踪标志460,此消息将替换任何错误输出中的消息8152。
db < > fiddle演示
ALTER DATABASE SCOPED CONFIGURATION VERBOSE_TRUNCATION_WARNINGS = { ON | OFF } APPLIES TO: SQL Server (Starting with SQL Server 2019 (15.x)) and Azure SQL Database Allows you to enable or disable the new String or binary data would be truncated error message. SQL Server 2019 (15.x) introduces a new, more specific error message (2628) for this scenario: String or binary data would be truncated in table '%.*ls', column'%.*ls'. Truncated value: '%.*ls'. When set to ON under database compatibility level 150, truncation errors raise the new error message 2628 to provide more context and simplify the troubleshooting process. When set to OFF under database compatibility level 150, truncation errors raise the previous error message 8152. For database compatibility level 140 or lower, error message 2628 remains an opt-in error message that requires trace flag 460 to be enabled, and this database scoped configuration has no effect.
是的,“一品脱的酒放进半品脱的锅里是不行的”。我对人们建议的各种sp没有太多的运气(无论出于什么原因),但只要两个表在同一个DB中(或者您可以将它们放到同一个DB中),您就可以使用INFORMATION_SCHEMA。列来定位错误字段,因此:
select c1.table_name,c1.COLUMN_NAME,c1.DATA_TYPE,c1.CHARACTER_MAXIMUM_LENGTH,c2.table_name,c2.COLUMN_NAME, c2.DATA_TYPE,c2.CHARACTER_MAXIMUM_LENGTH
from [INFORMATION_SCHEMA].[COLUMNS] c1
left join [INFORMATION_SCHEMA].[COLUMNS] c2 on
c1.COLUMN_NAME=c2.COLUMN_NAME
where c1.TABLE_NAME='MyTable1'
and c2.TABLE_NAME='MyTable2'
--and c1.DATA_TYPE<>c2.DATA_TYPE
--and c1.CHARACTER_MAXIMUM_LENGTH <> c2.CHARACTER_MAXIMUM_LENGTH
order by c1.COLUMN_NAME
这将允许您上下滚动,比较字段的长度。注释的部分可以让您查看(显然是在未注释的情况下)是否存在数据类型不匹配,或者特别显示字段长度不同的数据类型(因为我懒得滚动),只需注意,所有内容都基于与目标列名匹配的源列名。