Bir "karakterin" (birden çok Kod Noktasından oluşabilir: vekil çiftleri, karakterleri birleştirme vb.) Diğeriyle nasıl karşılaştırıldığı oldukça karmaşık bir kurallar kümesine dayanır. Unicode belirtiminde temsil edilen tüm dillerde bulunan çeşitli (ve bazen "tuhaf") kuralların dikkate alınması gerektiği için çok karmaşıktır . Bu sistem, tüm NVARCHAR
veriler ve VARCHAR
bir Windows Server Harmanlama kullanan ve bir SQL Server Harmanlama (bir tanesi ile başlayan SQL_
) kullanan veriler için ikili olmayan Harmanlamalara uygulanır . Bu sistem, VARCHAR
basit eşlemeler kullandığından SQL Server Harmanlama kullanan veriler için geçerli değildir .
Kuralların çoğu Unicode Harmanlama Algoritması'nda (UCA) tanımlanmıştır . Bu kurallardan bazıları ve bazıları UCA'da olmayanlar:
allkeys.txt
Dosyada verilen varsayılan sipariş / ağırlık (aşağıda belirtilmiştir)
- Hangi hassasiyetler ve seçenekler kullanılıyor (örn. Büyük / küçük harfe duyarlı mı yoksa duyarsız mı?) Ve eğer duyarlıysa, büyük harf birinci mi yoksa küçük harf mi?)
- Yerel ayar tabanlı geçersiz kılmalar.
- Unicode standardının sürümü kullanılıyor.
- "İnsan" faktörü (yani Unicode yazılım değil, bir özelliktir ve bu nedenle onu uygulamak için her satıcıya bırakılmıştır)
İnsan faktörü ile ilgili son noktanın, SQL Server'ın spesifikasyona göre her zaman% 100 davranmasını beklememesi gerektiğini açıkça belirtmek için vurguladım.
Buradaki geçersiz kılma faktörü, her bir Kod Noktasına verilen ağırlıktır ve birden fazla Kod Noktasının aynı ağırlık spesifikasyonunu paylaşabilmesidir. Burada temel ağırlıkları bulabilirsiniz (bölgeye özgü geçersiz kılmalar yok) ( 100
Harmanlama serisinin Unicode v 5.0 - Microsoft Connect öğesindeki yorumlarda gayri resmi onay olduğuna inanıyorum ):
http://www.unicode.org/Public/UCA/5.0.0/allkeys.txt
Söz konusu Kod Noktası - U + FFFD - şöyle tanımlanır:
FFFD ; [*0F12.0020.0002.FFFD] # REPLACEMENT CHARACTER
Bu gösterim, UCA'nın 9.1 Allkeys Dosya Biçimi bölümünde tanımlanmıştır :
<entry> := <charList> ';' <collElement>+ <eol>
<charList> := <char>+
<collElement> := "[" <alt> <weight> "." <weight> "." <weight> ("." <weight>)? "]"
<alt> := "*" | "."
Collation elements marked with a "*" are variable.
Baktığımız Kod Noktası "*" ile başlayan bir spesifikasyona sahip olduğundan, bu son satır önemlidir. 3.6 Değişken Ağırlıklandırma bölümünde , doğrudan erişimimiz olmayan Harmanlama yapılandırması değerlerine bağlı olarak tanımlanan dört olası davranış vardır (bunlar her Harmanlamanın Microsoft uygulamasına sabit olarak kodlanmıştır; örneğin, büyük / küçük harfe duyarlı veya küçük harf kullanıyorsa veya büyük harf ilk olarak, Harmanlamaları VARCHAR
kullanan veriler SQL_
ve diğer tüm varyasyonlar arasında farklı olan bir özellik ).
Yolların alındığı tam araştırmayı yapmak ve daha sağlam bir kanıt verilebilecek şekilde hangi seçeneklerin kullanıldığını çıkarmak için zamanım yok, ancak her Kod Noktası belirtiminde bir şey olsun veya olmasın söylemek güvenli "eşit" kabul edilir her zaman tam şartname kullanmayacak. Bu durumda, "0F12.0020.0002.FFFD" var ve büyük olasılıkla kullanılan seviye 2 ve 3'tür (yani .0020.0002 ). ".0020.0002" için Notepad ++ uygulamasında bir "Sayma" işlemi yapıyor. 12.581 sonuç bulundu (henüz ele almadığımız ek karakterler dahil). "[*" Üzerinde "Say" işlemi yapmak 4049 eşleşme döndürür. Bir desen kullanarak RegEx "Bul" / "Sayımı" yapmak\[\*\d{4}\.0020\.0002
832 eşleşme döndürür. Yani bu kombinasyonda bir yerde, artı göremediğim bazı diğer kurallar ve ayrıca Microsoft'a özgü bazı uygulama ayrıntıları, bu davranışın tam açıklamasıdır. Ve açık olmak gerekirse, davranış, eşleşen tüm karakterler için aynıdır, çünkü kurallar uygulandıktan sonra hepsi aynı ağırlığa sahiptirler (yani, bu soru bunlardan herhangi biri hakkında sorulabilirdi, değil mutlaka Bay �
).
Aşağıdaki sorguyu görebilir ve sorgunun altındaki COLLATE
sonuçlara göre cümleleri değiştirerek , çeşitli duyarlılıkların Harmanlamaların iki sürümünde nasıl çalıştığını görebilirsiniz:
;WITH cte AS
(
SELECT TOP (65536) ROW_NUMBER() OVER (ORDER BY (SELECT 0)) - 1 AS [Num]
FROM [master].sys.columns col
CROSS JOIN [master].sys.objects obj
)
SELECT cte.Num AS [Decimal],
CONVERT(VARBINARY(2), cte.Num) AS [Hex],
NCHAR(cte.Num) AS [Character]
FROM cte
WHERE NCHAR(cte.Num) = NCHAR(0xFFFD) COLLATE Latin1_General_100_CS_AS_WS --N'�'
ORDER BY cte.Num;
Farklı harmanlamalarda eşleşen karakterlerin çeşitli sayıları aşağıdadır.
Latin1_General_100_CS_AS_WS = 5840
Latin1_General_100_CS_AS = 5841 (The "extra" character is U+3000)
Latin1_General_100_CI_AS = 5841
Latin1_General_100_CI_AI = 6311
Latin1_General_CS_AS_WS = 21,229
Latin1_General_CS_AS = 21,230
Latin1_General_CI_AS = 21,230
Latin1_General_CI_AI = 21,537
Yukarıda listelenen tüm harmanlamalarda N'' = N'�'
da doğru olarak değerlendirilir.
GÜNCELLEME
Biraz daha araştırma yapabildim ve işte bulduğum şey:
"Muhtemelen" nasıl çalışmalı
YBÜ Harmanlama Demosunu kullanarak, yerel ayarı "en-US-u-va-posix" olarak ayarladım, gücü "birincil" olarak ayarladım, işaretli "sıralama tuşlarını" kontrol ettim ve kopyaladığım aşağıdaki 4 karaktere yapıştırdım. yukarıdaki sorgunun sonuçları ( Latin1_General_100_CI_AI
Harmanlama kullanılarak):
�
Ԩ
ԩ
Ԫ
ve bu döndürür:
Ԫ
60 2E 02 .
Ԩ
60 7A .
ԩ
60 7A .
�
FF FD .
Ardından, http://unicode.org/cldr/utility/character.jsp?a=fffd adresinden " " için karakter özelliklerini kontrol edin ve düzey 1 sıralama anahtarının (yani FF FD
) "uca" özelliğiyle eşleştiğini görün. Bu "uca" mülkünü tıkladığınızda, yalnızca 1 eşleşmeyi gösteren bir arama sayfasına ( http://unicode.org/cldr/utility/list-unicodeset.jsp?a=%5B%3Auca%3DFFFD%3A%5D) yönlendirilirsiniz . Ve allkeys.txt dosyasında, seviye 1 sıralama ağırlığı olarak gösterilir 0F12
ve bunun için yalnızca 1 eşleşme vardır.
Biz doğru davranış yorumlama emin olmak için, ben başka bir karakter baktı: YUNAN BÜYÜK HARFLERLE OMICRON İLE varia Ὸ
de http://unicode.org/cldr/utility/character.jsp?a=1FF8 hangi bir "uca" ( yani seviye 1 sıralama ağırlığı / harmanlama elemanı) 5F30
. Bu "5F30" u tıklamak bizi bir arama sayfasına götürür - http://unicode.org/cldr/utility/list-unicodeset.jsp?a=%5B%3Auca%3D5F30%3A%5D - 30 eşleşme gösteriliyor, 20 / 0 - 65535 aralığındadır (yani U + 0000 - U + FFFF). Baktığında allkeys.txt Kod Noktası için dosyanın 1FF8 , biz bir seviye 1 sıralama ağırlığını bkz 12E0
. Notepad ++ uygulamasında "Sayma" işlemi12E0.
30 eşleşmeyi gösterir (dosya Unicode v 5.0 için olduğu ve site Unicode v 9.0 verilerini kullandığı için garanti edilmese de, bu Unicode.org'un sonuçlarıyla eşleşir).
SQL Server'da, aşağıdaki sorgu 10 ek karakteri kaldırırken Unicode.org aramasıyla aynı olan 20 eşleşmeyi döndürür:
;WITH cte AS
(
SELECT TOP (65535) ROW_NUMBER() OVER (ORDER BY (SELECT 0)) AS [Num]
FROM [master].sys.columns col
CROSS JOIN [master].sys.objects obj
)
SELECT cte.Num AS [Decimal],
CONVERT(VARCHAR(50), CONVERT(VARBINARY(2), cte.Num), 2) AS [Hex],
NCHAR(cte.Num) AS [Character]
FROM cte
WHERE NCHAR(cte.Num) = NCHAR(0x1FF8) COLLATE Latin1_General_100_CI_AI
ORDER BY cte.Num;
Ve emin olmak için, ICU Harmanlama Demosu sayfasına geri dönme ve "Giriş" kutusundaki karakterleri SQL Server'dan 20 sonuç listesinden alınan aşağıdaki 3 karakterle değiştirme:
Ὂ
𝜪
Ὸ
aslında hepsinin aynı 5F 30
seviye 1 sıralama ağırlığına sahip olduğunu gösterir (karakter özelliği sayfasındaki "uca" alanı ile eşleşir).
SO, kesinlikle bu özel karakter olmalıdır sanki görünüyor değil başka bir şey uyuyor.
Aslında nasıl çalışır (en azından Microsoft-Land'de)
SQL Server'ın aksine, .NET, CompareInfo.GetSortKey Yöntemi aracılığıyla bir dize için sıralama anahtarını göstermenin bir yoluna sahiptir . Bu yöntemi kullanarak ve sadece U + FFFD karakterini ileterek, bir sıralama anahtarı döndürür 0x0101010100
. Daha sonra, 0 - 65535 aralığındaki tüm karakterleri tekrarlayan, hangilerinin 0x0101010100
4529 eşleşme döndürdüğünü görmek için . Bu, SQL Server'da döndürülen 5840 ile tam olarak eşleşmiyor ( Latin1_General_100_CS_AS_WS
Harmanlama kullanılırken), ancak Unicode v kullanan Windows 10 ve .NET Framework sürüm 4.6.1'i çalıştırdığımda (şimdilik) alabileceğimiz en yakın şey 6.3.0 CharUnicodeInfo Sınıfı grafiğine göre("Arayanlara Not", "Notlar" bölümünde). Şu an bir SQLCLR işlevi kullanıyorum ve bu nedenle hedef Framework sürümünü değiştiremiyorum. Bir şans elde ettiğimde, bir konsol uygulaması oluşturacağım ve 100 serisi Harmanlamalarla eşleşmesi gereken Unicode v 5.0'ı kullanan 4.5 hedef Framework sürümünü kullanacağım.
Ne bu test gösterileri bile .NET ve U + FFFD için SQL Server arasında maçların aynı numarası olmadan, yani, bu oldukça açıktır değil SQL Server özgü davranış ve uygulama ile kasıtlı veya gözetim yapılması olduğunu olsun Microsoft tarafından, U + FFFD karakteri, Unicode belirtimine uygun olmasa bile, gerçekten birkaç karakterle eşleşir. Ve bu karakterin U + 0000 (null) ile eşleştiği göz önüne alındığında, muhtemelen sadece ağırlık eksikliğidir.
AYRICA
=
Sorgu vs sorgu davranış davranış farkı ile ilgili olarak LIKE N'%�%'
, bu joker karakterler ve bu (yani � Ƕ Ƿ Ǹ
) karakterler için eksik (varsayalım) ağırlıkları ile ilgili . LIKE
Koşul basit olarak değiştirilirse , koşulla LIKE N'�'
aynı 3 satırı döndürür =
. Joker karakterlerle ilgili sorun "eksik" ağırlıklardan kaynaklanmıyorsa ( btw 0x00
tarafından döndürülen bir sıralama anahtarı yoktur CompareInfo.GetSortKey
), bu karakterlerin potansiyel olarak sıralama anahtarının bağlama göre değişmesine izin veren bir özelliğe sahip olmasından kaynaklanabilir (yani, çevreleyen karakterler) ).
FFFD
(arama*0F12.0020.0002.FFFD
sadece bir sonuç döndürür). @ Forrest'in hepsinin boş dizeyle eşleştiği ve konu üzerinde biraz daha fazla okuma yaptığı gözleminden, çeşitli ikili olmayan harmanlamalarda paylaştıkları ağırlığa benziyor aslında aslında sıfır olduğuna inanıyorum.