Cách sử dụng UTF-8 Collation trong cơ sở dữ liệu SQL Server?


83

Tôi đã di chuyển cơ sở dữ liệu từ mysql sang SQL Server (chính trị), cơ sở dữ liệu mysql ban đầu sử dụng UTF8.

Bây giờ tôi đọc /dba/7346/sql-server-2005-2008-utf-8-collation-charset rằng SQL Server 2008 không hỗ trợ utf8, đây có phải là một trò đùa?

Máy chủ SQL lưu trữ nhiều cơ sở dữ liệu, chủ yếu được mã hóa bằng tiếng Latinh. Vì db được di chuyển nhằm mục đích xuất bản web nên tôi muốn giữ mã hóa utf8. Tôi đã bỏ lỡ điều gì đó hoặc tôi có cần mã hóa / dec ở cấp ứng dụng không?


Trên thực tế, không có vấn đề gì với việc sử dụng UTF8, bằng cách tạo SQLCLR UDF và bạn có thể tải xuống mã từ Microsoft. kiểm tra liên kết này: technet.microsoft.com/en-us/library/ms160893(v=sql.90).aspx
Ronen Ariely

1
Cần lưu ý rằng Java, JavaScript, DotNet và Windows đều sử dụng UTF-16 nội bộ, vì vậy nếu trang web của bạn được mã hóa bằng bất kỳ mã nào trong số đó thì bạn đang lưu chuyển đổi thành UTF16.
Ben

1
Nếu hữu ích, bạn có thể giả vờ rằng SQL Server lưu trữ nội bộ văn bản dưới dạng UTF-8; và trình điều khiển chuyển đổi nó trở lại UTF-16 khi bạn truy xuất nó. Bạn cũng có thể giả sử rằng SQL Server lưu trữ văn bản dưới dạng UCS-32. Định dạng bộ nhớ trong là một chi tiết triển khai không liên quan. Điều quan trọng là cơ sở dữ liệu trả về dữ liệu ký tự unicode dưới dạng UTF-16 (phù hợp với môi trường lập trình của bạn).
Ian Boyd

Câu trả lời:


25

Không! Nó không phải là một trò đùa.

Hãy xem tại đây: http://msdn.microsoft.com/en-us/library/ms186939.aspx

Các kiểu dữ liệu ký tự là dữ liệu có độ dài cố định, nchar hoặc độ dài thay đổi, nvarchar, Unicode và sử dụng bộ ký tự UNICODE UCS-2.

Và cũng ở đây: http://en.wikipedia.org/wiki/UTF-16

UCS-2 cũ hơn (Bộ ký tự chung 2 byte) là kiểu mã hóa ký tự tương tự đã được thay thế bằng UTF-16 trong phiên bản 2.0 của tiêu chuẩn Unicode vào tháng 7 năm 1996.


Đồng ý. Mssql-client có thể dịch ra thế giới UTF8 bên ngoài không?
Teson

mssql-clientcó thể là mọi thứ. Java, .NET, C, PHP, v.v. ... nghĩa là gì với máy khách?
edze

1
Máy khách: phần mở rộng sqlsrv dưới php. Robert đặt nó, tôi có văn bản rõ ràng ở đây: social.msdn.microsoft.com/Forums/en/sqldriverforphp/thread/… , sẽ đánh giá và đăng kết quả.
Teson

