9

Tôi đang cố gắng sử dụng CONTEXT_INFO để chuyển mã người dùng từ quy trình được lưu trữ vào trình kích hoạt DELETE cho mục đích kiểm tra bảng.Truyền CONTEXT_INFO đến varchar và độ dài kết quả

Tất cả đều hoạt động tốt, tuy nhiên tôi nhận thấy rằng độ dài của mã người dùng được lưu trong bảng kiểm tra không chính xác.

Đi kịch bản này là một ví dụ ...

declare @userCode varchar(50) 
set @userCode = 'TestUser' 

declare @binary_userCode varbinary(128) 
set @binary_userCode = cast(@userCode as varbinary(128)) 
set CONTEXT_INFO @binary_userCode 

declare @temp_userCode varchar(50) 
set @temp_userCode = (select cast(CONTEXT_INFO() as varchar(50))) 

--set @temp_userCode = rtrim(ltrim(@temp_userCode)) 

select @userCode, len(@userCode), @temp_userCode, len(@temp_userCode) 

set CONTEXT_INFO 0x 

Kết quả:

len (@userCode) = 8

len (@temp_userCode) = 50

Tại sao biến số @temp_userCode quay lại với chiều dài là 50 và làm cách nào tôi có thể cắt nó về độ dài ban đầu để lưu trữ nó ctly?

Thông tin thêm:

Chạy SQL Server 2005, tuy nhiên giải pháp cần phải làm việc trong tất cả các phiên bản 2005 trở đi.

Trả lời

6

Khi giao cho CONTEXT_INFO nó được đệm với byte null 0x00-128 byte chiều dài và trở thành 0x5465737455736572000000...

Bạn có thể sử dụng

REPLACE(CAST(CONTEXT_INFO() AS varchar(128)) COLLATE Latin1_General_100_BIN , 
     0x00, 
     '') 
+1

này tuy nhiên việc tôi đã phải thay đổi collation để SQL_Latin1_General_CP437_BIN. Điều này được dựa trên thử nghiệm và lỗi tuy nhiên mà không để lại cho tôi với sự tự tin nhiều. Làm thế nào tôi có thể làm rõ collation tôi nên sử dụng? –

+0

@Poz - Bạn không nói rõ phiên bản SQL Server trong câu hỏi của mình. Nếu trước năm 2008, các collations '100' sẽ không có sẵn. –

+0

Xin lỗi. Tôi đang chạy năm 2005, tuy nhiên nó cần phải phù hợp với tất cả các phiên bản trên. –

3

Nó được đệm bằng CHAR(0). Hãy thử:

set @temp_userCode = REPLACE(@temp_userCode COLLATE Latin1_General_BIN, CHAR(0), ''); 

(EDIT: thêm một COLLATE khoản rõ ràng, mặc dù bây giờ tôi cảm thấy như tôi đang ăn cắp từ Martin.)

+0

+1 Tôi sử dụng mệnh đề đối chiếu và đối chiếu rõ ràng trong câu trả lời của mình [vì vấn đề này] (https://connect.microsoft.com/SQLServer/feedback/details/708179/indefinite-hang-with-replace-statement-on -varbinary-max) nhưng nó chỉ xuất hiện cho 'varbinary (max)' anyway. –

+0

Giải pháp này không hiệu quả đối với tôi, độ dài vẫn là 50. Do SQL 2005 có lẽ? –

+0

Thực ra tôi đã tìm thấy hai cái một chạy 9.00.3042, cái khác 9.00.4211, và nó hoạt động - cả hai độ dài hiển thị 8. ​​ –

0

Replace sẽ thất bại một cách ngẫu nhiên trên cài đặt khác nhau của SQL server unless you specify the collation:

REPLACE(CAST(CONTEXT_INFO() AS varchar(128)) COLLATE Latin1_General_100_BIN , 0x00, '') 

SQL server có hai hành vi khác nhau, tùy thuộc vào cách nó được cài đặt:

  • Thay thế thành công khi sử dụng phép đối chiếu SQL.
  • Thay thế không thành công khi Windows collation được sử dụng.

Hành vi này đã được gửi tới Microsoft gần hơn 7 năm về trước:

Q: Khi cố gắng một thay thế một ký tự NUL với replace(), công trình này là giá trị đã một SQL collation, nhưng không phải là Windows collation.

A: Điều này là do thực tế là 0x0000 là một ký tự không xác định trong Windows collations. Tất cả các ký tự không xác định được bỏ qua trong khi so sánh, sắp xếp, và đối sánh mẫu. Vì vậy, tìm kiếm 'a' + char (0) thực sự đang tìm kiếm ‘a’ và tìm kiếm char (0) là tương đương với chuỗi rỗng.

Cách xử lý nhân vật không xác định là một chút khó hiểu, nhưng đây là cách rằng Windows định nghĩa để sắp xếp chúng, và SQL Server phù hợp với Windows API chung.

Trong đối chiếu SQL, không có khái niệm của ký tự không xác định. Mỗi mã được chỉ định trọng số, đó là lý do tại sao chúng tôi không thấy sự cố ở đó.

2

Hãy thử điều này, nó làm việc cho tôi trên SQL Server 2005:

select cast(substring(CONTEXT_INFO(), 1, charindex(0x00, CONTEXT_INFO())-1) as varchar(128)); 

Không collations lộn xộn để xem xét :-)