Làm cách nào để xác định (các) cột chịu trách nhiệm về Chuỗi String hoặc dữ liệu nhị phân sẽ bị cắt ngắn.


31

Tôi đang tạo một số truy vấn tự động với mã tôi đã viết để CHỌN từ cơ sở dữ liệu PG từ xa và chèn vào cơ sở dữ liệu SQL Server cục bộ. Tuy nhiên, một trong số họ đang tạo ra lỗi này:

[Microsoft] [Trình điều khiển máy chủ SQL ODBC] [Máy ​​chủ SQL] Dữ liệu chuỗi hoặc nhị phân sẽ bị cắt ngắn. (SQL-22001) [trạng thái là 22001 bây giờ 01000]

[Microsoft] [Trình điều khiển máy chủ SQL ODBC] [Máy ​​chủ SQL] Câu lệnh đã bị chấm dứt. (SQL-01000) tại. \ Insert.pl dòng 106.

Làm cách nào để tìm ra cột nào đang tạo ra lỗi đó và thiếu độ dài cho đầu vào? Có cách nào để làm điều này mà không cần phải đoán tất cả varchar?

Câu trả lời:


35

Không, nó không được ghi lại ở bất cứ đâu. Đi bỏ phiếu và nêu trường hợp kinh doanh của bạn; đây là một trong danh sách dài những điều cần được sửa trong SQL Server.

Điều này đã được yêu cầu nhiều năm trước trên Connect (có thể là lần đầu tiên trong khung thời gian SQL Server 2000 hoặc 2005), sau đó một lần nữa trên hệ thống phản hồi mới:

Và bây giờ, nó đã được phân phối, trong SQL Server 2019 , SQL Server 2017 CU12 và sẽ xuất hiện trong SQL Server 2016 SP2 CU trong tương lai.

Trong CTP công khai đầu tiên của SQL Server 2019, nó chỉ xuất hiện dưới cờ theo dõi 460. Điều này nghe có vẻ bí mật, nhưng nó đã được xuất bản trong whitepaper của Microsoft này . Đây sẽ là hành vi mặc định (không yêu cầu cờ theo dõi) trong tương lai, mặc dù bạn sẽ có thể kiểm soát điều này thông qua cấu hình phạm vi cơ sở dữ liệu mới VERBOSE_TRUNCATION_WARNINGS.

Đây là một ví dụ:

USE tempdb;
GO
CREATE TABLE dbo.x(a char(1));

INSERT dbo.x(a) VALUES('foo');
GO

Kết quả trong tất cả các phiên bản được hỗ trợ trước SQL Server 2019:

Msg 8152, Cấp 16, Trạng thái 30,
Chuỗi dòng 5 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.

Bây giờ, trên SQL Server 2019 CTPs, với cờ theo dõi được bật:

DBCC TRACEON(460);
GO

INSERT dbo.x(a) VALUES('foo');
GO
DROP TABLE dbo.x;
DBCC TRACEOFF(460);

Kết quả hiển thị bảng, cột và giá trị ( cắt ngắn , không đầy đủ ):

Msg 2628, Cấp 16, Trạng thái 1,
Chuỗi 11 hoặc dữ liệu nhị phân sẽ bị cắt ngắn trong bảng 'tempdb.dbo.x', cột 'a'. Giá trị rút gọn: 'f'.
Các tuyên bố này đã bị chấm dứt.

Cho đến khi bạn có thể bỏ mọi thứ và nâng cấp lên SQL Server 2019 hoặc chuyển sang Cơ sở dữ liệu SQL Azure, bạn có thể thay đổi mã "tự động" của mình để thực sự lấy max_length từ đó sys.columns, cùng với tên mà bạn phải đặt ở đó, sau đó áp dụng LEFT(column, max_length)hoặc dù tương đương với PG là gì. Hoặc, vì điều đó chỉ có nghĩa là bạn sẽ âm thầm mất dữ liệu, hãy tìm ra những cột nào không khớp và sửa các cột đích để chúng khớp với tất cả dữ liệu từ nguồn. Cấp quyền truy cập siêu dữ liệu cho cả hai hệ thống và thực tế là bạn đã viết một truy vấn phải tự động khớp nguồn -> cột đích (nếu không thì lỗi này khó có thể là vấn đề lớn nhất của bạn), bạn không cần phải thực hiện bất kỳ hành động thô lỗ nào đoán ở tất cả.


2

Nếu bạn có quyền truy cập để chạy Trình hướng dẫn nhập và xuất SQL Server từ SQL Server Management Studio (bấm chuột phải vào cơ sở dữ liệu> Nhiệm vụ> Nhập dữ liệu ...), hãy tạo một tác vụ nhập từ Máy khách SQL bằng cách sử dụng truy vấn của bạn làm nguồn dữ liệu đến đích bàn.

