SQL Server String veya ikili veriler kesilecek


154

Bir veri taşıma projesine dahil oldum. Bir tablodan başka bir tabloya veri eklemeye çalıştığımda aşağıdaki hatayı alıyorum (SQL Server 2005):

Msg 8152, Level 16, State 13, Line 1
String veya ikili veriler kesilecek.

Kaynak veri sütunları veri türüyle eşleşir ve hedef tablo sütunlarının uzunluk tanımları içindedir, bu nedenle bu hataya neyin neden olabileceği konusunda bir kayıp yaşıyorum.


Her tablo hakkında biraz kod ve bilgi gönderebilir misiniz?
Kevin Mansel

Tabloların her ikisi de oldukça büyük - bu yüzden sadece ilgili tablo tanımlarının ve kodun bir kısmını göndereceğim - bu kabul edilebilir mi?
Jim Evans

Tablo tanımları ve kodu harika olurdu.
IAmTimCorey

1
Bu sorunu en son yaşadığımda, tetikleyiciydi, Tetikleyici, bir denetim tablosuna veri ekliyordu. tetikleyiciyi de kontrol etmeye değer.
Sachin Vishwakarma

Yanıtlar:


188

Sorunun nerede olduğunu anlamamız için kaynak ve hedef tabloların tablo tanımlarını göndermeniz gerekecek, ancak sonuç olarak kaynak tablodaki sütunlarınızdan birinin hedef sütunlarınızdan daha büyük olmasıdır . Farkında olmadığınız bir şekilde formatları değiştiriyor olabilirsiniz. Taşındığınız veritabanı modeli de bunu anlamak için önemlidir.


3
Aynı sorunla karşılaştım ve sorunu çözmek için her iki tablonun tüm sütun türlerini ve boyutlarını karşılaştırmak zorunda kaldım.
Aziz Shaikh

1
Kısmi tablo tanımlarını toplama ve sonra sproc kodumu alma zorunluluğuna gittikten sonra, rahatsız edici sütun bir şimşek gibi üstüme fırladı ... Girişiniz için hepinize teşekkürler.
Jim Evans

1
SQL'in soruna hangi sütunun neden olduğunu söyleyememesi gerçekten harika. Bu dahiyane çizgiyi taklit etmek amacıyla tüm hata mesajlarımdan yararlı bilgileri kaldırmaya başladım.
AR

91

Diğerlerinin daha önce söylediği gibi, kaynak tablodaki sütun veri türlerinizden biri hedef sütunlarınızdan daha büyük.

Basit bir çözüm, uyarıyı kapatmak ve kesmenin gerçekleşmesine izin vermektir. Bu nedenle, bu hatayı alıyorsanız, ancak eski veritabanınızdaki / tablonuzdaki verilerin kesilmesinin (boyuta göre kesilmesinin) kabul edilebilir olduğundan eminseniz, basitçe aşağıdakileri yapabilirsiniz;

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

Yukarıdaki gibi, her zaman daha sonra uyarıları tekrar açmayı unutmayın. Umarım bu yardımcı olur.


Burada da aynı şekilde. Bazen verileri, örneğin bir web hizmetinden, veri türünün yalnızca "dizge" olarak tanımlandığı bir tabloya kaydetmem gerekir. Her şeyi bir Varchar (MAX) yapamam ...
Curt

61

Sorun oldukça basit: Kaynak sorgudaki bir veya daha fazla sütun, hedef sütununun uzunluğunu aşan veriler içeriyor. Basit bir çözüm, kaynak sorgunuzu almak ve Max(Len( source col ))her bir sütunda çalıştırmak olacaktır. Yani,

Select Max(Len(TextCol1))
    , Max(Len(TextCol2))
    , Max(Len(TextCol3))
    , ...
From ...

Ardından bu uzunlukları hedef tablonuzdaki veri türü uzunluklarıyla karşılaştırın. En az biri, hedef sütun uzunluğunu aşıyor.

Durumun böyle olmaması gerektiğinden kesinlikle eminseniz ve durumun böyle olup olmadığını umursamıyorsanız , başka bir çözüm de kaynak sorgu sütunlarını zorla hedef uzunluklarına çevirmektir (bu, çok uzun olan tüm verileri kesecektir):

Select Cast(TextCol1 As varchar(...))
    , Cast(TextCol2 As varchar(...))
    , Cast(TextCol3 As varchar(...))
    , ...
From ...

Günlük sürecim bu hatayla bozulmaya başladı. Eklediğim veriler her zaman sığacak kadar kısaydı ve her zaman (aldığım Tabloda) filtrem nedeniyle hiçbir zaman eklenmemiş büyük boy dizelerle başka satırlar vardı. Belki bir Dizin Yeniden Oluşturuldu veya İstatistikler Güncellendi, ancak makinedeki hayalet bir gün artık sorgu planından hoşlanmadığına karar verdi, çünkü onu verilerin (bu çok geniş) "olabileceği" bir yola indirdi. Nerede-Maddesinde Dayanak tarafından filtrelenmeden önce eklendi. Bu sorunu çözmek için CAST yerine LEFT () kullandım - yazmak için daha az karakter.
MikeTeeVee

1
Teşekkürler Thomas, bu garip, çok uzun bir veriye sahip olmasam bile, yine de yeni hedef sütun boyutuna çevirmek zorundayım, bunu yaptığım anda işe yaradı.
Michelle

17

SQL Server 2019 sonunda daha anlamlı bir hata mesajı döndürecektir.

İkili veya dize verileri kesilir => hata mesajı geliştirmeleri

Bu hatayı (üretimde) alıyorsanız, bu hatanın hangi sütun veya satırdan geldiğini ve tam olarak nasıl bulunacağını görmek açık değildir.

Yeni davranışı etkinleştirmek için kullanmanız gerekir DBCC TRACEON(460). Şuradan yeni hata metni sys.messages:

SELECT * FROM sys.messages WHERE message_id = 2628

2628 - Dize veya ikili veriler '%. * Ls', '%. * Ls' sütununda kesilecek. Kesilmiş değer: '%. * Ls'.

Dize veya İkili veriler kesilecek: ünlü 8152 hatası değiştiriliyor

Bu yeni mesaj ayrıca SQL Server 2017 CU12'ye (ve yakında çıkacak olan bir SQL Server 2016 SP2 CU'da) desteklenir, ancak varsayılan olarak değildir. Oturum veya sunucu düzeyinde ileti kimliği 8152'yi 2628 ile değiştirmek için izleme bayrağını 460 etkinleştirmeniz gerekir.

Şimdilik, SQL Server 2019 CTP 2.0'da bile aynı izleme bayrağı 460'ın etkinleştirilmesi gerektiğini unutmayın. Gelecekteki bir SQL Server 2019 sürümünde, mesaj 2628 varsayılan olarak 8152 mesajının yerini alacaktır.


SQL Server 2017 CU12 de bu özelliği destekler.

İyileştirme: SQL Server 2017'de genişletilmiş bilgilerle "Dize veya ikili veriler kesilecek" mesajı için isteğe bağlı değiştirme

Bu SQL Server 2017 güncelleştirmesi, aşağıdaki ek bağlam bilgilerini içeren isteğe bağlı bir ileti sunar.

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

Yeni mesaj kimliği 2628'dir. İzleme bayrağı (460) etkinleştirilirse bu mesaj herhangi bir hata çıktısında mesaj 8152'nin yerini alır.

db <> fiddle demosu


ALTER VERİTABANI KAPSAMLI YAPILANDIRMA

VERBOSE_TRUNCATION_WARNINGS = {ON | OFF}

ŞUNLARA UYGULANIR: SQL Server (SQL Server 2019 (15.x) ile başlayan) ve Azure SQL Veritabanı

Yeni String'i etkinleştirmenize veya devre dışı bırakmanıza izin verir veya ikili veriler kesilir hata mesajı. SQL Server 2019 (15.x), bu senaryo için yeni ve daha spesifik bir hata mesajı (2628) sunar:

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

Veritabanı uyumluluk seviyesi 150 altında AÇIK olarak ayarlandığında, kesme hataları, daha fazla bağlam sağlamak ve sorun giderme sürecini basitleştirmek için yeni hata mesajı 2628'i yükseltir.

Veritabanı uyumluluk seviyesi 150 altında KAPALI olarak ayarlandığında, kesme hataları önceki 8152 hata mesajını yükseltir.

