@ gbn sudah menjelaskan alasan dasar dan memperbaikinya, tetapi alasan spesifik untuk perilaku yang Anda lihat adalah ini:
- Anda menggunakan
VARCHAR
literal (tanpa N
awalan) alih-alih NVARCHAR
literal (string dengan N
awalan), maka karakter Unicode akan dikonversi menjadi VARCHAR
.
VARCHAR
adalah pengkodean 8-bit yang, dalam banyak kasus, satu byte per karakter, tetapi juga bisa dua byte per karakter. Di sisi lain, NVARCHAR
adalah penyandian 16-bit (UTF-16 Little Endian) yang terdiri dari dua byte atau empat byte per karakter.
- Karena perbedaan jumlah byte yang tersedia untuk digunakan untuk memetakan karakter, pengkodean 8 bit, pada dasarnya, jauh lebih terbatas dalam jumlah karakter yang dapat dipetakan.
VARCHAR
data hingga 256 karakter untuk Set Karakter Byte Tunggal (mayoritasnya) dan hingga 65.536 karakter untuk Set Karakter Byte Ganda (hanya beberapa di antaranya). Di sisi lain, NVARCHAR
data dapat memetakan lebih dari 1,1 juta karakter Unicode (meskipun hanya di bawah 250 ribu yang saat ini dipetakan).
- Karena terbatasnya pemetaan yang dapat dilakukan dengan 8-bit /
VARCHAR
data, pengelompokan karakter yang berbeda (berdasarkan Bahasa / Budaya) tersebar di beberapa "Halaman Kode" (yaitu set karakter)
- Setiap Kolasi menentukan Halaman Kode mana, jika ada, yang akan digunakan untuk
VARCHAR
data ( NVARCHAR
semuanya karakter)
- Ketika mengkonversi string literal atau variabel dari
NVARCHAR
(yaitu Unicode / UTF-16 / semua karakter) ke VARCHAR
(set karakter berdasarkan Halaman Kode yang ditentukan dalam kebanyakan Collations), Collation default dari Database digunakan
- Jika Halaman Kode Koleksi yang digunakan untuk konversi tidak mengandung karakter yang sama, tetapi berisi pemetaan "paling cocok", maka pemetaan "paling cocok" akan digunakan.
- Jika Halaman Kode Koleksi yang digunakan untuk konversi tidak mengandung karakter yang sama atau berisi pemetaan "paling cocok", maka karakter "pengganti" default akan digunakan (paling umum
?
).
Jadi, apa yang Anda lihat adalah NVARCHAR
untuk VARCHAR
konversi karena hilang N
awalan pada literal string yang. Dan, Halaman Kode dari Collation default untuk Database tidak mengandung karakter yang sama persis, tetapi pemetaan "paling cocok" ditemukan, itulah sebabnya Anda mendapatkan 2
alih - alih a ?
.
Anda dapat melihat efek ini dengan melakukan tes sederhana berikut:
SELECT '₂', N'₂';
Pengembalian:
2 ₂
Agar lebih jelas, JIKA Halaman Kode dari Collation default untuk Database memang mengandung karakter yang sama persis, maka itu akan diterjemahkan ke dalam karakter yang sama di Halaman Kode itu. Dan, kemudian, dalam kasus Anda, karena Anda menyimpan ke dalam NVARCHAR
kolom, itu akan diterjemahkan lagi, kembali ke karakter Unicode yang asli. Contoh terakhir di bawah ini menunjukkan perilaku ini.
PENTING: Harap perhatikan bahwa konversi terjadi ketika string literal sedang ditafsirkan, yang sebelum disimpan ke dalam kolom. Ini berarti bahwa bahkan jika kolom dapat menampung karakter itu, itu akan telah dikonversi menjadi sesuatu yang lain, berdasarkan Basis Data default Basis Data, semua karena meninggalkan N
awalan pada string literal itu. Dan ini persis seperti apa yang Anda (atau sedang) alami.
Misalnya, jika Collation default dari Database Anda akan menjadi salah satu Collations Korea (salah satu dari empat Set Karakter Double-Byte), maka Anda tidak akan melihat masalah ini karena karakter "Subskrip 2" tersedia dalam karakter itu set (Kode Halaman 949). Coba tes berikut untuk melihat (menggunakan Collation of the kolom daripada Collation default di Database karena lebih mudah ditampilkan):
CREATE TABLE #TestChar
(
[8bit_Latin1_General-1252] VARCHAR(2) COLLATE Latin1_General_100_CI_AS_SC,
[8bit_Korean-949] VARCHAR(2) COLLATE Korean_100_CI_AS_SC,
[UTF16LE_Latin1_General-1252] NVARCHAR(2) COLLATE Latin1_General_100_CI_AS_SC
);
INSERT INTO #TestChar VALUES (N'₂', N'₂', N'₂');
SELECT * FROM #TestChar;
Pengembalian:
8bit_Latin1_General-1252 8bit_Korean-949 UTF16LE_Latin1_General-1252
2 ₂ ₂
Seperti yang dapat Anda lihat, Latin1_General Collations, yang menggunakan Code Page 1252 (Halaman Code yang sama yang Modern_Spanish
digunakan Collations) untuk VARCHAR
data, tidak memiliki kecocokan persis, tetapi mereka memiliki pemetaan "paling cocok" (yang Anda lihat) ). TAPI, Koleksi Korea, yang menggunakan Kode untuk VARCHAR
data, memiliki kecocokan yang tepat untuk karakter "Subskrip 2".
Untuk mengilustrasikan lebih lanjut, kita dapat membuat Database baru dengan Collation default dari salah satu Collations Korea, dan kemudian menjalankan SQL yang ada dalam pertanyaan:
CREATE DATABASE [TestKorean-949] COLLATE Korean_100_CI_AS_KS_WS_SC;
ALTER DATABASE [TestKorean-949] SET RECOVERY SIMPLE;
GO
USE [TestKorean-949];
CREATE TABLE test (
id INT NOT NULL,
description NVARCHAR(100) COLLATE Modern_Spanish_CI_AS NOT NULL
);
INSERT INTO test (id, description) VALUES (1, 'CO2');
SELECT * FROM test WHERE id = 1;
UPDATE test SET description = 'CO₂' WHERE id = 1;
SELECT * FROM test WHERE id = 1;
Pengembalian:
id description
1 CO2
id description
1 CO₂
MEMPERBARUI
Bagi siapa saja yang tertarik untuk mencari tahu lebih banyak tentang apa sebenarnya yang terjadi di sini (yaitu semua detail berdarah), silakan lihat penyelidikan dua bagian yang baru saja saya posting: