String SQL Server atau data biner akan terpotong

149

Saya terlibat dalam proyek migrasi data. Saya mendapatkan kesalahan berikut ketika saya mencoba memasukkan data dari satu tabel ke tabel lain (SQL Server 2005):

Msg 8152, Level 16, Status 13, Baris 1
String atau data biner akan terpotong.

Kolom data sumber cocok dengan tipe data dan berada dalam definisi panjang kolom tabel tujuan jadi saya bingung apa yang bisa menyebabkan kesalahan ini.

Jim Evans
sumber
Maukah Anda memposting beberapa kode, dan informasi tentang setiap tabel?
Kevin Mansel
Tabel keduanya cukup besar - jadi saya hanya akan memposting bagian dari definisi tabel yang terlibat dan kode - apakah itu dapat diterima?
Jim Evans
Definisi tabel dan kode akan sangat bagus.
IAmTimCorey
1
Terakhir kali ketika saya memiliki masalah ini, itu dengan pelatuk, pelatuk memasukkan data dalam tabel audit. layak dicoba juga.
Sachin Vishwakarma

Jawaban:

185

Anda perlu memposting definisi tabel untuk tabel sumber dan tujuan agar kami dapat mengetahui di mana masalahnya tetapi intinya adalah bahwa salah satu kolom Anda di tabel sumber lebih besar dari kolom tujuan Anda . Bisa jadi Anda mengubah format dengan cara yang tidak Anda sadari. Model basis data yang Anda pindahkan penting untuk menentukannya juga.

IAmTimCorey
sumber
1
Per komentar saya di atas - sebentar lagi :)
Jim Evans
3
Saya telah menghadapi masalah yang sama dan harus membandingkan semua jenis dan ukuran kolom dari kedua tabel untuk memperbaiki masalah.
Aziz Shaikh
1
Setelah melalui pelatihan mengumpulkan definisi tabel parsial dan kemudian mendapatkan kode sproc saya kolom menyinggung melompat keluar kepada saya seperti petir ... Terima kasih semua atas masukan Anda.
Jim Evans
Saya tidak bisa memberi tahu Anda berapa kali saya melakukan hal yang sama. Senang Anda bisa menyelesaikan masalah Anda.
IAmTimCorey
Saya menandai Anda sebagai balasan pertama karena itu yang membuat saya menemukan jawabannya :)
Jim Evans
86

Seperti yang telah dikatakan orang lain, salah satu dari kolom tipe data Anda di tabel sumber lebih besar dari kolom tujuan Anda.

Solusi sederhana adalah dengan mematikan peringatan dan membiarkan pemotongan terjadi. Jadi, jika Anda menerima kesalahan ini tetapi Anda yakin itu dapat diterima untuk data dalam database / tabel lama Anda akan dipotong (dipotong menurut ukuran) Anda cukup melakukan hal berikut;

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

Seperti di atas, selalu ingat untuk mengaktifkan kembali peringatan setelahnya. Saya harap ini membantu.

Rudi Kershaw
sumber
1
Anda menyelamatkan saya beberapa jam kerja! Terima semua terima kasih saya!
Urasquirrel
Begitu juga di sini. Kadang-kadang saya harus menyimpan data ke dalam tabel dari, katakanlah, layanan web, di mana datatype didefinisikan hanya sebagai "string". Saya tidak bisa menjadikan semuanya sebagai Varchar (MAX) ...
Curt
61

Masalahnya cukup sederhana: satu atau lebih kolom di kueri sumber berisi data yang melebihi panjang kolom tujuan. Solusi sederhana adalah mengambil kueri sumber Anda dan mengeksekusi Max(Len( source col ))pada setiap kolom. Yaitu,

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

Kemudian bandingkan panjang tersebut dengan panjang tipe data di tabel tujuan Anda. Paling tidak satu, melebihi panjang kolom tujuan.

Jika Anda benar-benar yakin bahwa ini tidak boleh terjadi dan tidak peduli jika bukan itu masalahnya , maka solusi lain adalah dengan secara paksa melemparkan kolom kueri sumber ke panjang tujuan mereka (yang akan memotong data apa pun yang terlalu panjang):

Select Cast(TextCol1 As varchar(...))
    , Cast(TextCol2 As varchar(...))
    , Cast(TextCol3 As varchar(...))
    , ...
From ...
Thomas
sumber
Proses harian saya mulai terputus dengan kesalahan ini. Data yang saya masukkan selalu cukup pendek agar sesuai dan saya selalu memiliki baris lain (dalam Tabel saya tarik dari) dengan string besar yang tidak pernah dimasukkan karena filter saya. Mungkin Indeks itu Dibangun Kembali, atau Statistik Diperbarui, tetapi hantu di mesin memutuskan suatu hari ia tidak menyukai rencana permintaan lagi, karena membawanya ke jalur di mana data (yang terlalu lebar) "bisa" menjadi disisipkan sebelum difilter oleh Predikat di Where-Clause. Untuk mengatasi ini, saya menggunakan LEFT () alih-alih CAST - hanya sedikit karakter untuk mengetik.
MikeTeeVee
1
Terima kasih Thomas, ini aneh, bahkan saya tidak punya data yang terlalu panjang, saya masih harus memasukkannya ke ukuran kolom tujuan baru, segera setelah saya melakukannya itu berfungsi.
Michelle
15

SQL Server 2019 akhirnya akan mengembalikan pesan kesalahan yang lebih bermakna.

Biner atau data string akan terpotong => peningkatan pesan kesalahan

jika Anda memiliki kesalahan itu (dalam produksi), tidak jelas untuk melihat dari kolom atau baris mana kesalahan ini berasal, dan bagaimana cara menemukannya dengan tepat.

Untuk mengaktifkan perilaku baru yang perlu Anda gunakan DBCC TRACEON(460). Teks kesalahan baru dari sys.messages:

SELECT * FROM sys.messages WHERE message_id = 2628

2628 - Data string atau biner akan dipotong dalam tabel '%. * Ls', kolom '%. * Ls'. Nilai terpotong: '%. * Ls'.

Data String atau Binary akan terpotong: mengganti kesalahan yang terkenal 8152

Pesan baru ini juga di-backport ke SQL Server 2017 CU12 (dan SQL Server 2016 SP2 CU yang akan datang), tetapi tidak secara default. Anda harus mengaktifkan jejak flag 460 untuk mengganti pesan ID 8152 dengan 2628, baik di tingkat sesi atau server.

Perhatikan bahwa untuk saat ini, bahkan di SQL Server 2019 CTP 2.0 tanda jejak yang sama 460 perlu diaktifkan. Dalam rilis SQL Server 2019 mendatang, pesan 2628 akan menggantikan pesan 8152 secara default.


SQL Server 2017 CU12 juga mendukung fitur ini.

Peningkatan: Penggantian opsional untuk pesan "Data string atau biner akan terpotong" dengan informasi tambahan di SQL Server 2017

Pembaruan SQL Server 2017 ini memperkenalkan pesan opsional yang berisi informasi konteks tambahan berikut.

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 pesan baru adalah 2628. Pesan ini menggantikan pesan 8152 dalam output kesalahan apa pun jika tanda jejak 460 diaktifkan.

db <> demo biola


ALTER DATABASE CONFIGURATION

VERBOSE_TRUNCATION_WARNINGS = {ON | MATI }

BERLAKU UNTUK: SQL Server (Dimulai dengan SQL Server 2019 (15.x)) dan Database SQL Azure

Memungkinkan Anda untuk mengaktifkan atau menonaktifkan data String atau biner yang baru akan terpotong pesan kesalahan. SQL Server 2019 (15.x) memperkenalkan pesan kesalahan baru, lebih spesifik (2628) untuk skenario ini:

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

Ketika diatur ke ON di bawah tingkat kompatibilitas basis data 150, kesalahan pemotongan meningkatkan pesan kesalahan baru 2628 untuk memberikan lebih banyak konteks dan menyederhanakan proses pemecahan masalah.

Ketika diatur ke OFF di bawah tingkat kompatibilitas basis data 150, kesalahan pemotongan meningkatkan pesan kesalahan sebelumnya 8152.

Untuk tingkat kompatibilitas basis data 140 atau lebih rendah, pesan kesalahan 2628 tetap pesan kesalahan pilihan yang membutuhkan tanda jejak 460 untuk diaktifkan, dan konfigurasi cakupan database ini tidak berpengaruh.

Lukasz Szozda
sumber
1
Ini sekarang juga tersedia untuk SQL Azure: azure.microsoft.com/en-gb/updates/…
Ian Kemp
7

Salah satu alasan potensial lainnya untuk hal ini adalah jika Anda memiliki pengaturan nilai default untuk kolom yang melebihi panjang kolom. Tampaknya seseorang gemuk meraba kolom yang memiliki panjang 5 tetapi nilai default melebihi panjang 5. Ini membuat saya gila ketika saya mencoba untuk memahami mengapa itu tidak bekerja pada insert apa pun, bahkan jika semua yang saya masukkan adalah satu kolom dengan bilangan bulat dari 1. Karena nilai default pada skema tabel memiliki yang melanggar nilai default itu mengacaukan semuanya - yang saya kira membawa kita ke pelajaran yang dipetik - hindari memiliki tabel dengan nilai default di skema. :)

Brian
sumber
1
Saya tidak berpikir menghindari nilai standar adalah solusi yang baik. Nilai default sangat berguna. Saya tidak akan menyelesaikan "masalah" database yang disebabkan oleh kesalahan pengetikan dengan menghapus nilai default ...
Jacob H
3

Untuk yang lain, periksa juga prosedur tersimpan Anda . Dalam kasus saya dalam prosedur tersimpan CustomSearchsaya secara tidak sengaja menyatakan tidak cukup panjang untuk kolom saya, jadi ketika saya memasukkan data besar saya menerima kesalahan itu meskipun saya memiliki panjang yang besar pada database saya. Saya baru saja mengubah panjang kolom saya di pencarian kustom saya kesalahan hilang. Ini hanya untuk pengingat. Terima kasih.

bot
sumber
inilah yang terjadi pada saya. tabel sumber / target cocok dengan baik tetapi proc yang disimpan memiliki #table yang didefinisikan dengan panjang yang lebih pendek dan gagal di sana. Terima kasih!
Joy Walker
3

Ini bisa menjadi kesalahan yang menantang. Berikut adalah beberapa catatan yang diambil dari https://connect.microsoft.com/SQLServer/feedback/details/339410/ lihat komentar AmirCharania.

Saya telah menyesuaikan jawaban yang diberikan oleh AmirCharania untuk data yang dipilih ke tabel aktual, bukan temp. Pertama-tama pilih dataset Anda ke dalam tabel pengembangan kemudian jalankan yang berikut:

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)
mcfea
sumber
Sepertinya MS telah mematikan situs Connect. Tautan baru ke masalah ini adalah: feedback.azure.com/forums/908035-sql-server/suggestions/… ... masih ditandai sebagai tidak terencana. Saya pikir komentar yang Anda maksud adalah (ironisnya) terpotong ketika migrasi terjadi.
SWalters
Menariknya, masalah ini dibuka lagi dengan judul yang sedikit berbeda: feedback.azure.com/forums/908035-sql-server/suggestions/… dan telah terdaftar sebagai "Dalam Tinjauan", jadi masih ada harapan.
SWalters
3

Ini jawaban yang sedikit berbeda. Nama & panjang kolom Anda mungkin cocok, tetapi mungkin Anda menentukan kolom dengan urutan yang salah dalam pernyataan SELECT Anda. Katakanlah tableX dan tableY memiliki kolom dengan nama yang sama, tetapi dalam urutan yang berbeda

SoloPilot
sumber
2

Saya menemukan masalah ini hari ini, dan dalam pencarian saya untuk jawaban atas pesan kesalahan informatif minimal ini saya juga menemukan tautan ini:

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

Jadi sepertinya microsoft tidak memiliki rencana untuk memperluas pesan kesalahan dalam waktu dekat.

Jadi saya beralih ke cara lain.

Saya menyalin kesalahan untuk unggul:

(1 baris terpengaruh)

(1 baris terpengaruh)

(1 baris terpengaruh) Msg 8152, Level 16, State 14, Line 13 String atau data biner akan terpotong. Pernyataan itu telah dihentikan.

(1 baris terpengaruh)

menghitung jumlah baris dalam excel, harus menutup ke catatan catatan yang menyebabkan masalah ... menyesuaikan kode ekspor saya untuk mencetak SQL dekat dengan itu ... kemudian jalankan sisipan 5 - 10 sql di sekitar masalah sql dan berhasil menentukan satu masalah, melihat string yang terlalu panjang, menambah ukuran kolom itu dan kemudian file impor besar berjalan tanpa masalah.

