Jak używać sortowania UTF-8 w bazie danych SQL Server?

84

Przeprowadziłem migrację bazy danych z mysql do SQL Server (polityka), oryginalnej bazy danych mysql używającej UTF8.

Teraz przeczytałem /dba/7346/sql-server-2005-2008-utf-8-collation-charset, że SQL Server 2008 nie obsługuje utf8, czy to żart?

SQL Server obsługuje wiele baz danych, w większości zakodowanych w alfabecie łacińskim. Ponieważ migrowana baza danych jest przeznaczona do publikowania w Internecie, chcę zachować kodowanie utf8. Czy coś przeoczyłem lub czy muszę kodować / dekodować na poziomie aplikacji?

Teson
źródło
Właściwie nie ma problemu z używaniem UTF8, tworząc SQLCLR UDF i możesz pobrać kod z Microsoft. sprawdź ten link: technet.microsoft.com/en-us/library/ms160893(v=sql.90).aspx
Ronen Ariely
1
Warto zauważyć, że Java, JavaScript, DotNet i Windows używają wewnętrznie UTF-16, więc jeśli Twoja witryna ma być zakodowana w którymkolwiek z nich, zapisujesz konwersję do UTF16.
Ben
1
Jeśli to pomoże, możesz udawać, że SQL Server wewnętrznie przechowuje tekst w formacie UTF-8; a sterownik konwertuje go z powrotem na UTF-16 podczas pobierania. Można również udawać, że SQL Server przechowuje tekst jako UCS-32. Format pamięci wewnętrznej jest nieistotnym szczegółem implementacji. Ważne jest, aby bazy danych zwracały dane znakowe Unicode w formacie UTF-16 (pasujące do twojego środowiska programistycznego).
Ian Boyd,

Odpowiedzi:

26

Nie! To nie żart.

Spójrz tutaj: http://msdn.microsoft.com/en-us/library/ms186939.aspx

Typy danych znakowych, które mają stałą długość, nchar lub zmienną długość, nvarchar, dane Unicode i używają zestawu znaków UNICODE UCS-2.

A także tutaj: http://en.wikipedia.org/wiki/UTF-16

Starszy UCS-2 (2-bajtowy uniwersalny zestaw znaków) to podobne kodowanie znaków, które zostało zastąpione przez UTF-16 w wersji 2.0 standardu Unicode w lipcu 1996 roku.