2
Hi một lần nữa, xin lỗi vì sự chậm trễ nhưng nhờ các đại diện, sử dụng sqlsrv_connect (, array ( "characterset" => "UTF-8") .. trong chuỗi kết nối hoạt động tốt PDO là ra, phải không.?
Teson

29

UTF-8 không phải là một bộ ký tự, nó là một mã hóa. Bộ ký tự cho UTF-8 là Unicode. Nếu bạn muốn lưu trữ văn bản Unicode, bạn sử dụng nvarcharkiểu dữ liệu.

Nếu cơ sở dữ liệu sử dụng UTF-8 để lưu trữ văn bản, bạn vẫn không lấy văn bản ra dưới dạng dữ liệu UTF-8 được mã hóa, bạn sẽ lấy nó ra dưới dạng văn bản được giải mã.

Bạn có thể dễ dàng lưu trữ văn bản được mã hóa UTF-8 trong cơ sở dữ liệu, nhưng sau đó bạn không lưu trữ nó dưới dạng văn bản, bạn lưu trữ nó dưới dạng dữ liệu nhị phân ( varbinary).


Cảm ơn cho đầu vào. Có nhiều điều cần tìm hiểu xung quanh vấn đề này, xem xét ví dụ: stackoverflow.com/questions/3951722/…
Teson

Tôi không thể hiểu được chuyện này. "Bộ ký tự cho UTF8 là Unicode" ?? Không phải cách utf8 rộng hơn unicode. Lưu Dauðalogn trong unicode so với utf8 cho kết quả khác nhau: (EF BB BF) 44 61 75 C3 B0 61 6C 6F 67 6E so với \ u0044 \ u0061 \ u0075 \ u00f0 \ u0061 \ u006c \ u006f \ u0067 \ u006e
Teson

2
@ user247245: UTF-8 là bảng mã và Unicode là bộ ký tự. UTF-8 là một cách lưu Unicode. Những gì bạn đã sử dụng để đại diện cho Unicode là các mã thoát được sử dụng trong chuỗi ký tự, đó không phải là cách thông thường bạn biểu diễn Unicode dưới dạng tệp. UTF-32 sẽ là bản dịch gần nhất trực tiếp từ Uncode sang định dạng tệp, trong đó mỗi mã ký tự được lưu dưới dạng số 32 bit.
Guffa

Bạn có thể vui lòng giải thích tại sao ký tự thứ ba trong ví dụ trên được biểu diễn trong UTF8 là C3 B0 và trong unicode chỉ đơn giản là F0. Cảm ơn bạn đã giúp đỡ.
Teson

4
@ user247245: Mã ký tự từ 8 đến 11 bit được mã hóa như 110xxxxx 10xxxxxxtrong UTF-8 (nơi xđại diện cho các bit dữ liệu), vì vậy mã ký tự F0( 00011110000dưới dạng 11 bit) được mã hóa thành 11000011 10110000(đặt 00011từ mã ký tự trong byte đầu tiên và 110000trong byte thứ hai ) là C3 B0.
Guffa

24

Có vẻ như điều này cuối cùng sẽ được hỗ trợ trong SQL Server 2019! SQL Server 2019 - có gì mới?

Từ BOL:

Hỗ trợ UTF-8

Hỗ trợ đầy đủ cho mã hóa ký tự UTF-8 được sử dụng rộng rãi dưới dạng mã hóa nhập hoặc xuất, hoặc đối chiếu cấp cơ sở dữ liệu hoặc cấp cột cho dữ liệu văn bản. UTF-8 được phép vào CHARVARCHARkiểu dữ liệu, và được kích hoạt khi tạo hoặc thay đổi đối chiếu của một đối tượng để một collation với UTF8hậu tố.

Ví dụ, LATIN1_GENERAL_100_CI_AS_SCđể LATIN1_GENERAL_100_CI_AS_SC_UTF8. UTF-8 chỉ khả dụng cho các đối chiếu Windows hỗ trợ các ký tự bổ sung, như được giới thiệu trong SQL Server 2012. NCHARvà chỉ NVARCHARcho phép mã hóa UTF-16 và không thay đổi.

Tính năng này có thể giúp tiết kiệm dung lượng đáng kể, tùy thuộc vào bộ ký tự được sử dụng. Ví dụ, thay đổi một kiểu dữ liệu cột hiện có với chuỗi ASCII từ NCHAR(10)để CHAR(10)sử dụng UTF-8 cho phép đối chiếu, chuyển thành giảm gần 50% trong các yêu cầu lưu trữ. Việc giảm này là do NCHAR(10)yêu cầu 22 byte để lưu trữ, trong khi CHAR(10)yêu cầu 12 byte cho cùng một chuỗi Unicode.

Cập nhật 2019-05-14:

Tài liệu dường như đã được cập nhật ngay bây giờ và giải thích các tùy chọn của chúng tôi trong MSSQL 2019 trong phần " Hỗ trợ đối chiếu và Unicode ".

Cập nhật 2019-07-24:

Bài viết của Pedro Lopes - Giám đốc Chương trình Cấp cao @ Microsoft về việc giới thiệu hỗ trợ UTF-8 cho Cơ sở dữ liệu Azure SQL


4

Lưu ý rằng như của Microsoft SQL Server 2016, UTF-8 được hỗ trợ bởi bcp, BULK_INSERTOPENROWSET.

Phụ lục 2016-12-21: SQL Server 2016 SP1 hiện cho phép Nén Unicode (và hầu hết các tính năng trước đây chỉ dành cho Doanh nghiệp) cho tất cả các phiên bản của MS SQL bao gồm Standard và Express. Điều này không giống như hỗ trợ UTF-8, nhưng nó mang lại lợi ích tương tự nếu mục tiêu là giảm dung lượng ổ đĩa cho các bảng chữ cái phương Tây.


Nhưng không phải OPENQUERY? Tôi tự hỏi liệu đây có phải là lý do tại sao tôi gặp sự cố khi di chuyển dữ liệu CLOB từ Oracle bằng OPENQUERY hay không.
Geoff Dawdy

4

Hai UDF để đối phó với UTF-8 trong T-SQL:

CREATE Function UcsToUtf8(@src nvarchar(MAX)) returns varchar(MAX) as
begin
    declare @res varchar(MAX)='', @pi char(8)='%[^'+char(0)+'-'+char(127)+']%', @i int, @j int
    select @i=patindex(@pi,@src collate Latin1_General_BIN)
    while @i>0
    begin
        select @j=unicode(substring(@src,@i,1))
        if @j<0x800     select @res=@res+left(@src,@i-1)+char((@j&1984)/64+192)+char((@j&63)+128)
        else            select @res=@res+left(@src,@i-1)+char((@j&61440)/4096+224)+char((@j&4032)/64+128)+char((@j&63)+128)
        select @src=substring(@src,@i+1,datalength(@src)-1), @i=patindex(@pi,@src collate Latin1_General_BIN)
    end
    select @res=@res+@src
    return @res
end

CREATE Function Utf8ToUcs(@src varchar(MAX)) returns nvarchar(MAX) as
begin
    declare @i int, @res nvarchar(MAX)=@src, @pi varchar(18)
    select @pi='%[à-ï][€-¿][€-¿]%',@i=patindex(@pi,@src collate Latin1_General_BIN)
    while @i>0 select @res=stuff(@res,@i,3,nchar(((ascii(substring(@src,@i,1))&31)*4096)+((ascii(substring(@src,@i+1,1))&63)*64)+(ascii(substring(@src,@i+2,1))&63))), @src=stuff(@src,@i,3,'.'), @i=patindex(@pi,@src collate Latin1_General_BIN)
    select @pi='%[Â-ß][€-¿]%',@i=patindex(@pi,@src collate Latin1_General_BIN)
    while @i>0 select @res=stuff(@res,@i,2,nchar(((ascii(substring(@src,@i,1))&31)*64)+(ascii(substring(@src,@i+1,1))&63))), @src=stuff(@src,@i,2,'.'),@i=patindex(@pi,@src collate Latin1_General_BIN)
    return @res
end
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.