@gbnはすでに基本的な理由と修正を説明しましたが、あなたが見ている振る舞いの特定の理由はこれです:
- あなたは、使用している
VARCHAR
リテラル(なしN
接頭辞)の代わりに、NVARCHAR
リテラル(文字列とN
プレフィックス)、したがって、Unicode文字を変換しまいますがVARCHAR
。
VARCHAR
ほとんどの場合、文字ごとに1バイトですが、文字ごとに2バイトにすることもできます。一方、NVARCHAR
16ビットエンコーディング(UTF-16リトルエンディアン)は、1文字あたり2バイトまたは4バイトです。
- 文字のマッピングに使用できる使用可能なバイト数の違いにより、8ビットエンコーディングは、その性質上、マッピングできる文字数がはるかに制限されています。
VARCHAR
データは、シングルバイト文字セット(それらの大部分)で最大256文字、ダブルバイト文字セット(これらのほんの一部)で最大65,536文字です。一方、NVARCHAR
データは110万個を超えるUnicode文字をマップできます(ただし、現在マップされているのは250k未満です)。
- 8ビット/
VARCHAR
データで実行できるマッピングの数が限られているため、さまざまな文字グループ(言語/文化に基づく)が複数の「コードページ」(つまり文字セット)に分散しています
- 各照合順序は、
VARCHAR
データに使用するコードページ(ある場合)を指定します(NVARCHAR
すべての文字です)
- 文字列リテラルまたは変数を
NVARCHAR
(つまり、Unicode / UTF-16 /すべての文字)からVARCHAR
(ほとんどの照合で指定されるコードページに基づく文字セット)に変換する場合、データベースのデフォルト照合が使用されます
- 変換に使用される照合のコードページに同じ文字が含まれておらず、「最適な」マッピングが含まれている場合、「最適な」マッピングが使用されます。
- 変換に使用される照合のコードページに同じ文字が含まれていないか、「最適な」マッピングが含まれていない場合、デフォルトの「置換」文字が使用されます(最も一般的
?
)。
だから、何を見ていることはあるNVARCHAR
のVARCHAR
欠落が原因への変換N
、文字列リテラルの接頭辞を。また、データベースの既定の照合順序のコードページにはまったく同じ文字が含まれていませんが、「最適な」マッピングが見つかったため、の2
代わりにを取得してい?
ます。
この効果は、次の簡単なテストを実行することで確認できます。
SELECT '₂', N'₂';
戻り値:
2 ₂
明確にするために、データベースの既定の照合のコードページにまったく同じ文字が含まれていた場合、そのコードページでは同じ文字に変換されていました。そして、あなたの場合、NVARCHAR
列に格納しているので、元のUnicode文字に再び変換されます。以下の最後の例は、この動作を示しています。
重要:文字列リテラルが解釈されるときに変換が行われることに注意してください。これは、列に格納される前です。これは、列がその文字を保持できる場合でも、データベースのデフォルトの照合に基づいて、N
その文字列リテラルのプレフィックスを省略することにより、すでに他の何かに変換されていることを意味します。そして、これはまさにあなたが経験している(または経験していた)ものです。
たとえば、データベースのデフォルトの照合が韓国語照合の1つ(4つの2バイト文字セットの1つ)である場合、「Subscript 2」文字がその文字で使用可能なため、この問題は発生しません。設定(コードページ949)。次のテストを試してみてください(表示しやすいように、データベースのデフォルトの照合の代わりに列の照合を使用します)。
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;
戻り値:
8bit_Latin1_General-1252 8bit_Korean-949 UTF16LE_Latin1_General-1252
2 ₂ ₂
ご覧のとおりModern_Spanish
、VARCHAR
データにコードページ1252(照合が使用するのと同じコードページ)を使用するLatin1_General照合は完全に一致していませんが、「最適な」マッピング(表示されているもの)があります。 )。ただし、VARCHAR
データにコードページ949を使用する韓国語照合は、「下付き文字2」文字に完全に一致します。
さらに説明するために、韓国語の照合順序のいずれかの既定の照合順序で新しいデータベースを作成し、問題のある正確なSQLを実行できます。
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;
戻り値:
id description
1 CO2
id description
1 CO₂
更新
何について詳しく調べることに興味を持っている人のために、正確にここで起こっている(つまり、血みどろの詳細のすべて)、私はちょうど掲示二部調査を参照してください。