SQL Server 문자열 또는 이진 데이터가 잘립니다


149

데이터 마이그레이션 프로젝트에 참여하고 있습니다. 한 테이블에서 다른 테이블로 데이터를 삽입하려고하면 다음 오류가 발생합니다 (SQL Server 2005).

메시지 8152, 수준 16, 상태 13, 줄 1
문자열 또는 이진 데이터가 잘립니다.

소스 데이터 열은 데이터 유형과 일치하고 대상 테이블 열의 길이 정의 내에 있으므로이 오류의 원인에 대해 손실됩니다.


코드와 각 테이블에 대한 정보를 게시 하시겠습니까?
Kevin Mansel

테이블이 상당히 큽니다. 따라서 관련된 테이블 정의의 일부만 게시하고 코드는 허용됩니까?
Jim Evans

테이블 정의와 코드는 훌륭 할 것입니다.
IAmTimCorey

1
지난번 에이 문제가 발생했을 때 트리거가 발생했습니다. 트리거는 감사 테이블에 데이터를 삽입하고있었습니다. 트리거를 확인할 가치가 있습니다.
Sachin Vishwakarma

답변:


185

문제의 위치를 ​​파악하기 위해 소스 및 대상 테이블에 대한 테이블 정의를 게시해야하지만 , 결론은 소스 테이블의 열 중 하나가 대상 열보다 크다는 것 입니다. 모르는 방식으로 형식을 변경하고있을 수 있습니다. 이동하려는 데이터베이스 모델도이를 파악하는 데 중요합니다.


1
위의 내 의견에 따라-곧 :)
Jim Evans

3
나는 같은 문제에 직면했고 문제를 해결하기 위해 두 테이블의 모든 열 유형과 크기를 비교해야했습니다.
Aziz Shaikh

1
부분 테이블 정의를 수집하고 내 sproc 코드를 얻는 exeecise를 시작한 후 문제의 열이 번개처럼 나에게 뛰어 들었습니다 ... 입력 해 주셔서 감사합니다.
Jim Evans

나는 같은 일을 몇 번이나했는지 말할 수 없다. 문제를 해결할 수있어서 다행입니다.
IAmTimCorey 2016 년

답을 찾게 되었기 때문에 답장으로 첫 번째 답글을 표시했습니다.)
Jim Evans

86

다른 사람들이 이미 말했듯이 소스 테이블의 열 데이터 유형 중 하나가 대상 열보다 큽니다.

간단한 해결책은 단순히 경고를 끄고 잘리는 것을 허용하는 것입니다. 따라서이 오류가 발생하지만 이전 데이터베이스 / 테이블의 데이터가 잘 리거나 크기가 잘릴 수있는 경우 다음을 수행하면됩니다.

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

위와 같이 항상 경고를 다시 설정해야합니다. 이게 도움이 되길 바란다.


1
작업 시간을 절약했습니다! 내 모든 감사합니다!
Urasquirrel 2016 년

마찬가지로 여기. 때로는 데이터 유형이 "문자열"로만 정의되는 웹 서비스의 테이블에 데이터를 저장해야하는 경우가 있습니다. 나는 모든 것을 Varchar (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 ...

내 일상적인 프로세스 가이 오류로 깨지기 시작했습니다. 내가 삽입 한 데이터는 항상 맞을만큼 짧았으며 필터로 인해 삽입되지 않은 대형 문자열이있는 다른 행 (내가 가져온 테이블에 있음)이 항상있었습니다. 인덱스가 재 구축되었거나 통계가 업데이트되었을 수 있지만 어느 날 컴퓨터의 고스트가 쿼리 계획이 마음에 들지 않는다고 판단했습니다. Where-Clause의 술어에 의해 필터링되기 전에 삽입되었습니다. 이 문제를 해결하기 위해 CAST 대신 LEFT ()를 사용했습니다. 입력 할 문자 수가 적습니다.
MikeTeeVee

1
토마스에게 감사합니다. 이것은 이상합니다. 너무 긴 데이터가 없어도 작업을 수행하자마자 새로운 대상 열 크기로 캐스트해야합니다.
Michelle

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)에도 백 포트되지만 기본적으로는 아닙니다. 세션 또는 서버 레벨에서 메시지 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를 대체합니다.

db <> 바이올린 데모


데이터베이스 범위 변경 구성

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을 사용해야하는 옵트 인 오류 메시지로 남아 있으며이 데이터베이스 범위 구성은 적용되지 않습니다.


1
이제 SQL Azure에서도 사용할 수 있습니다. azure.microsoft.com/en-gb/updates/…
Ian Kemp

7

