【问题标题】:SQL Server String or binary data would be truncatedSQL Server 字符串或二进制数据将被截断
【发布时间】:2011-09-17 08:11:03
【问题描述】:

我参与了一个数据迁移项目。当我尝试将数据从一个表插入另一个表(SQL Server 2005)时出现以下错误:

消息 8152,第 16 级,状态 13,第 1 行
字符串或二进制数据将被截断。

源数据列与数据类型匹配,并且在目标表列的长度定义范围内,所以我不知道是什么导致了这个错误。

【问题讨论】:

  • 您介意发布一些代码和有关每个表的信息吗?
  • 这两个表都很大——所以我将只发布所涉及的表定义的一部分和代码——这可以接受吗?
  • 表定义和代码会很棒。
  • 上次我遇到这个问题时,是与触发器有关的,触发器是在审计表中插入数据。也值得检查触发器。

标签: sql-server tsql sql-server-2005 migration data-migration


【解决方案1】:

您需要发布源表和目标表的表定义,以便我们找出问题所在,但底线是源表中的一列大于目标列。可能是您正在以您不知道的方式更改格式。您要从中迁移的数据库模型对于弄清楚这一点也很重要。

【讨论】:

  • 我遇到了同样的问题,必须比较两个表的所有列类型和大小来解决问题。
  • 在完成收集部分表定义然后获取我的 sproc 代码之后,有问题的列像闪电一样向我跳了出来......谢谢大家的意见。
  • SQL 懒得告诉你是哪一列导致了问题真是太好了。我已经开始从我的所有错误消息中删除有用的信息,以模仿这种天才的表现。
  • 对我来说,这主要是因为 MS SQL 在长度为 1 的创建语句中创建了一个没有给定长度的“varchar”文件。这只是没用的。所以我会检查我在 DDL 表中是否有“varchars(1)”...或者你的数字是 bif fot int/bigint...
  • @A.R.这已在 SQL 2017 中修复。
【解决方案2】:

正如其他人已经说过的,源表中的列数据类型之一大于目标列。

一个简单的解决方案是简单地关闭警告并允许进行截断。因此,如果您收到此错误,但您确定旧数据库/表中的数据可以被截断(按大小),您可以简单地执行以下操作;

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

如上所述,请务必记住之后再次打开警告。我希望这会有所帮助。

【讨论】:

  • 这里也一样。有时我必须将数据存储到一个表中,比如一个 Web 服务,其中数据类型仅定义为“字符串”。我不能把 everything 变成 Varchar(MAX)...
  • 这没有工作,但我得到的结果让我能够解决问题(增加 varchar 长度)!所以谢谢。
  • 绝对不是大规模数据迁移的最佳做法,但这足以让我“调试”我的查询,注意到我的一个列确实在裁剪输入的字符串.在我的具体情况下,这是迄今为止最快的行动方案。
【解决方案3】:

问题很简单:源查询中的一个或多个列包含超过其目标列长度的数据。一个简单的解决方案是获取您的源查询并在每一列上执行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 ...

【讨论】:

  • 我的日常流程开始因这个错误而中断。我插入的数据总是足够短以适应,并且我总是有其他行(在我从中提取的表中)带有超大字符串,由于我的过滤器而从未插入过。也许重建了索引,或者更新了统计信息,但机器中的幽灵有一天决定不再喜欢查询计划,因为它把它带到了一条数据(太宽)“可能”的路径在 Where 子句中的谓词过滤之前插入。为了解决这个问题,我使用了 LEFT() 而不是 CAST - 只需输入更少的字符。
  • 谢谢托马斯,这很奇怪,即使我没有任何太长的数据,我仍然必须将其转换为新的目标列大小,只要我这样做就可以了.
【解决方案4】:

SQL Server 2019 最终会返回更有意义的错误消息。

Binary or string data would be truncated => error message enhancments

如果您有该错误(在生产中),则很难看出该错误来自哪一列或哪一行,以及如何准确定位它。

