Mengapa datatype varchar memungkinkan nilai unicode?


17

Saya punya meja dengan kolom varchar. Ini memungkinkan Merek Dagang (™), hak cipta (©) dan karakter Unicode lainnya seperti yang ditunjukkan di bawah ini.

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

Tetapi definisi varchar mengatakan, ini memungkinkan data string non-unicode. Tetapi simbol-simbol Merek Dagang (™) dan Terdaftar (®) adalah karakter Unicode . Apakah definisi tersebut bertentangan dengan properti dari tipe data varchar? Saya membaca beberapa tautan seperti yang pertama dan yang kedua . Tapi tetap saya tidak bisa mengerti mengapa itu memungkinkan string unicode ketika definisi mengatakan bahwa itu hanya memungkinkan nilai-nilai string non-unicode.


12
Semua karakter adalah karakter Unicode.
Martin Smith

Microsoft sering menggunakan UNICODE ketika mereka berarti UTF-16 / UCS-2. Jadi mereka bahkan mungkin tidak menghitung UTF-8 karena UNICODE adalah beberapa konteks.
CodesInChaos

1
@CodesInChaos: Saya kesulitan mengurai komentar Anda, tapi saya khawatir Anda membingungkan Unicode dengan berbagai pengkodean UTF-n.
Lightness Races dengan Monica

1
@ Martin Smith: Jika semua karakter adalah karakter Unicode, maka mengapa microsoft definisi varchar mengatakan bahwa hal itu memungkinkan data string non-Unicode?
Shiva

2
penyandian untuk karakter dalam varchar bukan unicode tetapi semua karakter ada di unicode
Martin Smith

Jawaban:


15

Tetapi simbol-simbol Merek Dagang (™) dan Terdaftar (®) adalah karakter Unicode.

Anda salah di sini. String Anda hanya berisi asciikarakter.

Berikut ini adalah tes sederhana yang menunjukkan kepada Anda bahwa karakter Anda semuanya ascii (+ beberapa extended asciidengan kode ascii antara 128 dan 255):

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;

Di sini Anda dapat dengan jelas melihat bahwa semua karakter Anda dikodekan 1-byte:

masukkan deskripsi gambar di sini

Ya mereka bukan karakter ascii murni tetapi mereka Extended ASCII .

Di sini saya menunjukkan kepada Anda karakter unicode yang nyata Trademark(™)beserta kode dan representasi binernya:

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;

masukkan deskripsi gambar di sini

Akhirnya, Anda dapat melihat bahwa Trademark(™)karakter unicode memiliki 8482 kode dan bukan 153:

select nchar(8482), nchar(153)

1
Tetapi tidak ada kata "ASCII" dalam artikel yang Anda sebutkan, mereka berbicara tentang karakter unicode dan non-unicode saja, dan Trademark (™) yang Anda gunakan bukan unicode.
sepupic

16
"Extended ASCII" adalah istilah yang sangat ambigu. Akan lebih membantu untuk melihat encoding 8-bit apa yang sebenarnya digunakan (apakah ini didasarkan pada pengaturan lokal / susun?). Saya menebak kode Windows halaman 1252 , yang memang mengkodekan ™ sebagai karakter 153.
IMSoP

2
@supupic Saya pikir Anda perlu membaca lebih lanjut tentang perbedaan antara codepoint dan pengkodean. Wikipedia dapat membantu. "Sebuah peta penyandian (mungkin subset dari) kisaran kode Unicode menunjuk ke urutan nilai dalam beberapa rentang ukuran tetap, disebut nilai kode ." 8482 adalah titik kode untuk ™, yang dapat dikodekan sebagai \ x99 (153) di Windows-1252, sebagai \ xAA di MacRoman, sebagai \ xE2 \ x84 \ xA2 di UTF-8, dll.
curiousdannii