다른 잠재적 인 이유는 열 길이를 초과하는 열에 기본값을 설정 한 경우입니다. 누군가가 길이가 5 인 열을 뚱뚱한 것으로 보였지만 기본값은 길이가 5를 초과했습니다. 이것은 내가 삽입하는 모든 것이라도 테이블 스키마의 기본값에 위반 기본값이 있기 때문에 모든 것을 엉망으로 만들었습니다. 이로 인해 교훈을 얻었습니다. 기본 값이있는 테이블을 스키마에 두지 마십시오. :)


1
나는 기본값을 피하는 것이 좋은 해결책이라고 생각하지 않습니다. 기본값은 매우 유용합니다. 기본값을 제거하여 오타로 인한 데이터베이스 "문제"를 해결할 수 없습니다 ...
Jacob H

3

다른 경우에는 저장 프로시 저도 확인하십시오 . 내 경우에는 저장 프로 시저에서 CustomSearch실수로 열의 길이가 충분하지 않다고 선언 했으므로 큰 데이터를 입력하면 데이터베이스의 길이가 길어도 오류가 발생했습니다. 사용자 정의 검색에서 열 길이를 변경하여 오류가 사라졌습니다. 이것은 단지 알림입니다. 감사.


이것이 바로 저에게 일어나는 일입니다. 소스 / 타겟 테이블이 잘 일치하지만 저장된 proc에 #table이 더 짧은 길이로 정의되어있어 실패했습니다. 감사합니다!
조이 워커

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 개의 행이 영향을 받음)

엑셀의 행 수를 세고 문제를 일으킨 레코드 카운터에 가까워졌습니다. 내 수출 코드를 조정하여 SQL을 그에 가깝게 인쇄합니다 ... 그런 다음 문제 SQL 주위에 5-10 SQL 삽입을 실행했습니다. 문제 하나를 정확하게 찾아 내고, 너무 긴 문자열을보고, 해당 열의 크기를 늘리고 큰 가져 오기 파일에 아무런 문제가 없었습니다.

약간의 해킹과 해결 방법이 있지만 선택의 여지가 거의 없으면 할 수있는 일을하십시오.


2

그렇습니다, 나는 또한 이런 종류의 문제에 직면하고 있습니다.

REMARKS VARCHAR(500)
to
REMARKS VARCHAR(1000)

여기에서 REMARKS 파일 길이를 500에서 1000으로 변경했습니다.


2

아무도이 오류를 언급하지 않았기 때문에이 오류의 다른 가능한 원인을 추가하려고합니다 .OP가 자신의 답변을 찾았 기 때문에 미래의 사람에게 도움이 될 수 있습니다. 삽입하려는 테이블에 트리거가있는 경우 트리거가 오류를 생성 중일 수 있습니다. 테이블 필드 정의가 변경되었지만 감사 테이블은 변경되지 않았을 때 이런 일이 발생했습니다.


2

네- "반 파인트 냄비에 파인트가 가지 않습니다". 나는 사람들이 제안한 다양한 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

그러면 필드 길이를 비교하면서 위아래로 스크롤 할 수 있습니다. 주석이 달린 섹션에서는 데이터 유형이 일치하지 않거나 필드 길이가 다른 것을 구체적으로 보여 주거나 (주석 처리되지 않은 경우), 스크롤하기에는 너무 게으른 경우가 있습니다. 대상의 열 이름과 일치합니다.


나는 이런 식으로 글을 쓰려고했지만 당신은 그것을 쉽게 만들었습니다. 매우 편리하고 매력처럼 작동했습니다. 나는 그것을 90 + 열과 테이블을 비교하는 데 사용할 수 있었고 그중 두 개가 바로 뛰어 내 렸습니다. 감사합니다!
Joy Walker

1

테이블 생성시 빈 문자열 ''을 사용하고 후속 업데이트에서 오류 메시지 '메시지 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"에 대한 후속 업데이트 (적용 가능한 경우 대체)가 잘림 오류없이 허용됩니다. 다시 한 번,이 점은주의 사항에 설명 된 시나리오와 유사한 시나리오에서만 사용합니다.


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;

소스 테이블의 스키마를 임시 테이블과 비교했습니다. 나는 열 중 하나 varchar(4000)가을 기대할 때라는 것을 알았습니다 varchar(250).

업데이트 : 관심이있는 경우 varchar (4000) 문제를 여기에서 설명 할 수 있습니다.

Nvarchar (Max)의 경우 TSQL에서 4000 자만 가져 옵니까?

도움이 되었기를 바랍니다.


0

이 오류는 테이블의 열이 대부분 길이에 제약 조건을 둘 때 발생합니다. . 예를 들어 myColumn 열의 데이터베이스 스키마가 CHAR (2) 인 경우 응용 프로그램에서 값을 삽입하기 위해 호출 할 때 길이가 2 인 문자열을 전달해야합니다.

오류는 기본적으로 말합니다. 길이가 3 이상인 문자열은 데이터베이스 스키마에 지정된 길이 제한에 맞지 않습니다. 그렇기 때문에 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]
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.