Chuỗi máy chủ SQL hoặc dữ liệu nhị phân sẽ bị cắt ngắn


149

Tôi đang tham gia vào một dự án di chuyển dữ liệu. Tôi gặp lỗi sau khi cố gắng chèn dữ liệu từ một bảng vào một bảng khác (SQL Server 2005):

Msg 8152, Cấp 16, Trạng thái 13,
Chuỗi dòng 1 hoặc dữ liệu nhị phân sẽ bị cắt ngắn.

Các cột dữ liệu nguồn khớp với kiểu dữ liệu và nằm trong định nghĩa độ dài của các cột của bảng đích nên tôi không biết điều gì có thể gây ra lỗi này.


Bạn có phiền khi đăng một số mã và thông tin về mỗi bảng không?
Kevin Mansel

Các bảng đều khá lớn - vì vậy tôi sẽ chỉ đăng một phần của các định nghĩa bảng có liên quan và mã - có được chấp nhận không?
Jim Evans

Các định nghĩa bảng và mã sẽ là tuyệt vời.
IAmTimCorey

1
Lần trước khi tôi gặp vấn đề này, đó là với trình kích hoạt, Trình kích hoạt đã chèn dữ liệu vào bảng kiểm toán. đáng để kiểm tra kích hoạt là tốt.
Sachin Vishwakarma

Câu trả lời:


185

Bạn sẽ cần đăng định nghĩa bảng cho bảng nguồn và bảng đích để chúng tôi tìm ra vấn đề ở đâu nhưng điểm mấu chốt là một trong các cột của bạn trong bảng nguồn lớn hơn cột đích của bạn . Có thể là bạn đang thay đổi định dạng theo cách mà bạn không biết. Mô hình cơ sở dữ liệu mà bạn đang chuyển đến rất quan trọng trong việc tìm ra điều đó.


1
Theo nhận xét của tôi ở trên - sắp ra mắt :)
Jim Evans

3
Tôi đã phải đối mặt với cùng một vấn đề và phải so sánh tất cả các loại cột và kích cỡ của cả hai bảng để khắc phục sự cố.
Aziz Shaikh

1
Sau khi hoàn thành việc thu thập các định nghĩa bảng một phần và sau đó lấy mã sproc của tôi, cột vi phạm nhảy ra khỏi tôi như một tia sét ... Cảm ơn tất cả về đầu vào của bạn.
Jim Evans

Tôi không thể nói với bạn bao nhiêu lần tôi đã làm điều tương tự. Vui mừng bạn đã có thể giải quyết vấn đề của bạn.
IAmTimCorey

Tôi đã đánh dấu câu trả lời đầu tiên của bạn là câu trả lời vì đó là điều khiến tôi tìm thấy câu trả lời :)
Jim Evans

86

Như những người khác đã nói, một trong các kiểu dữ liệu cột của bạn trong bảng nguồn lớn hơn các cột đích của bạn.

Một giải pháp đơn giản là chỉ cần tắt cảnh báo và cho phép cắt ngắn diễn ra. Vì vậy, nếu bạn nhận được lỗi này nhưng bạn chắc chắn rằng dữ liệu trong cơ sở dữ liệu / bảng cũ của bạn sẽ bị cắt ngắn (cắt theo kích thước), bạn có thể chỉ cần làm như sau;

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

Như trên, luôn nhớ bật lại cảnh báo sau đó. Tôi hi vọng cái này giúp được.


1
Bạn đã tiết kiệm cho tôi một số giờ làm việc! Lấy tất cả lời cảm ơn của tôi!
Urasquirrel

Tương tự như vậy ở đây. Đôi khi tôi phải lưu trữ dữ liệu vào một bảng từ một dịch vụ web, trong đó kiểu dữ liệu chỉ được định nghĩa là một "chuỗi". Tôi không thể biến mọi thứ thành Varchar (MAX) ...
Curt

61

Vấn đề khá đơn giản: một hoặc nhiều cột trong truy vấn nguồn chứa dữ liệu vượt quá độ dài của cột đích. Một giải pháp đơn giản sẽ là lấy truy vấn nguồn của bạn và thực hiện Max(Len( source col ))trên mỗi cột. I E,

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

Sau đó so sánh các độ dài đó với độ dài loại dữ liệu trong bảng đích của bạn. Ít nhất một, vượt quá chiều dài cột đích của nó.

Nếu bạn hoàn toàn tích cực rằng đây không phải là trường hợp và không quan tâm nếu đó không phải là trường hợp đó, thì một giải pháp khác là buộc các cột truy vấn nguồn đến độ dài đích của chúng (sẽ cắt bớt bất kỳ dữ liệu nào quá dài):

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

Quá trình hàng ngày của tôi bắt đầu phá vỡ với lỗi này. Dữ liệu tôi chèn luôn đủ ngắn để vừa và tôi luôn có các hàng khác (trong Bảng tôi được kéo từ) với các chuỗi quá khổ không bao giờ được chèn vì bộ lọc của tôi. Có thể một Chỉ mục đã được xây dựng lại hoặc Số liệu thống kê được cập nhật, nhưng con ma trong máy đã quyết định một ngày nào đó nó không thích kế hoạch truy vấn nữa, bởi vì nó đã đưa nó xuống một con đường nơi dữ liệu (quá rộng) "có thể" được chèn trước khi nó được lọc bởi Vị ngữ trong mệnh đề. Để giải quyết vấn đề này, tôi đã sử dụng LEFT () thay vì CAST - chỉ cần nhập ít ký tự hơn.
MikeTeeVee

1
Cảm ơn Thomas, điều này thật lạ, thậm chí tôi không có bất kỳ dữ liệu nào quá dài, tôi vẫn phải chuyển nó sang kích thước cột đích mới, ngay khi tôi làm việc đó.
Michelle

15

SQL Server 2019 cuối cùng sẽ trả về thông báo lỗi có ý nghĩa hơn.

Dữ liệu nhị phân hoặc chuỗi sẽ bị cắt bớt => cải tiến thông báo lỗi

nếu bạn có lỗi đó (trong sản xuất), không rõ ràng để xem cột hoặc hàng lỗi này xuất phát từ đâu và làm thế nào để xác định chính xác lỗi đó.

Để kích hoạt hành vi mới, bạn cần sử dụng DBCC TRACEON(460). Văn bản lỗi mới từ sys.messages:

SELECT * FROM sys.messages WHERE message_id = 2628

2628 - Dữ liệu chuỗi hoặc nhị phân sẽ bị cắt ngắn trong bảng '%. * Ls', cột '%. * Ls'. Giá trị rút gọn: '%. * Ls'.

Dữ liệu chuỗi hoặc nhị phân sẽ bị cắt ngắn: thay thế lỗi khét tiếng 8152

Thông báo mới này cũng được nhập vào SQL Server 2017 CU12 (và trong SQL Server 2016 SP2 CU sắp tới), nhưng không phải theo mặc định. Bạn cần bật cờ theo dõi 460 để thay thế thông báo ID 8152 bằng 2628, ở cấp độ phiên hoặc máy chủ.

Lưu ý rằng hiện tại, ngay cả trong SQL Server 2019 CTP 2.0, cờ theo dõi tương tự 460 cần được bật. Trong bản phát hành SQL Server 2019 trong tương lai, thông báo 2628 sẽ thay thế thông báo 8152 theo mặc định.


SQL Server 2017 CU12 cũng hỗ trợ tính năng này.

Cải thiện: Tùy chọn thay thế cho thông báo "Chuỗi hoặc dữ liệu nhị phân sẽ bị cắt ngắn" với thông tin mở rộng trong SQL Server 2017

