데이터 마이그레이션 프로젝트에 참여하고 있습니다. 한 테이블에서 다른 테이블로 데이터를 삽입하려고하면 다음 오류가 발생합니다 (SQL Server 2005).
메시지 8152, 수준 16, 상태 13, 줄 1
문자열 또는 이진 데이터가 잘립니다.
소스 데이터 열은 데이터 유형과 일치하고 대상 테이블 열의 길이 정의 내에 있으므로이 오류의 원인에 대해 손실됩니다.
데이터 마이그레이션 프로젝트에 참여하고 있습니다. 한 테이블에서 다른 테이블로 데이터를 삽입하려고하면 다음 오류가 발생합니다 (SQL Server 2005).
메시지 8152, 수준 16, 상태 13, 줄 1
문자열 또는 이진 데이터가 잘립니다.
소스 데이터 열은 데이터 유형과 일치하고 대상 테이블 열의 길이 정의 내에 있으므로이 오류의 원인에 대해 손실됩니다.
답변:
문제의 위치를 파악하기 위해 소스 및 대상 테이블에 대한 테이블 정의를 게시해야하지만 , 결론은 소스 테이블의 열 중 하나가 대상 열보다 크다는 것 입니다. 모르는 방식으로 형식을 변경하고있을 수 있습니다. 이동하려는 데이터베이스 모델도이를 파악하는 데 중요합니다.
다른 사람들이 이미 말했듯이 소스 테이블의 열 데이터 유형 중 하나가 대상 열보다 큽니다.
간단한 해결책은 단순히 경고를 끄고 잘리는 것을 허용하는 것입니다. 따라서이 오류가 발생하지만 이전 데이터베이스 / 테이블의 데이터가 잘 리거나 크기가 잘릴 수있는 경우 다음을 수행하면됩니다.
SET ANSI_WARNINGS OFF;
-- Your insert TSQL here.
SET ANSI_WARNINGS ON;
위와 같이 항상 경고를 다시 설정해야합니다. 이게 도움이 되길 바란다.
이 문제는 매우 간단합니다. 소스 쿼리의 하나 이상의 열에 대상 열의 길이를 초과하는 데이터가 포함되어 있습니다. 간단한 해결책은 소스 쿼리를 가져와 Max(Len( source col ))
각 열에서 실행 하는 것입니다. 즉,
Select Max(Len(TextCol1))
, Max(Len(TextCol2))
, Max(Len(TextCol3))
, ...
From ...
그런 다음 해당 길이를 대상 테이블의 데이터 유형 길이와 비교하십시오. 하나 이상이 대상 열 길이를 초과합니다.
이것이 사실이 아니어야 하고 그것이 사실이 아닌지 신경 쓰지 않는다고 절대적으로 긍정적 인 경우 , 또 다른 해결책은 소스 쿼리 열을 대상 길이로 강제로 캐스트하는 것입니다 (너무 긴 데이터는 잘림).
Select Cast(TextCol1 As varchar(...))
, Cast(TextCol2 As varchar(...))
, Cast(TextCol3 As varchar(...))
, ...
From ...
SQL Server 2019 는 마침내 더 의미있는 오류 메시지를 반환합니다.
이진 또는 문자열 데이터가 잘립니다 => 오류 메시지 향상
해당 오류 (생산 중)가있는 경우이 오류가 발생하는 열 또는 행과 정확한 위치를 확인하는 방법이 명확하지 않습니다.
새로운 동작을 사용하려면을 사용해야 DBCC TRACEON(460)
합니다. 의 새로운 오류 텍스트 sys.messages
:
SELECT * FROM sys.messages WHERE message_id = 2628
2628 – 열 '%. * ls'의 테이블 '%. * ls'에서 문자열 또는 이진 데이터가 잘립니다. 잘린 값 : '%. * ls'.
문자열 또는 이진 데이터가 잘립니다 : 악명 높은 오류 8152 대체
이 새 메시지는 SQL Server 2017 CU12 (및 곧 출시 될 SQL Server 2016 SP2 CU)에도 백 포트되지만 기본적으로는 아닙니다. 세션 또는 서버 레벨에서 메시지 ID 8152를 2628으로 바꾸려면 추적 플래그 460을 활성화해야합니다.
현재로서는 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'.
새 메시지 ID는 2628입니다.이 메시지는 추적 플래그 460이 사용 가능한 경우 오류 출력에서 메시지 8152를 대체합니다.
VERBOSE_TRUNCATION_WARNINGS = {ON | 끄기}
적용 대상 : SQL Server (SQL Server 2019 (15.x로 시작)) 및 Azure SQL Database
새 문자열을 활성화하거나 비활성화 할 수 있습니다. 이진 데이터가 잘 리면 오류 메시지가 표시됩니다. 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를 초과했습니다. 이것은 내가 삽입하는 모든 것이라도 테이블 스키마의 기본값에 위반 기본값이 있기 때문에 모든 것을 엉망으로 만들었습니다. 이로 인해 교훈을 얻었습니다. 기본 값이있는 테이블을 스키마에 두지 마십시오. :)
이것은 어려운 오류 일 수 있습니다. 다음은 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)
나는 오늘이 문제를 발견 했으며이 최소한의 유익한 오류 메시지에 대한 답을 찾기 위해이 링크를 찾았습니다.
따라서 Microsoft는 언제든지 오류 메시지를 확장 할 계획이없는 것 같습니다.
그래서 나는 다른 수단으로 돌았습니다.
오류를 Excel에 복사했습니다.
(1 개의 행이 영향을 받음)
(1 개의 행이 영향을 받음)
(1 개의 행에 영향을 미침) 메시지 8152, 수준 16, 상태 14, 줄 13 문자열 또는 이진 데이터가 잘립니다. 그 진술서는 만료되었습니다.
(1 개의 행이 영향을 받음)
엑셀의 행 수를 세고 문제를 일으킨 레코드 카운터에 가까워졌습니다. 내 수출 코드를 조정하여 SQL을 그에 가깝게 인쇄합니다 ... 그런 다음 문제 SQL 주위에 5-10 SQL 삽입을 실행했습니다. 문제 하나를 정확하게 찾아 내고, 너무 긴 문자열을보고, 해당 열의 크기를 늘리고 큰 가져 오기 파일에 아무런 문제가 없었습니다.
약간의 해킹과 해결 방법이 있지만 선택의 여지가 거의 없으면 할 수있는 일을하십시오.
네- "반 파인트 냄비에 파인트가 가지 않습니다". 나는 사람들이 제안한 다양한 SP에 대해 (어떤 이유로 든) 운이 없었지만 두 테이블이 같은 DB에 있거나 (또는 동일한 DB에 넣을 수있는 한) 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
그러면 필드 길이를 비교하면서 위아래로 스크롤 할 수 있습니다. 주석이 달린 섹션에서는 데이터 유형이 일치하지 않거나 필드 길이가 다른 것을 구체적으로 보여 주거나 (주석 처리되지 않은 경우), 스크롤하기에는 너무 게으른 경우가 있습니다. 대상의 열 이름과 일치합니다.
테이블 생성시 빈 문자열 ''을 사용하고 후속 업데이트에서 오류 메시지 '메시지 8152, 문자열 또는 이진 데이터가 잘립니다'를 수신했습니다. 이는 6 자 포함 업데이트 값이 예상되는 열 정의보다 크기 때문에 발생했습니다. "SPACE"를 사용하여 초기 데이터 생성 후 대량 업데이트가 가능하다는 것을 알았 기 때문에이 문제를 해결했습니다. 즉, 열이 오랫동안 비어 있지 않은 상태였습니다.
여기에 큰 경고가 있습니다 : 이것은 특히 매끄러운 솔루션은 아니지만 데이터 마이닝을위한 테이블을 생성하고 대량 처리 / 해석 및 추후 비교 / 마이닝을 위해 결과 전후 저장. 이것은 내 업무 라인에서 자주 발생합니다.
처음에는 SPACE 키워드를 사용하여 채울 수 있습니다.
select
Table1.[column1]
,Table1.[column2]
,SPACE(10) as column_name
into table_you_are_creating
from Table1
where ...
그런 다음 10 자 이하의 "column_name"에 대한 후속 업데이트 (적용 가능한 경우 대체)가 잘림 오류없이 허용됩니다. 다시 한 번,이 점은주의 사항에 설명 된 시나리오와 유사한 시나리오에서만 사용합니다.
최소 길이 (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_
접두사로 다른 것을 피하고 사용하거나 접두사를 사용 하지 않는 것이 가장 좋습니다 !
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
적절한 권한이없는 경우에도 발생할 수 있습니다
나는 비슷한 문제가 있었다. 이름을 제외한 모든 테이블에서 하나의 테이블에서 동일한 테이블로 데이터를 복사하고있었습니다.
결국 SELECT INTO 문을 사용하여 소스 테이블을 임시 테이블로 덤프했습니다.
SELECT *
INTO TEMP_TABLE
FROM SOURCE_TABLE;
소스 테이블의 스키마를 임시 테이블과 비교했습니다. 나는 열 중 하나 varchar(4000)
가을 기대할 때라는 것을 알았습니다 varchar(250)
.
업데이트 : 관심이있는 경우 varchar (4000) 문제를 여기에서 설명 할 수 있습니다.
Nvarchar (Max)의 경우 TSQL에서 4000 자만 가져 옵니까?
도움이 되었기를 바랍니다.
다음 코드를 시도하십시오 :
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]