Varchar veri türü neden unicode değerlere izin veriyor?


17

Bir varchar sütun içeren bir tablo var. Aşağıda gösterildiği gibi Ticari Marka (™), telif hakkı (©) ve diğer Unicode karakterlere izin vermektedir.

Create table VarcharUnicodeCheck
(
col1 varchar(100)
)

insert into VarcharUnicodeCheck (col1) values ('MyCompany')
insert into VarcharUnicodeCheck (col1) values ('MyCompany™')
insert into VarcharUnicodeCheck (col1) values ('MyCompany░')
insert into VarcharUnicodeCheck (col1) values ('MyCompanyï')
insert into VarcharUnicodeCheck (col1) values ('MyCompany')

select * from VarcharUnicodeCheck

Ancak varchar'ın tanımı, unicode olmayan dize verilerine izin verdiğini söylüyor. Ancak Ticari Marka (™) ve Kayıtlı (®) sembolleri Unicode karakterlerdir. Tanım varchar veri tipinin özelliği ile çelişiyor mu? Birincisi ve ikincisi gibi birkaç bağlantı okudum . Ama yine de tanım sadece unicode olmayan dize değerlerine izin verdiğini söylediğinde neden unicode dizeye izin verdiğini anlayamadım.


12
Tüm karakterler Unicode karakterlerdir.
Martin Smith

Microsoft, UTF-16 / UCS-2 anlamına geldiğinde genellikle UNICODE kullanır. UNICODE bir bağlam olduğundan UTF-8'i saymayabilirler.
CodesInChaos

1
@CodesInChaos: Yorumunuzu ayrıştırmak için mücadele ettim, ancak Unicode'u çeşitli UTF-n kodlamaları ile karıştırdığınızdan endişeleniyorum.
Monica ile Hafiflik Yarışları

1
@Martin Smith: Tüm karakterler Unicode karakterler ise, neden microsoft varchar tanımlaması Unicode olmayan dize verilerine izin verdiğini söylüyor?
Shiva

2
varchar'daki karakterlerin kodlaması unicode değil, ancak tüm karakterler unicode'da var
Martin Smith

Yanıtlar:


15

Ancak Ticari Marka (™) ve Kayıtlı (®) sembolleri Unicode karakterlerdir.

Burada yanılıyorsun. Dizeleriniz yalnızca asciikarakter içeriyor .

İşte size karakterlerinizin ascii (+ bazılarının extended asciiascii kodları 128 ile 255 arasında) olduğunu gösteren basit bir test :

declare @VarcharUnicodeCheck table
(
col1 varchar(100)
)

insert into @VarcharUnicodeCheck (col1) values ('MyCompany')
insert into @VarcharUnicodeCheck (col1) values ('MyCompany™')
insert into @VarcharUnicodeCheck (col1) values ('MyCompany░')
insert into @VarcharUnicodeCheck (col1) values ('MyCompanyï')
insert into @VarcharUnicodeCheck (col1) values ('MyCompany')

select *,
        right(col1, 1)as last_char, 
        ascii(right(col1, 1)) as_last_char_ascii
from @VarcharUnicodeCheck;

Burada tüm karakterlerinizin 1 bayt olarak kodlandığını açıkça görebilirsiniz:

resim açıklamasını buraya girin

Evet, saf ascii karakterleri değiller ama Genişletilmiş ASCII .

Burada size gerçek unicode karakteri Trademark(™)ve kodunu ve ikili gösterimini göstereceğim :

declare @t table (uni_ch nchar(1), ascii_ch char(1));
insert into @t values (N'™', '™');

select unicode(uni_ch) as [unicode of ™], 
       ascii(ascii_ch) [ascii of ™], 
       cast(uni_ch as varbinary(10)) as [uni_ch as varbinary], 
       cast(ascii_ch as varbinary(10)) as [ascii_ch as varbinary]
from @t;

resim açıklamasını buraya girin

Son olarak, Trademark(™)unicode karakterin 153 değil 8482 koduna sahip olduğunu görebilirsiniz :

select nchar(8482), nchar(153)

1
Ancak bahsettiğiniz makalede "ASCII" sözcüğü yok, sadece unicode ve unicode olmayan karakterler hakkında konuşuyorlar ve kullandığınız Ticari Marka (™) unicode değildi.
Ocak'ta sepupik

16
"Genişletilmiş ASCII" çok belirsiz bir terimdir. Gerçekte hangi 8 bit kodlamanın kullanıldığına bakmak daha yararlı olacaktır (yerel ayar / harmanlama ayarlarına dayalı mı?). Gerçekten de karakter 153 olarak ™ kodlamak Windows kodu sayfa 1252 , tahmin ediyorum.
IMSoP

