Рядок або бінарні дані SQL Server будуть усічені


149

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

Msg 8152, рівень 16, стан 13, рядок 1
Рядок або двійкові дані будуть усічені.

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


Ви не хочете опублікувати якийсь код та інформацію про кожну таблицю?
Кевін Манзель

Обидва таблиці є досить великими - тож я розміщу лише ту частину визначень таблиці, які задіяні, та код - це прийнятно?
Джим Еванс

Визначення таблиці та код були б чудовими.
IAmTimCorey

1
Востаннє, коли у мене була ця проблема, саме з тригером, тригер вставляв дані в таблицю аудиту. варто також перевірити тригер.
Sachin

Відповіді:


185

Вам потрібно буде розмістити визначення таблиць для вихідних та цільових таблиць, щоб ми з'ясували, де проблема, але суть полягає в тому, що один із ваших стовпців у вихідній таблиці більший, ніж у стовпчиках призначення . Можливо, ви змінюєте формати таким чином, про який ви не знали. Модель бази даних, з якої ви рухаєтесь, важлива і для з'ясування цього.


1
За моїм коментарем вище - найближчим часом :)
Джим Еванс

3
Я зіткнувся з тією ж проблемою, і мені довелося порівняти всі типи та розміри стовпців обох таблиць, щоб виправити проблему.
Азіз Шайх

1
Після того, як пішов туди, я маю намір зібрати визначення часткової таблиці, а потім дістати мій проростовий код, стовпчик-кривдник вискочив на мене, як блискавка ... Дякую всім за ваш внесок.
Джим Еванс

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

Я позначив вас першою відповіддю як відповідь, тому що саме мене змусило знайти відповідь :)
Джим Еванс

86

Як уже говорили інші, один із типів даних ваших стовпців у вихідній таблиці більший, ніж цільові стовпці.

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

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

Як зазначено вище, завжди пам’ятайте, щоб потім знову ввімкнути попередження. Я сподіваюся, що це допомагає.


1
Ти врятував мені кілька годин роботи! Прийміть усі мої подяки!
Urasquirrel

Так само і тут. Іноді мені доводиться зберігати дані в таблиці з, скажімо, веб-сервісу, де тип даних визначається лише як "рядок". Я не можу зробити все Варшаром (MAX) ...
Curt

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 ...

Мій щоденний процес почався з цієї помилки. Дані, які я вставляв, завжди були досить короткими, щоб вміститись, і у мене завжди були інші рядки (у таблиці, з якої я витягувався) з великими рядками, які ніколи не вставлялися через мій фільтр. Можливо, індекс був відновлений, або статистику було оновлено, але привид в машині вирішив, що одного дня йому більше не подобається план запитів, тому що він знімав шлях, де дані (що були занадто широкими) "могли" бути вставлено до того, як він був відфільтрований присудком у пункті Де. Щоб обійти це, я використав ліворуч () замість 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 <> скриптова демонстрація


ПІДКЛЮЧЕНО КОНФІГУРАЦІЯ ДАНИХ

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'.

Якщо встановлено значення УВІМКНЕНО на рівні 150 сумісності баз даних, помилки усікання піднімають нове повідомлення про помилку 2628, щоб забезпечити більше контексту та спростити процес усунення несправностей.

Якщо встановлено значення OFF у рівні 150 сумісності баз даних, помилки усікання підвищують попереднє повідомлення про помилку 8152.

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


1
Це тепер також доступне для SQL Azure: azure.microsoft.com/en-gb/updates/…
Ian Kemp

7

Ще одна потенційна причина цього - якщо у вас встановлено значення за замовчуванням для стовпця, що перевищує довжину стовпця. Здається, хтось жир перебирав стовпчик, який мав довжину 5, але значення за замовчуванням перевищувало довжину 5. Це змусило мене гайок, оскільки я намагався зрозуміти, чому він не працює над жодною вставкою, навіть якщо все, що я вставляв, один стовпчик з цілим числом 1. Оскільки значення за замовчуванням на схемі таблиці було таким, що порушує значення за замовчуванням, воно все зіпсувало - що, мабуть, приводить нас до засвоєного уроку, - уникайте наявності в схемі таблиць із значенням за замовчуванням. :)


1
Я не думаю, що уникнення значень за замовчуванням є хорошим рішенням. Значення за замовчуванням дуже корисні. Я не вирішував би "проблеми" бази даних, викликані помилками помилок, видаляючи значення за замовчуванням ...
Jacob H

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 не планує розгортати повідомлення про помилку найближчим часом.

Тому я звернувся до інших засобів.

Я скопіював помилки на відмінності:

(1 ряд (и) зачеплений)

(1 ряд (и) зачеплений)

(1 ряд (и) зачіпають) Msg 8152, рівень 16, стан 14, рядок 13 Рядок або двійкові дані будуть усічені. Заява скасована.

(1 ряд (и) зачеплений)

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

Трохи хак і обхід, але коли ви залишилися з дуже маленьким вибором, ви робіть все, що можете.


2

Так, я також стикаюся з подібними проблемами.

REMARKS VARCHAR(500)
to
REMARKS VARCHAR(1000)

Тут я змінив довжину файлу REMARKS з 500 на 1000


2

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


2

Так - "пінта в напівпінтовий горщик не піде". Я не мав великого шансу (з будь-якої причини) з різними SP, які запропонували люди, АЛЕ поки дві таблиці знаходяться в одній БД (або ви можете отримати їх в одній БД), ви можете використовувати INFORMATION_SCHEMA. COLUMNS, щоб знайти поле (-ів) запиту, таким чином:

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

Я використовував порожню рядок '' у створенні таблиці, а потім отримував помилку 'Msg 8152, String або двійкові дані будуть врізані' при наступному оновленні. Це сталося завдяки значенню оновлення, що містить 6 символів, і воно було більшим, ніж передбачалося визначення стовпця. Я використовував "SPACE", щоб обійти це лише тому, що знав, що я буду оновлюватись масово після первинного створення даних, тобто стовпець не буде довго залишатися порожнім.

ТОЛЬКО ВЕЛИКИЙ КАВЕЙ ТУТ: Це не особливо гладке рішення, але це корисно у випадку, коли ви збираєте набір даних, наприклад, для разових запитів розвідки, коли ви створюєте таблицю для обміну даними, застосовуючи деяку об'ємну обробку / інтерпретацію та зберігання до і після результатів для подальшого порівняння / видобутку. Це часте явище в моїй роботі.

Ви можете спочатку заповнити за допомогою ключового слова SPACE, тобто

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

Подальші оновлення на "стовпчик_назви", що містить 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

Я зберігаю цю процедуру в основній базі даних, щоб я міг використовувати її у будь-якій базі даних:

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
Дійсно? Справжня помилка "Строкові або двійкові дані будуть усічені"? Це здається дуже дивною помилкою, якщо у вас немає дозволів. Чи є дозвіл, який перешкоджає написанню більше певного обсягу даних ?? (Мені цікаво, тому що я хочу перевірити розмір поля автоматично, коли отримую цю помилку - тому, якщо це може статися з якоїсь іншої причини, що дуже цікаво!)
Ian Grainger

0

У мене було подібне питання. Я копіював дані з однієї таблиці в ідентичну таблицю у всьому, крім імені.

Врешті-решт я скинув вихідну таблицю в таблицю темпів, використовуючи оператор SELECT INTO.

SELECT *
INTO TEMP_TABLE
FROM SOURCE_TABLE;

Я порівняв схему вихідної таблиці з таблицею temp. Я виявив, що одна з колонок була, 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.