Bản cập nhật SQL Server 2017 này giới thiệu một thông báo tùy chọn chứa thông tin ngữ cảnh bổ sung sau.

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 tin nhắn mới là 2628. Thông báo này thay thế tin nhắn 8152 trong bất kỳ đầu ra lỗi nào nếu cờ theo dõi 460 được bật.

db <> fiddle demo


THAY ĐỔI CẤU HÌNH XÁC NHẬN

ĐỘNG TỪ_TRUNCATION_WARNINGS = {ON | TẮT }

ÁP DỤNG CHO: Máy chủ SQL (Bắt đầu với SQL Server 2019 (15.x)) và Cơ sở dữ liệu SQL Azure

Cho phép bạn bật hoặc tắt Chuỗi mới hoặc dữ liệu nhị phân sẽ bị cắt ngắn thông báo lỗi. SQL Server 2019 (15.x) giới thiệu một thông báo lỗi mới, cụ thể hơn (2628) cho kịch bản này:

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

Khi được đặt thành BẬT dưới mức tương thích cơ sở dữ liệu 150, các lỗi cắt xén đưa ra thông báo lỗi mới 2628 để cung cấp thêm ngữ cảnh và đơn giản hóa quy trình xử lý sự cố.

Khi được đặt thành TẮT theo mức độ tương thích cơ sở dữ liệu 150, các lỗi cắt ngắn sẽ đưa ra thông báo lỗi trước đó là 8152.

Đối với mức độ tương thích cơ sở dữ liệu 140 hoặc thấp hơn, thông báo lỗi 2628 vẫn là thông báo lỗi chọn tham gia yêu cầu cờ theo dõi 460 được bật và cấu hình phạm vi cơ sở dữ liệu này không có hiệu lực.


1
Điều này hiện cũng có sẵn cho SQL Azure: azure.microsoft.com/en-gb/updates/ Khăn
Ian Kemp

7

Một lý do tiềm năng khác cho điều này là nếu bạn có thiết lập giá trị mặc định cho một cột vượt quá độ dài của cột. Có vẻ như ai đó mập ngón tay một cột có chiều dài 5 nhưng giá trị mặc định vượt quá chiều dài 5. Điều này khiến tôi phát điên khi tôi cố gắng hiểu tại sao nó không hoạt động trên bất kỳ chèn nào, ngay cả khi tất cả những gì tôi đang chèn là một cột duy nhất có số nguyên là 1. Bởi vì giá trị mặc định trên lược đồ bảng có vi phạm giá trị mặc định đó, nó làm rối tung tất cả - điều mà tôi đoán đưa chúng ta đến bài học đã học - tránh có các bảng có giá trị mặc định trong lược đồ. :)


1
Tôi không nghĩ tránh các giá trị mặc định là một giải pháp tốt. Giá trị mặc định rất hữu ích. Tôi sẽ không giải quyết "sự cố" cơ sở dữ liệu do lỗi chính tả gây ra bằng cách xóa các giá trị mặc định ...
Jacob H

3

Đối với những người khác, cũng kiểm tra thủ tục lưu trữ của bạn . Trong trường hợp của tôi trong thủ tục được lưu trữ, CustomSearchtôi đã vô tình tuyên bố không đủ độ dài cho cột của mình, vì vậy khi tôi nhập một dữ liệu lớn, tôi đã nhận được lỗi đó mặc dù tôi có một độ dài lớn trên cơ sở dữ liệu của mình. Tôi vừa thay đổi độ dài của cột trong tìm kiếm tùy chỉnh của tôi, lỗi sẽ biến mất. Đây chỉ là cho lời nhắc nhở. Cảm ơn.


đây chính xác là những gì xảy ra với tôi các bảng nguồn / đích khớp rất tốt nhưng Proc được lưu trữ có #table được xác định với độ dài ngắn hơn và nó đã thất bại ở đó. Cảm ơn bạn!
Joy Walker

3

Đây có thể là một lỗi đầy thách thức. Dưới đây là một số ghi chú được lấy từ https://connect.microsoft.com/SQLServer/feedback/details/339410/ tìm kiếm bình luận của AmirCharania.