7
Perhatian harus diberikan dengan karakter 8-bit di atas 127: apa yang diwakili oleh masing-masing kode di atas 127 dapat dan akan berubah tergantung pada penyandian yang digunakan yang akan bervariasi tergantung pada susunan mana yang digunakan. Dalam codepage 1252 unicode 8482 dipetakan ke 153. Dalam codepage 850 tempat itu diambil oleh 214 ( Ö) dan dalam ISO-8859-1 (kadang-kadang disebut Latin1) itu adalah kode kontrol tanpa representasi yang dapat dicetak. Kecuali Anda tahu Anda akan selalu menggunakan codepage yang sama, lebih aman untuk tetap menggunakan karakter ANSI (127 atau kurang) atau menggunakan tipe Unicode. Codepage 1252 paling umum di SQL Server tetapi jauh dari mana-mana.
David Spillett

4
@ Shiva Minimum Mutlak Setiap Pengembang Perangkat Lunak Sepenuhnya, Positif Harus Tahu Tentang Unicode dan Set Karakter . ASCII adalah bagian dari banyak pengkodean, dan hampir semua pengkodean itu mengandung simbol-simbol non-ASCII dan secara bersamaan bukan Unicode. Dan Unicode juga memiliki banyak pengkodean yang berbeda (seperti UTF-8, UTF-32, dll.).
jpmc26

7

Dari komentar, saya setuju "Extended ASCII" adalah istilah yang benar-benar buruk yang sebenarnya berarti halaman kode yang memetakan karakter / titik kode dalam kisaran 128-255, di luar rentang titik kode 0-127 standar yang ditentukan oleh ASCII.

SQL Server mendukung banyak halaman kode melalui collations. Karakter non-ASCII dapat disimpan dalam varchar selama susunan yang mendasarinya mendukung karakter tersebut.

Karakter '™' dapat disimpan dalam kolom varchar / char ketika halaman kode SQL Server 1250 atau lebih besar. Kueri di bawah ini akan mencantumkan ini:

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

Tetapi hanya sebagian dari ini yang juga mendukung karakter '©' sehingga susunan kolom perlu menjadi salah satu dari yang berikut untuk mendukung keduanya:

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

Tetapi definisi varchar mengatakan, ini memungkinkan data string non-unicode . Tetapi simbol-simbol Merek Dagang (™) dan Terdaftar (®) adalah karakter Unicode . Apakah definisi tersebut bertentangan dengan properti dari tipe data varchar?

Sementara jawaban lain tidak salah, saya pikir akan membantu untuk menunjukkan kebingungan dalam terminologi dasar. Saya telah menekankan dua kata dalam kutipan di atas dari pertanyaan sebagai contoh dari kebingungan ini. Ketika dokumentasi SQL Server berbicara tentang Unicode dan non-Unicode Data , mereka tidak berbicara tentang karakter . Mereka berbicara tentang urutan byte yang mewakili karakter tertentu. Perbedaan utama antara jenis Unicode ( NCHAR, NVARCHAR, XML, dan usang / jahat NTEXT) dan jenis non-Unicode ( CHAR, VARCHAR, dan usang / jahat TEXT) adalah apa jenis urutan byte mereka dapat menyimpan.

Jenis non-Unicode menyimpan salah satu dari beberapa pengkodean 8-bit, sedangkan jenis Unicode menyimpan pengodean Unicode 16-bit tunggal: UTF-16 Little Endian. Seperti jawaban lain yang disebutkan, karakter mana yang dapat disimpan dalam pengkodean 8-bit / non-Unicode tergantung pada halaman kode, yang ditentukan oleh Collation. Sementara yang lain telah mencatat bahwa nilai byte dari "karakter" dapat bervariasi di seluruh halaman kode yang ditemukan, nilai byte bahkan dapat bervariasi dalam halaman kode yang sama ketika berhadapan dengan salah satu dari beberapa halaman kode EBCDIC (variasi Windows- 1252), yang hanya ditemukan di SQL Server Collations yang lebih lama, yang seharusnya tidak benar-benar digunakan (yaitu yang memiliki nama yang dimulai dengan SQL_).

