Строка SQL Server или двоичные данные будут усечены


149

Я участвую в проекте по миграции данных. Я получаю следующую ошибку при попытке вставить данные из одной таблицы в другую таблицу (SQL Server 2005):

Сообщение 8152, уровень 16, состояние 13, строка 1
Строка или двоичные данные будут обрезаны.

Столбцы исходных данных соответствуют типу данных и находятся в пределах определений длины столбцов таблицы назначения, поэтому я не понимаю, что может быть причиной этой ошибки.


Не могли бы вы опубликовать код и информацию о каждой таблице?
Кевин Мэнсел,

Обе таблицы достаточно велики - поэтому я опубликую только часть используемых определений таблиц и код - это приемлемо?
Джим Эванс

Табличные определения и код были бы великолепны.
IAmTimCorey

1
В прошлый раз, когда у меня была эта проблема, это было с триггером, триггер вставлял данные в таблицу аудита. Стоит также проверить триггер.
Сачин Вишвакарма

Ответы:


185

Вам нужно будет опубликовать определения таблиц для исходной и целевой таблиц, чтобы мы могли выяснить, где проблема, но суть в том, что один из ваших столбцов в исходной таблице больше, чем столбцы назначения . Может случиться так, что вы меняете форматы так, как не знали. Модель базы данных, из которой вы переходите, также важна для выяснения этого.


1
На мой комментарий выше - скоро в ближайшее время :)
Джим Эванс

3
Я столкнулся с той же проблемой, и мне пришлось сравнить все типы столбцов и размеры обеих таблиц, чтобы решить эту проблему.
Азиз Шейх

1
После прохождения сбора неполных определений таблиц, а затем получения моего кода sproc, оскорбительная колонка выскочила на меня, как молния ... Спасибо всем за ваш вклад.
Джим Эванс

Я не могу сказать вам, сколько раз я делал одно и то же. Рад, что вы смогли решить вашу проблему.
IAmTimCorey

Я отметил твой первый ответ как ответ, потому что именно это заставило меня найти ответ :)
Джим Эванс

86

Как уже говорили другие, один из типов данных столбцов в исходной таблице больше, чем столбцы назначения.

Простое решение - просто отключить предупреждение и разрешить усечение. Итак, если вы получаете эту ошибку, но уверены, что данные в вашей старой базе данных / таблице допустимы для усечения (обрезки по размеру), вы можете просто сделать следующее;

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

Как и выше, всегда не забывайте снова включать предупреждения. Надеюсь, это поможет.


1
Вы сэкономили мне несколько часов работы! Прими все мое спасибо!
Urasquirrel

Точно так же и здесь. Иногда мне приходится хранить данные в таблице, скажем, из веб-службы, где тип данных определяется только как «строка». Я не могу сделать все Varchar (MAX) ...
Курт

61

Проблема довольно проста: один или несколько столбцов в исходном запросе содержат данные, длина которых превышает длину столбца назначения. Простое решение - взять исходный запрос и выполнить его 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 - просто меньше символов для ввода.
MikeTeeVee

1
Спасибо, Томас, это странно, даже если у меня нет слишком длинных данных, мне все равно придется привести их к новому размеру столбца назначения, как только я это сделаю.
Мишель

15

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, чтобы заменить идентификатор сообщения 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, Level 16, State 6, Procedure ProcedureName, Line Linenumber
String or binary data would be truncated in table '%.*ls', column '%.*ls'.
Truncated value: '%.*ls'.

Новый идентификатор сообщения - 2628. Это сообщение заменяет сообщение 8152 в любом выводе ошибки, если флаг трассировки 460 включен.

db <> Fiddle demo


Конфигурация с измененной базой данных ALTER

VERBOSE_TRUNCATION_WARNINGS = {ON | OFF}

ПРИМЕНИМО к: SQL Server (начиная с SQL Server 2019 (15.x)) и база данных SQL Azure

Позволяет включить или отключить новую строку или двоичные данные будет обрезано сообщение об ошибке. SQL Server 2019 (15.x) представляет новое, более конкретное сообщение об ошибке (2628) для этого сценария:

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

Когда установлено значение ON для уровня совместимости базы данных 150, ошибки усечения вызывают новое сообщение об ошибке 2628, чтобы предоставить больше контекста и упростить процесс устранения неполадок.