Tôi đã điều chỉnh câu trả lời do AmirCharania đưa ra cho dữ liệu được chọn vào một bảng thực tế, thay vì dữ liệu tạm thời. Đầu tiên chọn tập dữ liệu của bạn vào bảng phát triển, sau đó chạy như sau:

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)

Có vẻ như MS đã tắt trang Connect. Liên kết mới cho vấn đề này là: feedback.azure.com/forums/908035-sql-server/suggestions/ gợi ... vẫn được đánh dấu là không có kế hoạch. Tôi nghĩ rằng bình luận mà bạn đề cập đến đã bị cắt xén (trớ trêu thay) khi di chuyển xảy ra.
SWalters - Phục hồi Monica

Thật thú vị, vấn đề đã được mở lại dưới một tiêu đề hơi khác: feedback.azure.com/forums/908035-sql-server/suggestions/ trộm và nó đã được liệt kê là "Đang xem xét", vì vậy vẫn còn hy vọng.
SWalters - Phục hồi Monica

3

Đây là một câu trả lời hơi khác nhau. Tên và độ dài cột của bạn đều có thể khớp, nhưng có lẽ bạn đang chỉ định các cột theo thứ tự sai trong câu lệnh CHỌN của bạn. Giả sử bảngX và bảngY có các cột có cùng tên, nhưng theo thứ tự khác nhau


2

Tôi đã gặp vấn đề này ngày hôm nay, và trong quá trình tìm kiếm câu trả lời cho thông báo lỗi thông tin tối thiểu này, tôi cũng tìm thấy liên kết này:

https://connect.microsoft.com

Vì vậy, có vẻ như microsoft không có kế hoạch mở rộng thông báo lỗi bất cứ lúc nào sớm.

Vì vậy, tôi đã chuyển sang các phương tiện khác.

Tôi đã sao chép các lỗi để excel:

(1 hàng bị ảnh hưởng)

(1 hàng bị ảnh hưởng)

(1 hàng bị ảnh hưởng) Msg 8152, Cấp 16, Trạng thái 14, Chuỗi 13 hoặc dữ liệu nhị phân sẽ bị cắt ngắn. Các tuyên bố này đã bị chấm dứt.

(1 hàng bị ảnh hưởng)

đã đếm số lượng hàng trong excel, phải đóng gần bộ đếm hồ sơ gây ra sự cố ... đã điều chỉnh mã xuất của tôi để in ra SQL gần với nó ... sau đó chạy 5 - 10 sql chèn xung quanh vấn đề sql và quản lý để xác định chính xác vấn đề một, xem chuỗi quá dài, tăng kích thước của cột đó và sau đó tệp nhập lớn chạy không có vấn đề.

Một chút hack và một cách giải quyết, nhưng khi bạn rời đi với rất ít sự lựa chọn, bạn sẽ làm những gì bạn có thể.


2

Vâng, tôi cũng phải đối mặt với những vấn đề này.

REMARKS VARCHAR(500)
to
REMARKS VARCHAR(1000)

Ở đây, tôi đã thay đổi thời gian nộp hồ sơ từ 500 thành 1000


2

Tôi sẽ thêm một nguyên nhân có thể khác của lỗi này chỉ vì không ai đề cập đến nó và nó có thể giúp một số người trong tương lai (vì OP đã tìm thấy câu trả lời của anh ấy). Nếu bảng bạn đang chèn vào có các trình kích hoạt, thì đó có thể là trình kích hoạt đang tạo ra lỗi. Tôi đã thấy điều này xảy ra khi định nghĩa trường bảng được thay đổi, nhưng bảng kiểm toán thì không.


2

Đúng - "một pint vào nồi nửa pint sẽ không đi". Tôi đã không gặp nhiều may mắn (vì bất kỳ lý do gì) với các SP khác nhau mà mọi người đã đề xuất, NHƯNG miễn là hai bảng nằm trong cùng một DB (hoặc bạn có thể đưa chúng vào cùng một DB), bạn có thể sử dụng Information_SCHema. COLUMNS để xác định vị trí (các) trường errant, do đó:

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