Oleh karena itu, definisi tersebut akurat: karakter apa pun yang dapat Anda kelola untuk disimpan dalam tipe non-Unicode selalu 8-bit (bahkan jika mereka menggunakan dua nilai 8-bit dalam kombinasi sebagai "karakter" tunggal, yang merupakan apa yang Double- Halaman Byte Character Set / DBCS memungkinkan untuk). Dan tipe data Unicode selalu 16-bit, bahkan jika mereka kadang-kadang menggunakan dua nilai 16-bit dalam kombinasi sebagai "karakter" tunggal (yaitu pasangan pengganti yang pada gilirannya mewakili Karakter Tambahan).

DAN, karena SQL Server secara native mendukung pengkodean UTF-8 untuk VARCHARdan CHARtipe data pada SQL Server 2019,

VARCHARtidak dapat lagi disebut sebagai "non-Unicode". Jadi, dimulai dengan beta publik pertama dari SQL Server 2019 pada September 2018, kita harus merujuk VARCHARsebagai "datatype 8-bit", bahkan ketika berbicara dalam hal versi sebelum SQL Server 2019. Terminologi ini berlaku untuk semua 4 jenis pengkodean yang dapat digunakan dengan VARCHAR:

  1. Extended ASCII
  2. Set Karakter Double-Byte (DBCS)
  3. EBCDIC
  4. UTF-8 (Unicode)

Hanya TEXTtipe data (tidak digunakan pada SQL Server 2005, jadi jangan gunakan) adalah "non-Unicode", tapi itu hanya teknis, dan menyebutnya sebagai "8-bit datatype" yang akurat.

NVARCHAR,, NCHARdan NTEXTdapat disebut sebagai "UTF-16" atau "tipe data 16-bit". Oracle, saya percaya, menggunakan terminologi "Unicode-only" untuk NVARCHAR, tetapi itu tidak dengan jelas mengesampingkan kemungkinan menggunakan UTF-8 (juga enkode Unicode), yang tidak akan berfungsi, jadi mungkin yang terbaik untuk tetap menggunakan dua opsi pertama.

Untuk detail tentang pengkodean UTF-8 baru, silakan lihat posting saya:

Dukungan UTF-8 Asli di SQL Server 2019: Juruselamat atau Nabi Palsu?

PS Saya perlahan-lahan bekerja dengan cara saya memperbarui dokumentasi SQL Server untuk mencerminkan perubahan ini.

PPS Microsoft telah memperbarui beberapa halaman dengan info UTF-8, termasuk dokumentasi char dan varchar yang dirujuk dalam pertanyaan. Itu tidak lagi mengandung frasa "non-Unicode". Tapi itu hanya FYI; itu tidak mengubah pertanyaan karena ini adalah tentang pengkodean non-Unicode yang mengandung karakter yang keliru dianggap hanya Unicode.


3

Pertanyaannya berisi kesalahpahaman sentral tentang apa itu Unicode. Set karakter Unicode, bersama dengan penyandiannya seperti UTF-8 dan UTF-16, adalah salah satu dari banyak cara untuk merepresentasikan teks dalam komputer, dan yang tujuannya adalah untuk menggantikan semua set dan penyandian karakter lainnya. Jika "data non-Unicode" berarti "karakter yang tidak ada dalam Unicode", maka tidak ada teks yang saya gunakan dalam jawaban ini yang dapat disimpan dalam jenis itu, karena semua huruf dalam alfabet Latin dan tanda baca umum yang digunakan dalam bahasa Inggris sehari-hari adalah termasuk dalam Unicode.

Representasi teks secara luas dapat dipikirkan dalam dua bagian: satu set karakter memetakan karakter yang berbeda (huruf, angka, simbol, dll) ke angka pada grafik referensi; dan pengkodean yang mewakili angka-angka tersebut sebagai pola bit (pada disk, melalui koneksi jaringan, dll). Di sini kita sebagian besar memusatkan perhatian pada bagian pertama: karakter mana yang terdaftar pada bagan untuk rangkaian karakter tertentu.

Karena Unicode bertujuan untuk memiliki angka (yang disebut "titik kode") untuk setiap karakter di dunia, referensi seperti Wikipedia akan sering merujuk pada posisi Unicode karakter sebagai informasi referensi standar. Namun, itu tidak berarti bahwa rangkaian karakter lain tidak juga memiliki pemetaan untuk karakter yang sama.