Если для уровня совместимости базы данных установлено значение OFF, ошибки усечения вызывают предыдущее сообщение об ошибке 8152.

Для уровня совместимости базы данных 140 или ниже сообщение об ошибке 2628 остается сообщением об отказе, для которого требуется включить флаг трассировки 460, и эта конфигурация области действия базы данных не имеет никакого эффекта.


1
Теперь это также доступно для SQL Azure: azure.microsoft.com/en-gb/updates/……
Ян Кемп

7

Еще одна потенциальная причина этого заключается в том, что у вас есть настройка по умолчанию для столбца, длина которого превышает длину столбца. Похоже, кто-то толстый перебрал столбец, который имел длину 5, но значение по умолчанию превысило длину 5. Это сводило меня с ума, когда я пытался понять, почему он не работает ни на одной вставке, даже если все, что я вставлял, было один столбец с целым числом 1. Поскольку значение по умолчанию в схеме таблицы имело это нарушающее значение по умолчанию, оно все испортило - что, я думаю, подводит нас к извлеченному уроку - избегайте таблиц со значениями по умолчанию в схеме. :)


1
Я не думаю, что избегание значений по умолчанию является хорошим решением. Значения по умолчанию очень полезны. Я бы не разрешил «проблемы» базы данных, вызванные опечатками, путем удаления значений по умолчанию ...
Джейкоб Х

3

Для других, также проверьте свою хранимую процедуру . В моем случае в моей хранимой процедуре CustomSearchя случайно объявил недостаточную длину для своего столбца, поэтому, когда я вводил большие данные, я получал эту ошибку, даже если в моей базе данных была большая длина. Я просто изменил длину моего столбца в моем пользовательском поиске, ошибка исчезла. Это только для напоминания. Спасибо.


это именно то, что происходит со мной. исходные / целевые таблицы хорошо совпадают, но хранимый процесс имеет таблицу #, определенную с более короткой длиной, и там произошел сбой. Спасибо!
Джой Уокер

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)

Похоже, MS закрыл сайт Connect. Новая ссылка на эту проблему: feedback.azure.com/forums/908035-sql-server/suggestions/… ... все еще помечена как незапланированная. Я думаю, что комментарий, на который вы ссылаетесь, был (по иронии судьбы) обрезан, когда произошла миграция.
SWalters - Восстановить Монику

Интересно, что проблема была вновь открыта под немного другим названием: feedback.azure.com/forums/908035-sql-server/suggestions/… и она была указана как «На рассмотрении», так что надежда еще есть.
SWalters - Восстановить Монику

3

Вот немного другой ответ. Все имена и длины столбцов могут совпадать, но, возможно, вы указали столбцы в неправильном порядке в своем операторе SELECT. Скажем, у tableX и tableY есть столбцы с одинаковым именем, но в разном порядке


2

Я столкнулся с этой проблемой сегодня, и в моем поиске ответа на это минимальное информативное сообщение об ошибке я также нашел эту ссылку:

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

Так что, похоже, у Microsoft нет планов по расширению сообщений об ошибках в ближайшее время.

Поэтому я обратился к другим средствам.

Я скопировал ошибки в Excel:

(Затронут 1 ряд)

(Затронут 1 ряд)

(Затронуты 1 строка) Сообщение 8152, уровень 16, состояние 14, строка 13 Строка или двоичные данные будут усечены. Заявление было прекращено.

(Затронут 1 ряд)

посчитал количество строк в Excel, приблизился к счетчику записей, который вызвал проблему ... скорректировал мой код экспорта, чтобы распечатать близкий к нему SQL ... затем запустил 5 - 10 sql вставок вокруг проблемы sql и удалось определить проблему, увидеть строку, которая была слишком длинной, увеличить размер этого столбца, а затем большой файл импорта не запустился.

Немного взлома и обходного пути, но когда у вас остается мало выбора, вы делаете то, что можете.


2

Да, я тоже сталкиваюсь с такой проблемой.

REMARKS VARCHAR(500)
to
REMARKS VARCHAR(1000)

Здесь я изменил длину поля ЗАМЕЧАНИЯ от 500 до 1000


2

Я собираюсь добавить еще одну возможную причину этой ошибки только потому, что никто не упомянул об этом, и это могло бы помочь какому-нибудь будущему человеку (поскольку ОП нашел свой ответ). Если таблица, в которую вы вставляете, имеет триггеры, возможно, триггер генерирует ошибку. Я видел это, когда определения полей таблицы были изменены, а таблицы аудита - нет.