Veri tabanı uyumluluk seviyesi 140 veya daha düşük için, hata mesajı 2628, izleme bayrağının 460 etkinleştirilmesini gerektiren bir kabul hata mesajı olarak kalır ve bu veri tabanı kapsamlı konfigürasyonun hiçbir etkisi yoktur.


1
Bu artık SQL Azure için de kullanılabilir: azure.microsoft.com/en-gb/updates/…
Ian Kemp

8

Bunun bir diğer olası nedeni, sütunun uzunluğunu aşan bir sütun için varsayılan bir değer ayarınızın olmasıdır. Görünüşe göre şişman birisinin uzunluğu 5 olan bir sütunu parmaklamış, ancak varsayılan değer 5 uzunluğunu aşmıştı. Bu, eklediğim tek şey olsa bile, neden herhangi bir ek parça üzerinde çalışmadığını anlamaya çalışırken beni deli etti. 1 tamsayısına sahip tek bir sütun. Tablo şemasındaki varsayılan değer, her şeyi bozan varsayılan değeri ihlal ettiğinden - ki bu da bizi öğrenilen derse getiriyor - şemada varsayılan değerlere sahip tablolardan kaçının. :)


1
Varsayılan değerlerden kaçınmanın iyi bir çözüm olduğunu düşünmüyorum. Varsayılan değerler çok kullanışlıdır. Varsayılan değerleri kaldırarak yazım hatalarının neden olduğu veritabanı "sorunlarını" çözemem ...
Jacob H

5

İşte biraz farklı bir cevap. Sütun adlarınız ve uzunluklarınızın tümü eşleşebilir, ancak SELECT deyiminizde sütunları yanlış sırada belirtiyor olabilirsiniz. Diyelim ki tableX ve tableY aynı ada sahip ancak farklı sırada sütunlara sahip


3

Diğerleri için de saklı yordamınızı kontrol edin . Depolanan yordamımda CustomSearchyanlışlıkla sütunum için yeterli uzunluk olmadığını beyan ettim, bu nedenle büyük bir veri girdiğimde veritabanımda büyük bir uzunluğa sahip olsam da bu hatayı aldım. Özel aramamda sütunumun uzunluğunu değiştirdim, hata ortadan kalkıyor. Bu sadece hatırlatma amaçlıdır. Teşekkürler.


tam olarak bana olan bu. kaynak / hedef tablolar iyi eşleşiyor, ancak depolanan işlemin daha kısa uzunlukta tanımlanmış bir # tablosu vardı ve orada başarısız oldu. Teşekkür ederim!
Joy Walker

3

Bu zorlu bir hata olabilir. İşte AmirCharania'nın yorumuna https://connect.microsoft.com/SQLServer/feedback/details/339410/ adresinden alınan bazı notlar .

Geçici tablo yerine gerçek bir tabloya seçilen veriler için AmirCharania tarafından verilen yanıtı ayarladım. Öncelikle veri kümenizi bir geliştirme tablosunda seçin ve ardından aşağıdakileri çalıştırın:

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)

Görünüşe göre MS, Connect sitesini kapatmış. Bu sorunun yeni bağlantısı: feedback.azure.com/forums/908035-sql-server/suggestions/… ... hala planlanmamış olarak işaretlendi. Bence bahsettiğiniz yorum, geçiş gerçekleştiğinde (ironik bir şekilde) kısaltıldı.
SWalters

İlginç bir şekilde, sorun biraz farklı bir başlık altında yeniden açıldı: feedback.azure.com/forums/908035-sql-server/suggestions/… ve "İnceleniyor" olarak listelendi, bu yüzden henüz umut var.
SWalters

2

Bugün bu problemle karşılaştım ve bu minimal bilgilendirici hata mesajına bir cevap arayışımda şu bağlantıyı da buldum:

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

Bu nedenle, Microsoft'un yakın zamanda herhangi bir zamanda hata mesajını genişletme planı yok gibi görünüyor.

Bu yüzden başka yollara döndüm.

Hataları excel'e kopyaladım:

(1 satır etkilendi)

(1 satır etkilendi)

(Etkilenen 1 satır) Msg 8152, Level 16, State 14, Line 13 Dize veya ikili veriler kesilecek. Açıklama sona erdirildi.

(1 satır etkilendi)