Trước khi bạn chạy nhập, bạn có thể xem lại ánh xạ dữ liệu và nó sẽ cho bạn biết cột nào có loại trường không nhất quán. Và nếu bạn chạy tác vụ nhập, nó sẽ cho bạn biết cột nào không thể nhập.

Cảnh báo xác nhận mẫu:

Cảnh báo 0x802092a7: Nhiệm vụ luồng dữ liệu 1: Việc cắt xén có thể xảy ra do chèn dữ liệu từ cột luồng dữ liệu "NARRECT" với độ dài từ 316 đến cột cơ sở dữ liệu "NARRECT" với độ dài 60. (Trình hướng dẫn nhập và xuất máy chủ SQL)


1

Cuối cùng, tôi không thể tìm ra cách lấy thông tin cột mà không tự viết.

Thông báo lỗi này được tạo bởi DBD::ODBC, tuy nhiên bạn cũng có thể sử dụng sys.columns (max_length)(tôi chỉ không biết làm thế nào).

Tôi đã sử dụng mã như thế này trong danh sách cột của mình để có được danh sách các mảng có hai phần tử COLUMN_NAME, và MAX_LENGTH(được ghi lại trong DBIcolumn_info() ).

my @max_lengths = map [ @{$_->fetchall_arrayref->[0]}[3,6] ]
    , map $dbh_mssql->column_info('database', 'dbo', $dest_table, $_)
    , @col_mssql
;

Sau đó, tôi bắt gặp các ngoại lệ trên INSERTvà in ra một cái gì đó hữu ích. Trong ví dụ @$rownày là dữ liệu được gửi đếnsth->execute()

if ($@) {
        warn "$@\n";
        for ( my $idx=0; $idx <= $#{ $row }; $idx++ ) {
                Dumper {
                        maxlength => $max_lengths[$idx]->[1]
                        , name    => $max_lengths[$idx]->[0]
                        , length  => length( $row->[$idx] )
                        , content => $row->[$idx]
                };
        }
        die;
}

Ngoài ra, vui lòng bỏ phiếu và đưa ra câu trả lời khác


2
Tôi đã không đặt bất kỳ mã tham chiếu nào sys.columnsvì tôi hoàn toàn không biết bạn đang sử dụng mã nào để "tự động" tạo các truy vấn của bạn. Thực sự không có quá nhiều phức tạp tôi có thể đoán về việc kết hợp vào mã của bạn hơn SELECT name, object_id, max_length FROM sys.columns;. Vì bạn đã có mã tự động phải thực hiện điều này - hoặc một cái gì đó rất giống nó - tôi không nghĩ rằng một ví dụ là cần thiết.
Aaron Bertrand

Tôi không chắc cách thức sys.columnshoạt động với hai cột giống nhau name. Ngoài ra, tôi nhận được điều làm việc bằng thư viện hơn là sys, tại sao tôi lại coi đó là câu trả lời được chọn? Microsoft SQL doesn't have x, do y insteadlà một đóng góp hợp lệ, nhưng nếu bạn ykém hơn tôi y, tôi sẽ làm điều gì đó khác biệt và đánh dấu nó là đã chọn.
Evan Carroll

1
Về cơ bản, câu hỏi của bạn là làm thế nào để tôi tìm ra cột nào tạo ra lỗi (có lẽ là để bạn có thể khắc phục một điểm đó, thay vì tái thiết kế giải pháp). Tôi đã nói với bạn nơi để tìm: sys.columns. Đó chính xác là nơi bạn nên tìm để so sánh độ dài cột nguồn của bạn với độ dài cột đích. Làm thế nào bạn làm điều đó là tùy thuộc vào bạn. Tôi không nói cho bạn biết cách sửa mã của bạn, vì tôi hoàn toàn không biết làm thế nào truy vấn tự động của bạn được tạo ở nơi đầu tiên, vì vậy, như tôi đã nói, không biết làm thế nào để thêm các xác định độ dài cho bất kỳ truy vấn nào bạn đã có .
Aaron Bertrand

1

Cuối cùng, Microsoft đã quyết định cung cấp thông tin có ý nghĩa để String or binary would be truncatedbắt đầu từ SQL Server 2016 SP2 CU, SQL Server 2017 CU12 và trong SQL Server 2019.

Thông tin hiện bao gồm cả cột bảng vi phạm (tên đủ điều kiện) và giá trị vi phạm (bị cắt ở 120 ký tự):

Msg 2628, Cấp 16, Trạng thái 1, Dòng x Chuỗi hoặc dữ liệu nhị phân sẽ bị cắt ngắn trong bảng 'TheDb .Schema .Table', cột 'TheColumn'. Giá trị rút gọn: '...'. Các tuyên bố này đã bị chấm dứt.

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.