Sedikit peretasan dan solusi, tetapi ketika Anda pergi dengan pilihan yang sangat sedikit Anda melakukan apa yang Anda bisa.

Shaakir
sumber
2

Ya, saya juga menghadapi masalah seperti ini.

REMARKS VARCHAR(500)
to
REMARKS VARCHAR(1000)

Di sini, saya telah mengubah REMARKS yang diajukan dari 500 menjadi 1000

Thivan Mydeen
sumber
2

Saya akan menambahkan satu kemungkinan penyebab lain dari kesalahan ini hanya karena tidak ada yang menyebutkannya dan mungkin membantu beberapa orang di masa depan (karena OP telah menemukan jawabannya). Jika tabel yang Anda masukkan memiliki pemicu, bisa jadi pemicu menghasilkan kesalahan. Saya telah melihat ini terjadi ketika definisi bidang tabel diubah, tetapi tabel audit tidak.

HLGEM
sumber
2

Yap - "satu liter ke dalam panci setengah liter tidak akan pergi". Saya tidak beruntung (dengan alasan apa pun) dengan berbagai SP yang disarankan orang, TAPI selama dua tabel dalam DB yang sama (atau Anda dapat memasukkannya ke dalam DB yang sama), Anda dapat menggunakan INFORMATION_SCHEMA. COLUMNS untuk menemukan bidang yang salah, dengan demikian:

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

Ini akan memungkinkan Anda menggulir ke atas dan ke bawah, membandingkan panjang bidang saat Anda pergi. Bagian yang dikomentari membuat Anda melihat (setelah tidak dicommentasikan, jelas) jika ada ketidakcocokan tipe data, atau secara khusus menunjukkan yang berbeda dalam panjang bidang - karena saya terlalu malas untuk menggulir - hanya perlu diketahui bahwa semuanya didasarkan pada sumber. nama kolom yang cocok dengan target.

Kevin Anderson
sumber
Saya akan menulis sesuatu seperti ini tetapi Anda membuatnya mudah. sangat berguna dan bekerja seperti pesona. Saya bisa menggunakannya untuk membandingkan tabel dengan 90 kolom dan dua di antaranya langsung melompat keluar. Terima kasih!
Joy Walker
1

Saya menggunakan string kosong '' pada pembuatan tabel dan kemudian menerima kesalahan 'Msg 8152, String atau data biner akan terpotong' pada pembaruan berikutnya. Ini terjadi karena nilai pembaruan yang mengandung 6 karakter dan lebih besar dari definisi kolom yang diantisipasi. Saya menggunakan "SPACE" untuk mengatasi ini hanya karena saya tahu saya akan memperbarui secara massal setelah pembuatan data awal yaitu kolom tidak akan tetap kosong lama.

SO BIG CAVEAT DI SINI: Ini bukan solusi yang sangat licin tetapi berguna dalam kasus di mana Anda mengumpulkan satu set data misalnya untuk permintaan intelijen satu kali di mana Anda membuat tabel untuk penggalian data, menerapkan beberapa pemrosesan / interpretasi massal dan menyimpan sebelum dan sesudah hasil untuk perbandingan / penambangan nanti. Ini adalah kejadian yang sering terjadi dalam pekerjaan saya.

Anda awalnya dapat mengisi menggunakan kata kunci SPACE yaitu

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

Pembaruan berikutnya untuk "nama_kolom" dari 10 karakter atau kurang (pengganti yang berlaku) kemudian akan diizinkan tanpa menyebabkan kesalahan truncate. Sekali lagi, saya hanya akan menggunakan ini dalam skenario yang mirip dengan yang dijelaskan dalam peringatan saya.

Hilary
sumber
1