excel'deki satır sayısını saydı, soruna neden olan kayıt sayacına yaklaştım ... ihracat kodumu SQL'i ona yakın yazdıracak şekilde ayarladı ... sonra problem sql etrafına 5-10 sql ekleri koştum ve sorunu tam olarak belirlemeyi başardı, çok uzun olan dizeyi gördü, o sütunun boyutunu artırdı ve ardından büyük içe aktarma dosyası sorun olmadı.

Biraz hack ve geçici bir çözüm, ancak çok az seçeneğiniz olduğunda elinizden geleni yaparsınız.


2

Evet, ben de bu tür sorunlarla karşı karşıyayım.

REMARKS VARCHAR(500)
to
REMARKS VARCHAR(1000)

Burada REMARKS dosyalama uzunluğunu 500'den 1000'e değiştirdim


2

Bu hatanın olası bir nedenini daha ekleyeceğim çünkü kimse bundan bahsetmedi ve gelecekteki bir kişiye yardımcı olabilir (OP'nin cevabını bulduğundan beri). Eklediğiniz tabloda tetikleyiciler varsa, tetikleyici hatayı oluşturuyor olabilir. Tablo alanı tanımları değiştirildiğinde bunun olduğunu gördüm, ancak denetim tabloları değişmedi.


2

Evet - "yarım litrelik bir tencereye bir bardak gitmeyecek". İnsanların önerdiği çeşitli SP'lerde (herhangi bir nedenle) pek şansım olmadı, ANCAK iki tablo aynı DB'de olduğu sürece (veya onları aynı DB'ye getirebildiğiniz sürece), INFORMATION_SCHEMA'yı kullanabilirsiniz. Hatalı alanları bulmak için SÜTUNLAR, böylece:

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

Bu, ilerlerken alan uzunluklarını karşılaştırarak yukarı ve aşağı kaydırmanıza izin verir. Yorumlu bölümler, veri türü uyuşmazlıkları olup olmadığını görmenizi (açık bir şekilde, açık bir şekilde) veya özellikle alan uzunluğu açısından farklı olanları göstermenizi sağlar - çünkü kaydırmak için çok tembelim - sadece her şeyin kaynağa dayandığını unutmayın. hedefinkilerle eşleşen sütun adları.


Böyle bir şey yazacaktım ama sen bunu kolaylaştırdın. çok kullanışlı ve bir cazibe gibi çalıştı. 90+ sütunlu bir tabloyu karşılaştırmak için kullanabildim ve bunlardan ikisi hemen dışarı çıktı. Teşekkür ederim!
Joy Walker

1

Tablo oluştururken boş dize '' kullanıyordum ve ardından sonraki güncellemede 'Msg 8152, Dize veya ikili veriler kesilecek' hatası alıyordum. Bu, 6 karakter içeren güncelleme değeri ve sütun tanımının beklendiğinden daha büyük olması nedeniyle oluyordu. Bunun üstesinden gelmek için "SPACE" kullandım çünkü ilk veri oluşturma işleminden sonra toplu güncelleme yapacağımı biliyordum, yani sütun uzun süre boş kalmayacaktı.

BURADA ÇOK BÜYÜK MAĞAZA: Bu özellikle kaygan bir çözüm değildir, ancak veri madenciliği için bir tablo oluşturduğunuz, bazı toplu işleme / yorumlama uyguladığınız ve bir kereye mahsus istihbarat talepleri gibi bir veri setini bir araya getirdiğiniz durumlarda kullanışlıdır. daha sonra karşılaştırma / madencilik için sonuçlardan önce ve sonra depolama. Bu benim iş kolumda sık görülen bir durumdur.

Başlangıçta SPACE anahtar sözcüğünü yani

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

10 veya daha az karakterden oluşan "sütun_adı" için sonraki güncellemelere (uygun olduğu şekilde değiştirin), kesme hatasına neden olmadan izin verilecektir. Yine, bunu sadece uyarıda anlatılana benzer senaryolarda kullanırdım.


1

Sütun başına minimum uzunluk (min_len) ve maksimum uzunluk (maks_len) gibi çeşitli özelliklerle bir kaynak tabloyu veya sorguyu analiz eden bir saklı yordam oluşturdum.

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

Bu prosedürü ana veritabanında saklıyorum, böylece her veritabanında şu şekilde kullanabilirim:

sp_analysetable 'table_name', 1
// deep=1 for doing value analyses

Ve çıktı:

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,


Yan not: gerekir değil kullanmak sp_için saklanan prosedürleri için önek. Microsoft bu ön eki kendi kullanımı için ayırmıştır (bkz. Depolanan Prosedürleri Adlandırma ) ve ileride bir ad çatışması riskini alırsınız. Depolanan yordam performansınız için de kötü . sp_Önek olarak başka bir şeyden kaçınmak ve kullanmak en iyisidir - ya da hiç önek kullanmadan!
marc_s

1

INSERT SELECT deyimi kullanıldığında metin kesme sorununu (Dize veya ikili veriler kesilir) tanımlamaya ve çözmeye yardımcı olacak yararlı bir saklama prosedürü yazdım. Yalnızca CHAR, VARCHAR, NCHAR VE NVARCHAR alanlarını karşılaştırır ve hatanın olası nedeni olması durumunda alana göre bir değerlendirme alanı döndürür.

EXEC dbo.GetFieldStringTruncate SourceTableName, TargetTableName

Bu saklı yordam, bir INSERT SELECT ifadesi yapıldığında metnin kesilmesi sorununa yöneliktir.

Bu saklı yordamın çalışması, kullanıcının daha önce sorunla INSERT deyimini tanımlamasına bağlıdır. Daha sonra kaynak verileri genel bir geçici tabloya eklemek. SELECT INTO deyimi önerilir.

SELECT deyiminin her alanının diğer adında hedef tablonun alanıyla aynı adı kullanmanız gerekir.

İŞLEV KODU:

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

Şimdilik yalnızca CHAR, VARCHAR, NCHAR ve NVARCHAR veri türlerini desteklemektedir . Bu kodun son halini aşağıdaki sonraki bağlantıda bulabilirsiniz ve iyileştirmek için birbirimize yardımcı oluyoruz. GetFieldStringTruncate.sql

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


1

SQL Server 2016-2017 kullanıyorsanız: düzeltmek için izleme bayrağı 460'ı açın

DBCC TRACEON(460, 1);
GO

ve şunlardan sonra kapattığınızdan emin olun:

DBCC TRACEOFF(460, 1);
GO

kaynak


0

Bu, yeterli izinlere sahip olmadığınız zaman da olabilir


2
Gerçekten mi? Gerçek bir 'Dize veya ikili veri kesilecek' hatası mı? İzinlere sahip değilseniz bu çok garip bir hata gibi görünüyor. Belli bir miktardan fazlasını yazmanızı engelleyen bir izin var mı? (Ben bu hatayı alınca otomatik olarak saha boyutu için kontrol etmek istiyorum çünkü ilgi ediyorum! - çok ilginç başka bir nedenden dolayı oluşabilir eğer öyleyse)
Ian Grainger

0

Benzer bir sorun yaşadım. Bir tablodan, adı dışında her şeyde aynı tabloya veri kopyalıyordum.

Sonunda kaynak tabloyu bir SELECT INTO deyimi kullanarak geçici bir tabloya döktüm.

SELECT *
INTO TEMP_TABLE
FROM SOURCE_TABLE;

Kaynak tablonun şemasını geçici tabloyla karşılaştırdım. Birini varchar(4000)beklediğimde sütunlardan birinin a olduğunu buldum varchar(250).

GÜNCELLEME: İlgilenmeniz durumunda varchar (4000) sorunu burada açıklanabilir:

Nvarchar için (Maks) TSQL'de sadece 4000 karakter alıyorum?

Bu yardımcı olur umarım.


0

Bu hata, bir tablonun sütunu kısıtlama [çoğunlukla uzunluk] koyduğunda atılır. . Örneğin, myColumn sütunu için veritabanı şeması CHAR (2) ise, uygulamanızın herhangi birinden değer eklemek için yaptığınız çağrıda, String uzunluğunu iki olarak iletmelisiniz.

Hata temelde bunu söylüyor; üç ve üzeri uzunluk dizesi, veritabanı şeması tarafından belirtilen uzunluk kısıtlamasına uyacak şekilde tutarsız. Bu nedenle SQL Server uyarır ve veri kaybı / Kesme hatası verir.


0

Lütfen aşağıdaki kodu deneyin:

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]
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.