Điều này sẽ cho phép bạn cuộn lên và xuống, so sánh độ dài trường khi bạn đi. Các phần được nhận xét cho phép bạn xem (một khi không bị lỗi, rõ ràng) nếu có sự không phù hợp về kiểu dữ liệu, hoặc hiển thị cụ thể những phần khác nhau về độ dài trường - vì tôi quá lười để cuộn - chỉ cần lưu ý rằng toàn bộ nội dung được cung cấp trên nguồn tên cột khớp với tên của mục tiêu.


Tôi sẽ viết một cái gì đó như thế này nhưng bạn chỉ làm cho nó dễ dàng. rất tiện dụng và làm việc như một lá bùa. Tôi đã có thể sử dụng nó để so sánh một bảng với hơn 90 cột và hai trong số chúng nhảy ra ngay lập tức. Cảm ơn bạn!
Joy Walker

1

Tôi đã sử dụng chuỗi rỗng '' khi tạo bảng và sau đó nhận được lỗi 'Msg 8152, Chuỗi hoặc dữ liệu nhị phân sẽ bị cắt ngắn' trong lần cập nhật tiếp theo. Điều này đã xảy ra do giá trị cập nhật chứa 6 ký tự và lớn hơn định nghĩa cột dự đoán. Tôi đã sử dụng "KHÔNG GIAN" để giải quyết vấn đề này chỉ vì tôi biết rằng tôi sẽ cập nhật hàng loạt sau khi tạo dữ liệu ban đầu, tức là cột sẽ không còn trống lâu.

RẤT LỚN Ở ĐÂY: Đây không phải là một giải pháp đặc biệt khéo léo nhưng rất hữu ích trong trường hợp bạn tập hợp một bộ dữ liệu, ví dụ như đối với các yêu cầu thông minh một lần trong đó bạn đang tạo một bảng để khai thác dữ liệu, áp dụng một số xử lý / giải thích hàng loạt và lưu trữ trước và sau kết quả để so sánh / khai thác sau này. Đây là một sự xuất hiện thường xuyên trong dòng công việc của tôi.

Ban đầu, bạn có thể nhập bằng cách sử dụng từ khóa SPACE

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

Các cập nhật tiếp theo cho "cột_name" từ 10 ký tự trở xuống (thay thế nếu có) sẽ được cho phép mà không gây ra lỗi cắt ngắn. Một lần nữa, tôi sẽ chỉ sử dụng điều này trong các tình huống tương tự như mô tả trong cảnh báo của tôi.


1