2
@sepupic Bence kod noktaları ve kodlamalar arasındaki fark hakkında daha fazla okumak gerekir. Wikipedia yardımcı olabilir. "Bir kodlama Unicode kod aralığını (muhtemelen bir alt kümesi) kod değerleri olarak adlandırılan sabit boyutlu bir aralıktaki değer dizilerini eşler ." 8482, Windows-1252'de \ x99 (153), MacRoman'da \ xAA, UTF-8'de \ xE2 \ x84 \ xA2 gibi kodlanabilen ™ kod noktasıdır.
curiousdannii

7
127'nin üzerindeki 8 bitlik karakterlere dikkat edilmelidir: 127'nin üzerindeki her kodun temsil ettiği, kullanılan kodlamaya bağlı olarak değişebilir ve değişecektir. 1252 kod sayfasında unicode 8482, 153 ile eşleştirilir. 850 kod sayfasında, bu nokta 214 ( Ö) tarafından alınır ve ISO-8859-1'de (bazen Latin1 olarak adlandırılır) yazdırılabilir temsili olmayan bir kontrol kodudur. Eğer sürece biliyorum , olur hep aynı Codepage kullanıyor ANSI karakterleri (127 veya daha az) veya kullanım Unicode türleri sadık güvenlidir. Codepage 1252 en çok SQL Server'da yaygındır, ancak her yerde bulunmaz.
David Spillett

4
@Shiva Mutlak Minimum Her Yazılım Geliştiricisi Unicode ve Karakter Kümelerini Kesinlikle, Olumlu Olarak Bilmeli . ASCII birçok kodlamanın bir alt kümesidir ve bu kodlamaların neredeyse tamamı ASCII olmayan semboller içerir ve aynı anda Unicode değildir. Unicode'un da birçok farklı kodlaması vardır (UTF-8, UTF-32 vb.).
jpmc26

7

Yorumlardan, "Genişletilmiş ASCII" gerçekten ASCII tarafından tanımlanan standart 0-127 kod noktası aralığının ötesinde 128-255 aralığında karakterleri / kod noktalarını eşleyen bir kod sayfası anlamına gelen gerçekten kötü bir terim olduğunu kabul ediyorum.

SQL Server, harmanlamalarla birçok kod sayfasını destekler. ASCII olmayan karakterler, temel harmanlama karakteri desteklediği sürece varchar'ta saklanabilir.

'™' karakteri SQL Server harmanlama kodu sayfası 1250 veya daha büyük olduğunda varchar / char sütunlarında saklanabilir. Feryat sorgusu aşağıdakileri listeler:

SELECT COLLATIONPROPERTY(name, 'CodePage') AS code_page, name, description
FROM sys.fn_helpcollations()
WHERE COLLATIONPROPERTY(name, 'CodePage') >= 1250
ORDER BY name;

Ancak bunların yalnızca bir alt kümesi '©' karakterini de destekler, bu nedenle sütun harmanlamanın her ikisini de desteklemek için aşağıdakilerden biri olması gerekir:

SELECT COLLATIONPROPERTY(name, 'CodePage') AS code_page, name, description
FROM sys.fn_helpcollations()
WHERE COLLATIONPROPERTY(name, 'CodePage') IN(
    1250
    ,1251
    ,1252
    ,1253
    ,1254
    ,1255
    ,1256
    ,1257
    ,1258
)
ORDER BY name;

4

Ancak varchar'ın tanımı, unicode olmayan dize verilerine izin verdiğini söylüyor . Ancak Ticari Marka (™) ve Kayıtlı (®) sembolleri Unicode karakterlerdir . Tanım varchar veri tipinin özelliği ile çelişiyor mu?

Diğer cevaplar yanlış olmasa da, temel terminolojide bir karışıklığa dikkat çekmenin faydalı olacağını düşünüyorum. Bu karışıklığa örnek olarak yukarıdaki alıntıdaki iki kelimeyi sorudan vurguladım. SQL Server belgelerine Unicode ve Unicode olmayan bahseder zaman verilerine onlar vardır değil bahsediyoruz karakterler . Belirli karakterleri temsil eden bayt dizilerinden bahsediyorlar. Unicode türleri (arasındaki temel fark NCHAR, NVARCHAR, XMLve kullanımdan kaldırıldı / kötü NTEXT) ve Unicode olmayan türde ( CHAR, VARCHARve kullanımdan kaldırıldı / kötü TEXT) ne tür bayt dizileri de depolayabilir.