要启用新行为,您需要使用 DBCC TRACEON(460)。来自sys.messages 的新错误文本:

SELECT * FROM sys.messages WHERE message_id = 2628

2628 – 表‘%.*ls’、列‘%.*ls’中的字符串或二进制数据将被截断。截断值:'%.*ls'。

String or Binary data would be truncated: replacing the infamous error 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 也支持此功能。

Improvement: Optional replacement for "String or binary data would be truncated" message with extended information in SQL Server 2017

此 SQL Server 2017 更新引入了一条可选消息,其中包含以下附加上下文信息。

Msg 2628, Level 16, State 6, Procedure ProcedureName, Line Linenumber
String or binary data would be truncated in table '%.*ls', column '%.*ls'.
Truncated value: '%.*ls'.

新消息 ID 为 2628。如果启用了跟踪标志 460,此消息将替换任何错误输出中的消息 8152。

db<>fiddle demo


ALTER DATABASE SCOPED CONFIGURATION

VERBOSE_TRUNCATION_WARNINGS = { 开 |关闭}

适用于:SQL Server(从 SQL Server 2019 (15.x) 开始)和 Azure SQL 数据库

允许您启用或禁用新的字符串或二进制数据 截断的错误消息。 SQL Server 2019 (15.x) 引入了一个新的、更 此方案的特定错误消息 (2628):

String or binary data would be truncated in table '%.*ls', column'%.*ls'. Truncated value: '%.*ls'.

在数据库兼容级别 150 下设置为 ON 时,截断 错误引发新的错误消息 2628 以提供更多上下文和 简化故障排除过程。

在数据库兼容级别 150 下设置为 OFF 时,截断 错误引发先前的错误消息 8152。

对于数据库兼容级别 140 或更低,错误消息 2628 仍然是选择加入错误消息,需要跟踪标志 460 启用,并且此数据库范围配置无效。

【讨论】:

【解决方案5】:

另一个可能的原因是,如果您为超过列长度的列设置了默认值。似乎有人胖手指了一个长度为 5 但默认值超过了 5 的列。这让我发疯了,因为我试图理解为什么它在任何插入上都不起作用,即使我插入的只是一个整数为 1 的单列。因为表架构上的默认值违反了默认值,所以它把它搞砸了——我想这让我们学到了教训——避免在架构中使用默认值的表。 :)

【讨论】:

  • 我不认为避免使用默认值是一个好的解决方案。默认值非常有用。我不会通过删除默认值来解决由拼写错误引起的数据库“问题”...
【解决方案6】:

这是一个略有不同的答案。您的列名和长度可能都匹配,但也许您在 SELECT 语句中以错误的顺序指定了列。假设 tableX 和 tableY 具有相同名称但顺序不同的列

【讨论】:

  • !!如此出乎意料,但它奏效了。谢谢! (对我来说,失败的是 INSERT INTO x SELECT * FROM y。)
【解决方案7】:

如果您使用的是 SQL Server 2016-2017: 要修复它,请打开跟踪标志 460

DBCC TRACEON(460, 1);
GO

并确保在以下操作后将其关闭:

DBCC TRACEOFF(460, 1);
GO

source