edze
źródło
Dobrze. Czy klient mssql może przetłumaczyć na zewnętrzny świat UTF8?
Teson,
mssql-clientmoże być wszystkim. Java, .NET, C, PHP itp. ... co oznacza klient?
edze
1
Klient: rozszerzenie sqlsrv w php. Robert umieszcza to tutaj jako czysty tekst: social.msdn.microsoft.com/Forums/en/sqldriverforphp/thread/… , oceni i opublikuje wyniki.
Teson,
2
Witam ponownie, przepraszam za opóźnienie, ale dziękuję za powtórzenia, używając sqlsrv_connect (, array ("CharacterSet" => "UTF-8") .. w ciągu połączenia działa dobrze. PDO jest niedostępny, prawda?
Teson
33

UTF-8 nie jest zestawem znaków, to kodowanie. Zestaw znaków dla UTF-8 to Unicode. Jeśli chcesz przechowywać tekst Unicode, użyj nvarchartypu danych.

Gdyby baza danych używała UTF-8 do przechowywania tekstu, nadal nie wydobywałbyś tekstu jako zakodowanych danych UTF-8, ale jako tekst zdekodowany.

Możesz łatwo przechowywać tekst zakodowany w UTF-8 w bazie danych, ale wtedy nie przechowujesz go jako tekstu, przechowujesz go jako dane binarne ( varbinary).

Guffa
źródło
Dzięki za wkład. Można się więcej dowiedzieć na ten temat, patrząc na przykład na stackoverflow.com/questions/3951722/ ...
Teson
Nie mogę tego obejść. „Zestaw znaków dla UTF8 to Unicode” ?? Czy utf8 nie jest szerszy niż unicode. Zapisanie Dauðalogn w unicode vs utf8 daje różne wyniki: (EF BB BF) 44 61 75 C3 B0 61 6C 6F 67 6E vs \ u0044 \ u0061 \ u0075 \ u00f0 \ u0061 \ u006c \ u006f \ u0067 \ u006e
Teson
2
@ user247245: UTF-8 to kodowanie, a Unicode to zestaw znaków. UTF-8 to jeden ze sposobów zapisywania Unicode. To, czego użyłeś do reprezentowania Unicode, to kody ucieczki używane w literałach ciągów, zwykle nie jest to sposób reprezentowania Unicode jako pliku. UTF-32 byłby najbliższym tłumaczeniem bezpośrednio z Uncode do formatu pliku, w którym każdy kod znaku jest zapisywany jako liczba 32-bitowa.
Guffa
Czy możesz wyjaśnić, dlaczego trzecia litera w powyższym przykładzie jest reprezentowana w UTF8 jako C3 B0, aw Unicode jako po prostu F0. Dzięki za pomoc.
Teson
4
@ user247245: Kody znaków od 8 do 11 bitów są kodowane jak 110xxxxx 10xxxxxxw UTF-8 (gdzie xreprezentuje bity danych), więc kod znaku F0( 00011110000jako 11 bitów) jest kodowany jako 11000011 10110000(umieszczenie 00011z kodu znaku w pierwszym bajcie iw 110000drugim ), który jest C3 B0.
Guffa
24

Wygląda na to, że będzie to wreszcie obsługiwane w SQL Server 2019! SQL Server 2019 - co nowego?

Od BOL:

Obsługa UTF-8

Pełna obsługa szeroko stosowanego kodowania znaków UTF-8 jako kodowania importu lub eksportu lub jako sortowanie danych tekstowych na poziomie bazy danych lub kolumny. UTF-8 jest dozwolone w CHARi VARCHARtypów danych, a jest włączona podczas tworzenia lub zmiany sortowania obiektu, do zestawień z UTF8przyrostkiem.

Na przykład LATIN1_GENERAL_100_CI_AS_SCto LATIN1_GENERAL_100_CI_AS_SC_UTF8. UTF-8 jest dostępny tylko dla sortowań systemu Windows, które obsługują znaki uzupełniające, zgodnie z wprowadzeniem w SQL Server 2012. NCHARi NVARCHARpozwalają tylko na kodowanie UTF-16 i pozostają niezmienione.

Ta funkcja może zapewnić znaczne oszczędności pamięci, w zależności od używanego zestawu znaków. Na przykład zmiana istniejącego typu danych kolumny z ciągami znaków ASCII z NCHAR(10)na CHAR(10)używanie sortowania z włączoną obsługą UTF-8 przekłada się na prawie 50% zmniejszenie wymagań dotyczących pamięci. Ta redukcja jest spowodowana tym, że NCHAR(10)wymaga 22 bajtów do przechowywania, podczas gdy CHAR(10)wymaga 12 bajtów dla tego samego ciągu Unicode.

Aktualizacja 2019-05-14:

Wydaje się, że dokumentacja jest teraz zaktualizowana i wyjaśnia nasze opcje pojawiające się w MSSQL 2019 w sekcji „ Sortowanie i obsługa Unicode ”.

Aktualizacja 2019-07-24:

Artykuł Pedro Lopes - Senior Program Manager @ Microsoft na temat wprowadzenia obsługi UTF-8 dla Azure SQL Database

Bartosz X
źródło
4

Zauważ, że jak Microsoft SQL Server 2016, UTF-8 jest obsługiwane przez bcp, BULK_INSERTi OPENROWSET.

Dodatek 2016-12-21: SQL Server 2016 z dodatkiem SP1 umożliwia teraz kompresję Unicode (i większość innych funkcji, które wcześniej były dostępne tylko dla przedsiębiorstw) dla wszystkich wersji MS SQL, w tym Standard i Express. To nie to samo, co obsługa UTF-8, ale daje podobne korzyści, jeśli celem jest redukcja miejsca na dysku dla zachodnich alfabetów.

Charles Burns
źródło
Ale nie OPENQUERY? Zastanawiam się, czy to dlatego mam problemy z migracją danych CLOB z Oracle przy użyciu OPENQUERY.
Geoff Dawdy
4

Dwa UDF do obsługi UTF-8 w 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
Xabi
źródło