Unicode olmayan türler birkaç 8 bit kodlamadan birini depolarken Unicode türleri tek bir 16 bit Unicode kodlaması depolar: UTF-16 Little Endian. Diğer cevapların belirttiği gibi, hangi karakterler 8 bitlik / Unicode olmayan bir kodlamada saklanabilir, Harmanlama tarafından belirlenen kod sayfasına bağlıdır. Diğerleri, bir "karakterin" bayt değerinin bulunduğu kod sayfalarında değişebileceğini belirtmiş olsa da, bayt değeri birkaç EBCDIC kod sayfasından biriyle uğraşırken aynı kod sayfası içinde bile değişebilir (Windows- 1252) yalnızca eski sürümlerde bulunan SQL Server Harmanlamalarını gerçekten kullanmamalı (yani,SQL_ ).

Bu nedenle, tanım doğrudur: Unicode olmayan bir türde saklamak için yönetebileceğiniz karakterler her zaman 8 bittir (iki 8 bitlik değeri tek bir "karakter" olarak birlikte kullansalar bile, Bayt Karakter Kümesi / DBCS kod sayfaları izin verir). Ve Unicode veri türleri, bazen tek bir "karakter" olarak iki 16-bit değer kullansalar bile, her zaman 16 bittir (yani, bir Tamamlayıcı Karakteri temsil eden bir vekil çift).

AND, SQL Server'ın yerel olarak UTF-8 kodlamasını desteklemesi nedeniyle VARCHARveCHAR SQL Server 2019'dan veri türlerini ,

VARCHARartık "Unicode olmayan" olarak adlandırılamaz. Bu nedenle, Eylül 2018'de SQL Server 2019'un ilk herkese açık beta sürümünden başlayarak, SQL Server 2019'dan VARCHARönceki sürümler açısından konuşurken bile "8 bit veri türü" olarak adlandırmalıyız. Bu terminoloji 4 tip için de geçerlidir. ile kullanılabilen kodlamaların listesi VARCHAR:

  1. Genişletilmiş ASCII
  2. Çift Baytlı Karakter Kümeleri (DBCS)
  3. EBCDIC
  4. UTF-8 (Unicode)