Tôi đã xây dựng một quy trình được lưu trữ để phân tích bảng nguồn hoặc truy vấn với một số đặc điểm cho mỗi cột trong đó độ dài tối thiểu (min_len) và độ dài tối đa (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

Tôi lưu trữ thủ tục này trong cơ sở dữ liệu chủ để tôi có thể sử dụng nó trong mọi cơ sở dữ liệu như vậy:

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

Và đầu ra là:

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,


Lưu ý bên: bạn không nên sử dụng sp_tiền tố cho các thủ tục được lưu trữ của bạn. Microsoft đã bảo lưu tiền tố đó cho mục đích sử dụng riêng của mình (xem Đặt tên các thủ tục được lưu trữ ) và bạn sẽ gặp rủi ro về một cuộc đụng độ tên đôi khi trong tương lai. Nó cũng không tốt cho hiệu suất thủ tục được lưu trữ của bạn . Tốt nhất là chỉ cần tránh sp_và sử dụng một cái gì đó khác làm tiền tố - hoặc không có tiền tố nào cả!
marc_s

1

Tôi đã viết một thủ tục lưu trữ hữu ích để giúp xác định và giải quyết vấn đề cắt ngắn văn bản (Chuỗi hoặc dữ liệu nhị phân sẽ bị cắt ngắn) khi sử dụng câu lệnh INSERT SELECT. Nó chỉ so sánh các trường CHAR, VARCHAR, NCHAR VÀ NVARCHAR và trả về một trường đánh giá theo trường trong trường hợp có thể là nguyên nhân gây ra lỗi.

EXEC dbo.GetFieldStringTruncate SourceTableName, TargetTableName

Quy trình được lưu trữ này được định hướng cho vấn đề cắt ngắn văn bản khi câu lệnh INSERT SELECT được tạo.

Hoạt động của thủ tục được lưu trữ này phụ thuộc vào người dùng trước đó xác định câu lệnh INSERT có vấn đề. Sau đó chèn dữ liệu nguồn vào một bảng tạm thời toàn cầu. Câu lệnh CHỌN VÀO được khuyến nghị.

Bạn phải sử dụng cùng tên của trường của bảng đích trong bí danh của từng trường của câu lệnh SELECT.

MÃ CHỨC NĂNG:

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

Hiện tại chỉ hỗ trợ các loại dữ liệu CHAR, VARCHAR, NCHAR và NVARCHAR . Bạn có thể tìm thấy phiên bản cuối cùng của mã này trong liên kết tiếp theo bên dưới và chúng tôi giúp nhau cải thiện nó. GetFieldStringTruncate.sql

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


1

Nếu bạn đang sử dụng SQL Server 2016-2017: để khắc phục, hãy bật cờ theo dõi 460

DBCC TRACEON(460, 1);
GO

và đảm bảo bạn tắt nó sau:

DBCC TRACEOFF(460, 1);
GO

nguồn


0

Điều này cũng có thể xảy ra khi bạn không có quyền đầy đủ


2
Có thật không? Một lỗi 'Dữ liệu chuỗi hoặc nhị phân thực tế sẽ bị cắt ngắn'? Đó có vẻ là một lỗi rất lạ nếu bạn không có quyền. Có quyền nào ngăn bạn viết nhiều hơn một lượng dữ liệu nhất định không ?? (Tôi quan tâm vì tôi muốn tự động kiểm tra kích thước trường khi tôi gặp lỗi này - vì vậy nếu nó có thể xảy ra vì một số lý do khác thì rất thú vị!)
Ian Grainger

0

Tôi đã có một vấn đề tương tự. Tôi đã sao chép dữ liệu từ một bảng vào một bảng giống hệt nhau trong mọi thứ trừ tên.

Cuối cùng, tôi đã đổ bảng nguồn vào một bảng tạm thời bằng cách sử dụng câu lệnh CHỌN VÀO.

SELECT *
INTO TEMP_TABLE
FROM SOURCE_TABLE;

Tôi đã so sánh lược đồ của bảng nguồn với bảng tạm thời. Tôi tìm thấy một trong những cột là một varchar(4000)khi tôi đang mong đợi a varchar(250).

CẬP NHẬT: Vấn đề varchar (4000) có thể được giải thích ở đây trong trường hợp bạn quan tâm:

Đối với Nvarchar (Tối đa) tôi chỉ nhận được 4000 ký tự trong TSQL?

Hi vọng điêu nay co ich.


0

Lỗi này được đưa ra khi cột của bảng đặt ràng buộc [chủ yếu là chiều dài]. . Ví dụ: nếu lược đồ cơ sở dữ liệu cho cột myColumn là CHAR (2), thì khi cuộc gọi của bạn từ bất kỳ ứng dụng nào của bạn để chèn giá trị, bạn phải chuyển Chuỗi có độ dài hai.

Các lỗi cơ bản nói nó; chuỗi có độ dài từ ba trở lên không nhất quán để phù hợp với giới hạn độ dài được chỉ định bởi lược đồ cơ sở dữ liệu. Đó là lý do tại sao SQL Server cảnh báo và ném lỗi mất / cắt dữ liệu.


0

Vui lòng thử mã sau đây:

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]
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.