Sự cố mã hóa với cột VARCHAR của SQL Server được truy xuất trong Python


10

Gần đây, chúng tôi đã gặp sự cố với mã hóa liên quan đến một trường đang được lưu trữ dưới dạng varchar (120) trong SQL Server. Trong SSMS, varchar xuất hiện dưới dạng:

"Ai đã giết JonBen‚t?"

Tuy nhiên, khi nó được đưa vào trăn, nó xuất hiện như sau:

nhập mô tả hình ảnh ở đây

Tôi đã nghiên cứu điều này từ phía Python và không có gì lạ xảy ra. Lý thuyết của tôi là varchar trong SQL Server đang chấp nhận các ký tự UTF-8 đang hiển thị khác nhau trong python so với SSMS. Tôi không rành lắm về mã hóa trong SQL Server. Ai đó có thể vui lòng cho tôi biết như sau:

  • Có cách nào trong SSMS để xem mã hóa của varchar không? Chẳng hạn, xem \ x82 thay vì hiển thị dấu phẩy như hiện tại từ SSMS?
  • Chúng tôi đang sử dụng SQL Server 2008. Có cách nào để thay đổi mã hóa cho bất kỳ ký tự UTF-8 nào thành ký tự ASCII mà không cần sử dụng các công cụ nhập / xuất hoặc đổ vào một tệp phẳng không? Tức là tôi có thể thực hiện chuyển đổi này thông qua một truy vấn?
  • Có cách nào để xác định lập trình các bản ghi có vấn đề thông qua một truy vấn (có vấn đề được xác định là các ký tự UTF-8 không được hỗ trợ qua ASCII) không?

Cảm ơn bạn trước!

Sử dụng sp_help N'table_name';tôi thấy rằng Collation của VARCHARcột này là : SQL_Latin1_General_CP1_CI_AS.


VARCHARCột đối chiếu là gì sử dụng?
Solomon Rutzky

@SolomonRutzky làm thế nào để bạn kiểm tra đối chiếu. Tôi không chắc điều đó có nghĩa là gì
Eric

Cách nhanh nhất tôi nghĩ là : sp_help N'table_name';. Nhìn vào cột dựa trên "tên" và sau đó nhìn vào cột "collation_name".
Solomon Rutzky

@SolomonRutzky đối chiếu cho trường đó là 'SQL_Latin1_General_CP1_CI_AS'
Eric

Câu trả lời:


17

SQL Server không lưu trữ UTF-8 trong mọi trường hợp. Bạn nhận được UTF-16 Little Endian (LE) thông qua NVARCHAR(bao gồm NCHARNTEXT, nhưng không bao giờ sử dụng NTEXT) và XML, hoặc một số mã hóa 8 bit, dựa trên Trang mã, thông qua VARCHAR(bao gồm CHARTEXT, nhưng không bao giờ sử dụng TEXT) .

Vấn đề ở đây là mã của bạn đang dịch sai ký tự 0x82 đó, nghĩ rằng đó là UTF-8, nhưng thực tế không phải vậy. Không có "ký tự" UTF-8 nào có giá trị 0x82, đó là lý do tại sao bạn nhận được biểu tượng "không xác định" / thay thế của "". Vui lòng xem bảng UTF-8 sau đây cho thấy rằng không có ký tự nào cho một byte đơn 0x82:

Bảng mã hóa UTF-8

Như OP đã nêu, Collation của cột được đề cập là SQL_Latin1_General_CP1_CI_AS, điều đó có nghĩa là mã hóa 8 bit đang sử dụng Mã Trang 1252, là Windows Latin 1 (ANSI) . Và kiểm tra biểu đồ đó (cuộn xuống biểu đồ phía dưới vì nó có tên các ký tự) có giá trị 0x82 (tìm "82" trong cột "Điểm mã") trên thực tế là Dấu ngoặc đơn 9 điểm thấp mà bạn thấy trong SSMS. Ký tự đó, trong UTF-8, là một chuỗi 3 byte : E2 80 9A.

Tất cả những gì các phương tiện này là: mã Python nhu cầu của bạn cho một trong hai bộ client mã hóa cho kết nối SQL Server để Mã Trang 1252, hoặc bạn cần phải thay đổi / chuyển đổi bảng mã của chuỗi trở lại từ Mã Trang 1252 để UTF-8.

Tất nhiên, nếu điều này đang được hiển thị trên một trang web, thì bạn có thể thay đổi bộ ký tự khai báo của trang thành Windows-1252, nhưng điều đó có thể gây trở ngại cho các ký tự khác trên trang nếu đã có các ký tự UTF-8 ở đó.


Thật tuyệt, điều này rất hữu ích, cảm ơn bạn Solomon. Xin vui lòng cho tôi biết về việc dịch sai. Đây là một vấn đề khá khó khăn và tôi thậm chí không chắc bắt đầu từ đâu.
Eric

Wow, chi tiết tuyệt vời, @Solomon! Tôi đã đến đây để tìm kiếm một vấn đề Python + MS SQL khác, nhưng vẫn tiếp tục đọc vì tôi đã học được rất nhiều. :-P
Mike Williamson

1
@MikeWilliamson Cảm ơn bạn đã chia sẻ lời khen đó :). Bạn cũng có thể quan tâm đến các vấn đề sau: băm TSQL md5 khác với C # .NET md5 (trên SO), Cách xóa dấu dấu tiếng Do Thái (ở đây trên DBA.SE) và Collations.Info . Thưởng thức!
Solomon Rutzky

Cảm ơn! Tôi nghi ngờ bất cứ ai làm việc với một ngôn ngữ phi Latin dựa trên hiểu biết công cụ này đến nay tốt hơn so với bất kỳ người trong chúng ta sung sướng làm việc tại Mỹ / Anh. :)
Mike Williamson

1
Xin lưu ý: MS SQL Server 2019 giới thiệu hỗ trợ riêng cho UTF-8 trong các kiểu dữ liệu VARCHAR / CHAR.
Gregory Arenius
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.