Salah satu set karakter tertua dan paling sederhana (dan penyandian) yang masih digunakan adalah ASCII, yang memiliki pemetaan untuk 128 karakter berbeda (0 hingga 127), karena menggunakan 7 bit untuk mengkodekan setiap karakter. Karena ini tidak termasuk banyak karakter beraksen dan simbol umum, pengkodean selanjutnya menggunakan 8 bit, dan memetakan 128 karakter pertama yang sama, menambah set karakter dengan mengisi posisi 128 hingga 255. Yang paling penting di antaranya adalah standar ISO 8859-1 dan ISO 8859- 15 , dan Kode Windows spesifik Microsoft .

Jadi, untuk kembali ke MS SQL Server: a "Unicode string", sebagai disimpan dalam nchar, nvarcharatau ntextkolom, dapat mewakili semua karakter dipetakan dalam set karakter Unicode, karena menggunakan Unicode encoding untuk menyimpan data. Sebuah "non-Unicode string", yang disimpan dalam char, varcharatau textkolom, dapat hanya mewakili karakter dipetakan dalam beberapa pengkodean lainnya . Apa pun yang dapat Anda simpan di kolom non-Unicode juga dapat disimpan dalam kolom Unicode, tetapi tidak sebaliknya.

Untuk mengetahui persis karakter mana yang dapat Anda simpan, Anda perlu mengetahui "susunan" yang digunakan, yang menentukan apa yang disebut Microsoft sebagai "halaman kode", seperti yang dijelaskan pada halaman referensi Microsoft ini . Mungkin dalam kasus Anda bahwa Anda menggunakan Kode yang sangat umum, yang saya sebutkan sebelumnya.

Karakter yang Anda sebutkan ada di Unicode dan Code Page 1252:

  • Merek Dagang (™) muncul di Unicode di posisi 8482, dan di CP1252 di posisi 153
  • Terdaftar (®), seperti yang terjadi, muncul di Unicode dan CP1252 di posisi 174

3
“Unicode adalah salah satu dari banyak cara penyandian teks untuk digunakan di komputer” - Itu tidak benar. Unicode hanyalah kumpulan karakter dan simbol, di mana setiap karakter memiliki titik kode uniknya sendiri yang hanya berupa angka. Tugas pengkodean kemudian untuk mencocokkan titik-titik kode itu dengan urutan byte. UTF-8 dan UTF-16 adalah penyandian, Unicode tidak.
aduk

@ aduk Ketika saya melanjutkan untuk mengatakan lebih lanjut dalam jawaban, saya menggunakan "pengodean" di sini untuk mewakili "pemetaan karakter ke posisi pada grafik" dan "representasi posisi-posisi itu sebagai urutan bit". Mungkin ada istilah yang lebih baik untuk digunakan, tetapi saya tidak yakin akan seperti apa.
IMSoP

3
Nah, Anda tidak bisa hanya menggunakan "encoding" dengan definisi Anda sendiri. Maaf untuk melakukan nitpicking di sini, tetapi Anda tidak dapat melakukannya dalam jawaban yang terbuka dengan "pertanyaan berisi kesalahpahaman sentral tentang apa itu Unicode" .
aduk

2
IMSoP (dan @poke): Saya sepenuhnya setuju dengan menyodok tentang jangkauan berlebihan menggunakan "encoding" berarti sesuatu selain encoding, meskipun saya juga bersimpati dengan dilema IMSoP. Preferensi saya adalah merujuk ke Unicode sebagai rangkaian karakter yang memiliki banyak pengkodean, sedangkan biasanya rangkaian karakter dan pengkodean digunakan secara bergantian karena hubungan 1-ke-1 paling banyak (atau mungkin semua?) Pada saat itu.
Solomon Rutzky

2
Jawaban yang bagus. Saya sangat merekomendasikan untuk menambahkan tautan ke The Absolute Minimum Setiap Pengembang Perangkat Lunak Sepenuhnya, Pasti Harus Tahu Tentang Unicode dan Karakter Set di sana.
jpmc26
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.