2

Да - «пинта в полпинты не пойдет». Мне не очень повезло (по какой-то причине) с различными 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 столбцами, и сразу два из них выпрыгнули. Спасибо!
Джой Уокер

1

Я использовал пустую строку «» при создании таблицы и затем получал сообщение об ошибке «Сообщение 8152, строка или двоичные данные будут обрезаны» при последующем обновлении. Это происходило из-за значения обновления, содержащего 6 символов, которое было больше ожидаемого определения столбца. Я использовал «ПРОБЕЛ», чтобы обойти это только потому, что знал, что я буду обновлять массово после первоначального создания данных, то есть столбец не будет оставаться пустым долго.

ТАК БОЛЬШОЕ ПРЕДУПРЕЖДЕНИЕ ЗДЕСЬ: Это не очень удобное решение, но оно полезно в том случае, когда вы собираете набор данных, например, для разовых аналитических запросов, когда вы создаете таблицу для интеллектуального анализа данных, применяя некоторую массовую обработку / интерпретацию и сохранение до и после результатов для последующего сравнения / майнинга. Это частое явление в моей работе.

Вы можете изначально заполнить, используя ключевое слово SPACE, т.е.

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

Последующие обновления «column_name» длиной не более 10 символов (замените при необходимости) будут разрешены без возникновения ошибки усечения. Опять же, я бы использовал это только в сценариях, аналогичных описанным в моем предупреждении.


1

Я построил хранимую процедуру, которая анализирует исходную таблицу или запрос с несколькими характеристиками на столбец, среди которых минимальная длина (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

Я храню эту процедуру в базе данных master, чтобы использовать ее в каждой базе данных следующим образом:

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,


Примечание: вы не должны использовать sp_префикс для ваших хранимых процедур. Microsoft зарезервировала этот префикс для собственного использования (см. Именование хранимых процедур ) , и вы рискуете столкнуться с именем в будущем. Это также плохо сказывается на производительности хранимых процедур . Лучше просто избегать sp_и использовать что-то другое в качестве префикса - или вообще без префикса!
marc_s

1

Я написал полезную процедуру хранения, которая поможет идентифицировать и решить проблему усечения текста (строка или двоичные данные будут усечены) при использовании оператора 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, '')


        --/programming/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


1

Если вы используете SQL Server 2016-2017: чтобы исправить это, включите флаг трассировки 460

DBCC TRACEON(460, 1);
GO

и убедитесь, что вы выключите его после:

DBCC TRACEOFF(460, 1);
GO

источник


0

это также может произойти, если у вас нет соответствующих разрешений


2
В самом деле? Фактическая ошибка «Строка или двоичные данные будет усечена»? Это кажется очень странной ошибкой, если у вас нет прав. Есть ли разрешение, которое мешает вам писать больше определенного количества данных? (Мне интересно, потому что я хочу автоматически проверять размер поля, когда получаю эту ошибку - поэтому, если это может произойти по какой-то другой причине, это очень интересно!)
Ян Грейнджер

0

У меня была похожая проблема. Я копировал данные из одной таблицы во все идентичные таблицы, кроме имени.

В конце концов я сбросил исходную таблицу во временную таблицу с помощью инструкции SELECT INTO.

SELECT *
INTO TEMP_TABLE
FROM SOURCE_TABLE;

Я сравнил схему исходной таблицы с временной таблицей. Я обнаружил, что одна из колонн была, varchar(4000)когда я ожидал varchar(250).

ОБНОВЛЕНИЕ: проблему varchar (4000) можно объяснить здесь, если вы заинтересованы:

Для Nvarchar (Max) я получаю только 4000 символов в TSQL?

Надеюсь это поможет.


0

Эта ошибка выдается, когда в столбец таблицы накладывается ограничение [в основном длина]. , Например, если схема базы данных для столбца myColumn имеет вид CHAR (2), то при вызове любого из ваших приложений для вставки значения необходимо передать строку длины два.

Ошибка в основном говорит это; Строка длиной три и выше не соответствует ограничениям длины, заданным схемой базы данных. Вот почему SQL Server предупреждает и выдает ошибку потери данных / усечения.


0

Пожалуйста, попробуйте следующий код:

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]
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.