Saya telah membangun prosedur tersimpan yang menganalisis tabel sumber atau kueri dengan beberapa karakteristik per kolom di antaranya panjang minimum (min_len) dan panjang maksimum (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

Saya menyimpan prosedur ini di database master sehingga saya bisa menggunakannya di setiap database seperti:

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

Dan hasilnya adalah:

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,

Christiaan Westerbeek
sumber
Catatan: Anda tidak harus menggunakan sp_awalan untuk prosedur tersimpan Anda. Microsoft telah memesan awalan itu untuk penggunaannya sendiri (lihat Prosedur Penamaan yang Disimpan ) , dan Anda memang menghadapi risiko bentrokan nama suatu saat nanti. Ini juga buruk untuk kinerja prosedur tersimpan Anda . Yang terbaik adalah hanya menghindari sp_dan menggunakan sesuatu yang lain sebagai awalan - atau tidak ada awalan sama sekali!
marc_s
1

Saya menulis prosedur penyimpanan yang berguna untuk membantu mengidentifikasi dan menyelesaikan masalah pemotongan teks (String atau data biner akan terpotong) ketika pernyataan INSERT SELECT digunakan. Ini membandingkan bidang CHAR, VARCHAR, NCHAR DAN NVARCHAR saja dan mengembalikan bidang evaluasi dengan bidang jika kemungkinan penyebab kesalahan.

EXEC dbo.GetFieldStringTruncate SourceTableName, TargetTableName

Prosedur tersimpan ini berorientasi pada masalah pemotongan teks ketika pernyataan INSERT SELECT dibuat.

Operasi prosedur tersimpan ini tergantung pada pengguna yang sebelumnya mengidentifikasi pernyataan INSERT dengan masalah. Kemudian memasukkan data sumber ke tabel sementara global. Pernyataan SELECT INTO direkomendasikan.

Anda harus menggunakan nama yang sama dari bidang tabel tujuan di alias setiap bidang pernyataan SELECT.

KODE FUNGSI:

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

Untuk saat ini hanya mendukung tipe data CHAR, VARCHAR, NCHAR dan NVARCHAR . Anda dapat menemukan versi terakhir kode ini di tautan berikutnya di bawah ini dan kami saling membantu untuk memperbaikinya. GetFieldStringTruncate.sql

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

JotaPardo
sumber
1

Jika Anda menggunakan SQL Server 2016-2017: untuk memperbaikinya, aktifkan jejak bendera 460

DBCC TRACEON(460, 1);
GO

dan pastikan Anda mematikannya setelah:

DBCC TRACEOFF(460, 1);
GO

sumber

nimajv
sumber
0

ini juga dapat terjadi ketika Anda tidak memiliki izin yang memadai

Biscuit128
sumber
2
Betulkah? Kesalahan 'String atau data biner aktual akan terpotong'? Itu sepertinya kesalahan yang sangat aneh jika Anda tidak memiliki izin. Apakah ada izin yang menghentikan Anda menulis lebih dari jumlah data tertentu ?? (Saya tertarik karena saya ingin memeriksa ukuran bidang secara otomatis ketika saya mendapatkan kesalahan ini - jadi jika itu terjadi karena alasan lain yang sangat menarik!)
Ian Grainger
0

Saya punya masalah serupa. Saya menyalin data dari satu tabel ke tabel yang sama dalam segala hal kecuali nama.

Akhirnya saya membuang tabel sumber ke tabel temp menggunakan pernyataan SELECT INTO.

SELECT *
INTO TEMP_TABLE
FROM SOURCE_TABLE;

Saya membandingkan skema tabel sumber dengan tabel temp. Saya menemukan salah satu kolom adalah varchar(4000)ketika saya mengharapkanvarchar(250) .

UPDATE: Masalah varchar (4000) dapat dijelaskan di sini jika Anda tertarik:

Untuk Nvarchar (Max) saya hanya mendapatkan 4000 karakter di TSQL?

Semoga ini membantu.

bank warren
sumber
0

Kesalahan ini dilemparkan ketika kolom tabel memberi batasan [kebanyakan panjang]. . Misalnya, jika skema database untuk kolom myColumn adalah CHAR (2), maka ketika panggilan Anda dari aplikasi Anda untuk memasukkan nilai, Anda harus melewati String dengan panjang dua.

Kesalahan pada dasarnya mengatakannya; string dengan panjang tiga dan di atas tidak konsisten agar sesuai dengan batasan panjang yang ditentukan oleh skema database. Itu sebabnya SQL Server memperingatkan dan melempar kehilangan data / kesalahan pemotongan.

Yergalem
sumber
0

Silakan coba kode berikut:

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]
arnav
sumber