【讨论】:

    【解决方案8】:

    对于其他人,还请检查您的存储过程。在我的存储过程CustomSearch 中,我不小心声明了我的列的长度不足,所以当我输入大数据时,即使我的数据库有很大的长度,我也会收到该错误。我只是在自定义搜索中更改了列的长度,错误就消失了。这只是为了提醒。谢谢。

    【讨论】:

    • 这正是发生在我身上的事。源/目标表匹配得很好,但存储的 proc 定义了一个长度较短的#table,并且在那里失败了。谢谢!
    【解决方案9】:

    这可能是一个具有挑战性的错误。以下是来自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)
    

    【讨论】:

    【解决方案10】:

    我将添加另一个可能导致此错误的原因,只是因为没有人提到它,它可能会帮助一些未来的人(因为 OP 找到了他的答案)。如果您要插入的表具有触发器,则可能是触发器正在生成错误。当表字段定义更改但审计表没有更改时,我已经看到这种情况发生。

    【讨论】:

      【解决方案11】:

      是的 - “一品脱放入半品脱的罐子里是不行的”。对于人们建议的各种 SP,我没有太多运气(无论出于何种原因),但是只要这两个表在同一个数据库中(或者您可以将它们放入同一个数据库中),您就可以使用 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
      

      这将使您可以上下滚动,并在进行时比较字段长度。注释部分可让您查看(显然,一旦未注释)是否存在数据类型不匹配,或者专门显示字段长度不同的部分 - 因为我懒得滚动 - 请注意整个事情都是基于源与目标的列名匹配的列名。

      【讨论】:

      • 我本来打算写这样的东西,但你让它变得简单了。非常方便,工作起来就像一个魅力。我能够用它来比较一个有 90 多列的表,其中两个立即跳出来。谢谢!
      【解决方案12】:

      我今天遇到了这个问题,在寻找这个最小信息错误消息的答案时,我还找到了这个链接:

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

      因此,微软似乎没有计划在短期内扩展错误消息。

      所以我转向了其他方式。

      我将错误复制到 excel:

      (受影响的 1 行)

      (受影响的 1 行)

      (1 行受影响) 消息 8152,第 16 层,第 14 状态,第 13 行 字符串或二进制数据将被截断。 声明已终止。

      (受影响的 1 行)

      计算 excel 中的行数,接近导致问题的记录计数器...调整我的导出代码以打印出接近它的 SQL...然后在周围运行 5 - 10 个 sql 插入问题sql并设法查明问题之一,查看过长的字符串,增加该列的大小,然后大导入文件运行没有问题。

      有点技巧和解决方法,但是当您离开时别无选择时,您会尽力而为。

      【讨论】:

        【解决方案13】:

        是的,我也面临这样的问题。

        REMARKS VARCHAR(500)
        to
        REMARKS VARCHAR(1000)
        

        在这里,我已将 REMARKS 归档长度从 500 更改为 1000

        【讨论】:

          【解决方案14】:

          我在创建表时使用了空字符串“”,然后在后续更新时收到错误“消息 8152,字符串或二进制数据将被截断”。这是因为更新值包含 6 个字符并且大于预期的列定义。我使用“SPACE”来解决这个问题只是因为我知道在初始数据创建之后我会进行批量更新,即该列不会长时间保持为空。

          这里有这么大的警告:这不是一个特别巧妙的解决方案,但在您将数据集组合在一起的情况下很有用,例如对于您正在创建数据挖掘表的一次性情报请求,应用一些批量处理/解释并在结果之前和之后存储以供以后比较/挖掘。这在我的工作中经常发生。

          您最初可以使用 SPACE 关键字进行填充,即

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

          随后将允许对“column_name”进行不超过 10 个字符(如适用,可替换)的更新,而不会导致截断错误。同样,我只会在类似于我的警告中描述的场景中使用它。

          【讨论】:

            【解决方案15】:

            我构建了一个存储过程,用于分析源表或查询,每列具有多个特征,其中最小长度 (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 '+@db+';'+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 @tmpQ=@tmpQ+' from tempdb.information_schema.columns c, (select null as value) sp'
              end
              else begin
                SET @tmpQ=@tmpQ+'
                  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 @tmpQ=@tmpQ+' where c.table_name = '''+@tableName+''''
            
              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 ['+@column_name+']),'+char(13)+char(10)+
                  '  @count_nulls=sum(case when ['+@column_name+'] is null then 1 else 0 end),'+char(13)+char(10)+
                  '  @count_blanks=sum(case when ltrim(['+@column_name+'])='''' then 1 else 0 end),'+char(13)+char(10)+
                  '  @count_numerics=sum(isnumeric(['+@column_name+'])),'+char(13)+char(10)+
                  '  @min_len=min(len(['+@column_name+'])),'+char(13)+char(10)+
                  '  @max_len=max(len(['+@column_name+']))'+char(13)+char(10)+
                  ' from ['+@tableName+']'
                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(['+@column_name+'] as varchar),  cast(['+@column_name+'] as varchar))'+char(13)+char(10)+
                    '  from ('+char(13)+char(10)+
                    '    select distinct ['+@column_name+'] from ['+@tableName+'] where ['+@column_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 @count_rows=@count_distinct then 1 else 0 end,
                  distincts      =@count_distinct,
                  nulls          =@count_nulls,
                  blanks         =@count_blanks,
                  numerics       =@count_numerics,
                  min_len        =@min_len,
                  max_len        =@max_len,
                  distinct_values=@distinct_values,
                  remarks       =
                    case when @count_rows=@count_nulls then 'all null,' else '' end+
                    case when @count_rows=@count_distinct then 'unique,' else '' end+
                    case when @count_distinct=0 then 'empty,' else '' end+
                    case when @min_len=@max_len then 'same length,' else '' end+
                    case when @count_rows=@count_numerics then 'all numeric,' else '' end
                WHERE [column]=@column_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,

            【讨论】:

            【解决方案16】:

            我编写了一个有用的存储过程来帮助识别和解决使用 INSERT SELECT 语句时出现的文本截断问题(字符串或二进制数据会被截断)。它仅比较字段 CHAR、VARCHAR、NCHAR 和 NVARCHAR,并在可能导致错误的情况下逐个字段返回评估字段。

            EXEC dbo.GetFieldStringTruncate SourceTableName, TargetTableName
            

            这个存储过程是针对INSERT SELECT语句时文本截断的问题。

            此存储过程的操作取决于用户先前确定存在问题的 INSERT 语句。然后将源数据插入到全局临时表中。建议使用 SELECT INTO 语句。

            您必须在 SELECT 语句的每个字段的别名中使用与目标表的字段相同的名称。

            功能代码:

            DECLARE @strSQL nvarchar(1000)
            IF NOT EXISTS (SELECT * FROM dbo.sysobjects where id = OBJECT_ID(N'[dbo].[GetFieldStringTruncate]'))
                BEGIN
                    SET @strSQL = 'CREATE PROCEDURE [dbo].[GetFieldStringTruncate] AS RETURN'
                    EXEC sys.sp_executesql @strSQL
                END
            
            GO
            
            SET ANSI_NULLS ON
            GO
            SET QUOTED_IDENTIFIER ON
            GO
            
            /*
            ------------------------------------------------------------------------------------------------------------------------
                Description:    
                                Syntax 
                                ---------------
                                dbo.GetFieldStringTruncate(SourceTable, TargetTable)
                                +---------------------------+-----------------------+
                                |   SourceTableName         |   VARCHAR(255)        |
                                +---------------------------+-----------------------+
                                |   TargetTableName         |   VARCHAR(255)        |
                                +---------------------------+-----------------------+
            
                                Arguments
                                ---------------
                                SourceTableName
                                The name of the source table. It should be a temporary table using double charp '##'. E.g. '##temp'
            
                                TargetTableName
                                The name of the target table. It is the table that receives the data used in the INSERT INTO stament.
            
                                Return Type
                                ----------------
                                Returns a table with a list of all the fields with the type defined as text and performs an evaluation indicating which field would present the problem of string truncation.
            
                                Remarks
                                ----------------
                                This stored procedure is oriented to the problem of text truncation when an INSERT SELECT statement is made.
                                The operation of this stored procedure depends on the user previously identifying the INSERT statement with the problem. Then inserting the source data into a global temporary table. The SELECT INTO statement is recommended.
                                You must use the same name of the field of the destination table in the alias of each field of the SELECT statement.
            
                                Examples
                                ====================================================================================================
            
                                --A. Test basic
            
                                    IF EXISTS (SELECT * FROM sys.objects  WHERE OBJECT_ID = OBJECT_ID(N'[dbo].[tblDestino]') AND TYPE IN (N'U'))
                                        DROP TABLE tblDestino
            
                                    CREATE TABLE tblDestino
                                    (
                                        Id INT IDENTITY,
                                        Field1 VARCHAR(10),
                                        Field2 VARCHAR(12),
                                        Field3 VARCHAR(11),
                                        Field4 VARCHAR(16),
                                        Field5 VARCHAR(5),
                                        Field6 VARCHAR(1),
                                        Field7 VARCHAR(1),
                                        Field8 VARCHAR(6),
                                        Field9 VARCHAR(6),
                                        Field10 VARCHAR(50),
                                        Field11 VARCHAR(50),
                                        Field12 VARCHAR(50)
                                    )
            
                                    INSERT INTO dbo.tblDestino
                                    (
                                         Field1 ,
                                         Field2 ,
                                         Field3 ,
                                         Field4 ,
                                         Field5 ,
                                         Field6 ,
                                         Field7 ,
                                         Field8 ,
                                         Field9 ,
                                         Field10 ,
                                         Field11 ,
                                         Field12
                                        )
                                    SELECT 
                                         '123456789' , -- Field1 - varchar(10)
                                         '123456789' , -- Field2 - varchar(12)
                                         '123456789' , -- Field3 - varchar(11)
                                         '123456789' , -- Field4 - varchar(16)
                                         '123456789' , -- Field5 - varchar(5)
                                         '123456789' , -- Field6 - varchar(1)
                                         '123456789' , -- Field7 - varchar(1)
                                         '123456789' , -- Field8 - varchar(6)
                                         '123456789' , -- Field9 - varchar(6)
                                         '123456789' , -- Field10 - varchar(50)
                                         '123456789' , -- Field11 - varchar(50)
                                         '123456789'  -- Field12 - varchar(50)
                                    GO  
            
                                Result:
                                    String or binary data would be truncated
            
            
                                *Here you get the truncation error. Then, we proceed to save the information in a global temporary table. 
                                *IMPORTANT REMINDER: You must use the same name of the field of the destination table in the alias of each field of the SELECT statement.
            
            
                                Process:
            
                                    IF OBJECT_ID('tempdb..##TEMP') IS NOT NULL DROP TABLE ##TEMP
                                    go
                                    SELECT 
                                         [Field1] = '123456789' ,
                                         [Field2] = '123456789' ,
                                         [Field3] = '123456789' ,
                                         [Field4] = '123456789' ,
                                         [Field5] = '123456789' ,
                                         [Field6] = '123456789' ,
                                         [Field7] = '123456789' ,
                                         [Field8] = '123456789' ,
                                         [Field9] = '123456789' ,
                                         [Field10] = '123456789' ,
                                         [Field11] = '123456789' ,
                                         [Field12] = '123456789'  
                                    INTO ##TEMP
            
                                Result:
                                (1 row(s) affected)
            
                                Test:
                                    EXEC dbo.GetFieldStringTruncate @SourceTableName = '##TEMP', @TargetTableName = 'tblDestino'
            
                                Result:
            
                                    (12 row(s) affected)
                                    ORIGEN Nombre Campo        ORIGEN Maximo Largo  DESTINO Nombre Campo     DESTINO Tipo de campo   Evaluación
                                    -------------------------- -------------------- ------------------------ ----------------------- -------------------------
                                    Field1                     9                    02 - Field1              VARCHAR(10)             
                                    Field2                     9                    03 - Field2              VARCHAR(12)             
                                    Field3                     9                    04 - Field3              VARCHAR(11)             
                                    Field4                     9                    05 - Field4              VARCHAR(16)             
                                    Field5                     9                    06 - Field5              VARCHAR(5)              possible field with error
                                    Field6                     9                    07 - Field6              VARCHAR(1)              possible field with error
                                    Field7                     9                    08 - Field7              VARCHAR(1)              possible field with error
                                    Field8                     9                    09 - Field8              VARCHAR(6)              possible field with error
                                    Field9                     9                    10 - Field9              VARCHAR(6)              possible field with error
                                    Field10                    9                    11 - Field10             VARCHAR(50)             
                                    Field11                    9                    12 - Field11             VARCHAR(50)             
                                    Field12                    9                    13 - Field12             VARCHAR(50)             
            
                                ====================================================================================================
            
                ------------------------------------------------------------------------------------------------------------
            
                Responsible:    Javier Pardo 
                Date:           October 19/2018
                WB tests:       Javier Pardo 
            
                ------------------------------------------------------------------------------------------------------------
            
            */
            
            ALTER PROCEDURE dbo.GetFieldStringTruncate
            (
                @SourceTableName AS VARCHAR(255)
                , @TargetTableName AS VARCHAR(255)
            )
            AS
            BEGIN
                BEGIN TRY
            
                    DECLARE @colsUnpivot AS NVARCHAR(MAX),
                        @colsUnpivotConverted AS NVARCHAR(MAX),
                       @query  AS NVARCHAR(MAX)
            
                    SELECT @colsUnpivot = stuff((
                                SELECT DISTINCT ',' + QUOTENAME(col.NAME)
                                FROM tempdb.sys.tables tab
                                INNER JOIN tempdb.sys.columns col
                                    ON col.object_id = tab.object_id
                                INNER JOIN tempdb.sys.types typ
                                    ON col.system_type_id = TYP.system_type_id
                                WHERE tab.NAME = @SourceTableName
                                FOR XML path('')
                                ), 1, 1, '')
                            ,@colsUnpivotConverted = stuff((
                                SELECT DISTINCT ',' + 'CONVERT(VARCHAR(MAX),' + QUOTENAME(col.NAME) + ') AS ' + QUOTENAME(col.NAME)
                                FROM tempdb.sys.tables tab
                                INNER JOIN tempdb.sys.columns col
                                    ON col.object_id = tab.object_id
                                INNER JOIN tempdb.sys.types typ
                                    ON col.system_type_id = TYP.system_type_id
                                WHERE tab.NAME = @SourceTableName
                                FOR XML path('')
                                ), 1, 1, '')
            
            
                    --https://stackoverflow.com/questions/11158017/column-conflicts-with-the-type-of-other-columns-in-the-unpivot-list
                    IF OBJECT_ID('tempdb..##TablaConMaximos') IS NOT NULL DROP TABLE ##TablaConMaximos
            
                    set @query 
                      = 'SELECT u.d AS colname, MAX(LEN(u.data)) as [maximo_largo]
                        INTO ##TablaConMaximos
                        FROM 
                        (
                            SELECT ' + @colsUnpivotConverted + '
                            FROM ' + @SourceTableName + '
                        ) T
                        UNPIVOT
                         (
                            data
                            for d in ('+ @colsunpivot +')
                         ) u
                         GROUP BY u.d'
            
                    PRINT @query
            
                    exec sp_executesql @query;
            
                    ------------------------------------------------------------------------------------------------------------
                    SELECT --'Nombre de campo' = RIGHT('00' + ISNULL(CONVERT(VARCHAR,col.column_id),''),2) + ' - ' + col.name + ' '
                        --, 'Tipo de campo' = ISNULL(CONVERT(VARCHAR,upper(typ.name)),'') + '(' + ISNULL(CONVERT(VARCHAR,col.max_length),'') + ')'
                        [ORIGEN Nombre Campo] = tcm.colname
                        , [ORIGEN Maximo Largo] = tcm.maximo_largo
                        , [DESTINO Nombre Campo] = DESTINO.[Nombre de campo]
                        , [DESTINO Tipo de campo] = DESTINO.[Tipo de campo]
                        , [Evaluación] = CASE WHEN DESTINO.maximo_largo < tcm.maximo_largo THEN 'possible field with error' ELSE '' END
                        --, * 
                    FROM tempdb.sys.tables tab
                        INNER JOIN tempdb.sys.columns col
                            ON col.object_id = tab.object_id
                        INNER JOIN tempdb.sys.types typ
                            ON col.system_type_id = TYP.system_type_id
                        RIGHT JOIN 
                            (
                                SELECT column_id
                                    , [Nombre de campo] = RIGHT('00' + ISNULL(CONVERT(VARCHAR,col.column_id),''),2) + ' - ' + col.name + ' '
                                    , [Tipo de campo] = ISNULL(CONVERT(VARCHAR,upper(typ.name)),'') + '(' + ISNULL(CONVERT(VARCHAR,col.max_length),'') + ')'
                                    , [maximo_largo] = col.max_length
                                    , [colname] = col.name
                                FROM sys.tables tab
                                    INNER JOIN sys.columns col
                                        ON col.object_id = tab.object_id
                                    INNER JOIN sys.types typ
                                        ON col.system_type_id = TYP.system_type_id
                                WHERE tab.NAME = @TargetTableName
                            ) AS DESTINO
                                ON col.name = DESTINO.colname
                        INNER JOIN ##TablaConMaximos tcm
                            ON tcm.colname = DESTINO.colname
            
                    WHERE tab.NAME = @SourceTableName
                        AND typ.name LIKE '%char%'
                    ORDER BY col.column_id
            
                END TRY
                BEGIN CATCH
                    SELECT 'Internal error ocurred' AS Message
                END CATCH   
            
            END
            

            目前只支持数据类型CHAR、VARCHAR、NCHAR和NVARCHAR。您可以在下面的下一个链接中找到此代码的最新版本,我们互相帮助改进它。 GetFieldStringTruncate.sql

            https://gist.github.com/jotapardo/210e85338f87507742701aa9d41cc51d

            【讨论】:

              【解决方案17】:

              当您没有足够的权限时也会发生这种情况

              【讨论】:

              • 真的吗?实际的“字符串或二进制数据将被截断”错误?如果您没有权限,这似乎是一个非常奇怪的错误。是否有阻止您写入超过一定数量数据的权限? (我很感兴趣,因为我想在收到此错误时自动检查字段大小 - 所以如果它可能由于其他原因而发生,那非常有趣!)
              【解决方案18】:

              我遇到了类似的问题。我正在将数据从一个表复制到一个相同的表中,但名称除外。

              最终我使用 SELECT INTO 语句将源表转储到临时表中。

              SELECT *
              INTO TEMP_TABLE
              FROM SOURCE_TABLE;
              

              我将源表的架构与临时表进行了比较。当我期待varchar(250) 时,我发现其中一列是varchar(4000)

              更新: 如果您有兴趣,可以在此处解释 varchar(4000) 问题:

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

              希望这会有所帮助。

              【讨论】:

                【解决方案19】:

                当表的列放置约束 [ 主要是长度 ] 时会引发此错误。 .例如。如果 myColumn 列的数据库架构是 CHAR(2),那么当您从任何应用程序调用插入值时,您必须传递长度为 2 的字符串。

                错误基本上说明了;长度为 3 及以上的字符串与数据库模式指定的长度限制不一致。这就是 SQL Server 发出警告并引发数据丢失/截断错误的原因。

                【讨论】:

                  【解决方案20】:

                  请尝试以下代码:

                  CREATE TABLE [dbo].[Department](
                      [Department_name] char(10) NULL
                  )
                  
                  INSERT INTO [dbo].[Department]([Department_name]) VALUES  ('Family Medicine')
                  --error will occur
                  
                   ALTER TABLE [Department] ALTER COLUMN [Department_name] char(50)
                  
                  INSERT INTO [dbo].[Department]([Department_name]) VALUES  ('Family Medicine')
                  
                  select * from [Department]
                  

                  【讨论】:

                    猜你喜欢
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    相关资源
                    最近更新 更多