Yalnızca TEXTveri türü (SQL Server 2005'ten itibaren kullanımdan kaldırılmıştır, bu nedenle kullanmayın) "Unicode olmayan" dır, ancak bu sadece bir tekniktir ve buna "8 bit veri türü" olarak atıfta bulunmak doğrudur.

NVARCHAR, NCHARve NTEXT"UTF-16" veya "16 bitlik veri türü" olarak adlandırılabilir. Oracle, inanıyorum ki, "yalnızca Unicode" terminolojisiniNVARCHAR , ancak bu, işe yaramayacak UTF-8 (ayrıca bir Unicode kodlaması) kullanma olasılığını açıkça göz ardı etmiyor, bu nedenle muhtemelen en iyisi ilk iki seçenek.

Yeni UTF-8 kodlamaları hakkında ayrıntılar için lütfen yazıma bakın:

SQL Server 2019'da Yerel UTF-8 Desteği: Kurtarıcı mı yoksa Sahte Peygamber?

PS Yavaş yavaş bu değişiklikleri yansıtmak için SQL Server belgelerini güncelleyerek yolumu çalışıyorum.

PPS Microsoft, soruda belirtilen char ve varchar belgeleri dahil olmak üzere bazı sayfaları UTF-8 bilgisiyle güncellemiştir . Artık "Unicode olmayan" ifadesini içermiyor. Ama bu sadece bir FYI; bu, yanlışlıkla yalnızca Unicode olduğu düşünülen karakterleri içeren Unicode olmayan kodlamalar ile ilgili olduğu için soruyu değiştirmez.


3

Soru Unicode'un ne olduğu hakkında merkezi bir yanlış anlama içeriyor. Unicode karakter seti, UTF-8 ve UTF-16 gibi kodlamaları ile birlikte, bir bilgisayardaki metni temsil etmenin birçok yolundan biridir ve amacı diğer tüm karakter setlerinin ve kodlamaların yerini almaktır. "Unicode olmayan veriler", "Unicode'da mevcut olmayan karakterler" anlamına geliyorsa, bu cevapta kullandığım metnin hiçbiri bu türde saklanamaz çünkü Latin alfabesinin tüm harfleri ve günlük İngilizcede kullanılan ortak noktalama işaretleri Unicode'a dahildir.

Metin gösterimleri genel olarak iki kısımda düşünülebilir: farklı karakterleri (harfler, rakamlar, semboller, vb.) Referans grafikteki sayılarla eşleştiren bir karakter kümesi ; ve bu sayıları bit kalıpları olarak gösteren bir kodlama (diskte, ağ bağlantısı üzerinden, vb.). Burada çoğunlukla ilk bölümle ilgileniyoruz: belirli bir karakter seti için grafiklerde hangi karakterlerin listelendiğini.

Unicode, dünyadaki her karakter için sayıları ("kod noktaları" olarak adlandırır) hedeflediğinden, Wikipedia gibi referanslar genellikle bir karakterin Unicode konumuna standart referans bilgi parçası olarak atıfta bulunur. Ancak bu, diğer karakter kümelerinin aynı karakter için bir eşleşmeye sahip olmadığı anlamına gelmez.

Halen kullanılmakta olan en eski ve en basit karakter setlerinden (ve kodlamalardan) biri 128 farklı karakter (0 ila 127) için eşlemeleri olan ASCII'dir, çünkü her karakteri kodlamak için 7 bit kullanır. Bu, birçok aksanlı karakteri ve ortak simgeleri içermediğinden, daha sonra kodlamalar 8 bit kullanır ve 128 ila 255 konumlarını doldurarak karakter kümesine ekleyerek aynı ilk 128 karakteri eşleştirir. Bunlar arasında standart ISO 8859-1 ve ISO 8859- 15 ve Microsoft'a özgü Windows Kodu .

Bir saklanan gibi bir "Unicode dizesi": Yani, MS SQL Server için geri gelmek nchar, nvarcharya da ntexttemsil edebilir, sütun tüm bu verileri depolamak için kodlayan bir Unicode kullanır, çünkü Unicode karakter setinde eşlenen karakterleri. Bir "Unicode olmayan dize" gibi bir saklanan char, varcharya textsütununda eşlenen sadece karakterleri temsil edebilir diğer bazı kodlama . Unicode olmayan bir sütunda depolayabileceğiniz her şey bir Unicode sütununda da saklanabilir, ancak bunun tersi de mümkün değildir.

Tam olarak hangi karakterleri saklayabileceğinizi bilmek için , bu Microsoft başvuru sayfasında açıklandığı gibi, Microsoft'un "kod sayfası" olarak adlandırdığı şeyi belirten "harmanlama" yı bilmeniz gerekir . Sizin durumunuzda, daha önce bahsettiğim çok yaygın Kod'u kullanmanız muhtemeldir.

Bahsettiğiniz karakterler hem Unicode hem de Kod'da bulunur:

  • Ticari marka (™) 8482 konumundaki Unicode'da ve 153 konumundaki CP1252'de görünür
  • Kayıtlı (®) olduğu gibi, 174 konumunda hem Unicode hem de CP1252'de görünür

3
“Unicode, bilgisayarda kullanılmak üzere metin kodlamanın birçok yolundan biridir” - Bu doğru değil. Unicode, her karakterin kendine özgü bir kod noktasına sahip olduğu bir karakter ve sembol koleksiyonudur . Daha sonra bir kodlamanın işi bu kod noktalarını bir bayt dizisiyle eşleştirmektir. UTF-8 ve UTF-16 kodlamalarıdır, Unicode değildir.
dürtmek

@poke Cevaba daha fazla değindiğimde, hem "karakterlerin bir grafikteki konumlarla eşlenmesini" hem de "bu konumların bir bit dizisi olarak temsillerini" temsil etmek için "kodlama" kullanıyorum. Belki kullanmak için daha iyi bir terim vardır, ama bunun ne olacağından emin değilim.
IMSoP

3
"Kodlamayı" kendi tanımınızla kullanamazsınız. Burada çürüttüğüm için üzgünüm, ancak “soru Unicode'un ne olduğu hakkında merkezi bir yanlış anlama içeriyor” şeklinde açılan bir cevapta bunu yapamazsınız .
dürtmek

2
IMSoP (ve @poke): Ben de IMSoP ikilemine sempati duyuyorum, ancak kodlama dışında bir şey ifade etmek için "kodlama" kullanma aşırı tepki konusunda tamamen katılıyorum. Benim tercihim Unicode'u birden fazla kodlamaya sahip bir karakter seti olarak ifade etmek, oysa tipik olarak karakter seti ve kodlama çoğu zaman (1 ya da 1?) Bir ilişki olması nedeniyle birbirinin yerine kullanılabilir.
Solomon Rutzky

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.