テーブル行の「CO2」を「CO₂」に更新できません


19

この表が与えられた場合:

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

(1 affected rows)

(1 affected rows)

id          description
----------- -----------
1           CO2

(1 affected rows)

は明らかに小さな2であるため、最終的な値は変わらないため、変更する価値がないとSQL Serverが判断したかのようです。

誰かがこれに少し光を当てて、回避策を提案することができますか(中間値に更新する以外)?


1
アルバロ:この動作について詳しく知りたい場合は、なぜこのようなことが起こったのかをよりよく理解するために、答えの最後に追加した2つのリンクを参照してください。
ソロモンラツキー

回答:


29

下付き文字2は、varchar文字セットの一部ではありません(どの照合でも、Modern_Spanishだけではありません)。したがって、nvarchar定数にします。

UPDATE test SET description = N'CO₂' WHERE id = 1;

1
値を修正しただけでなく、そもそもどうやってそこに到達したかを理解しました。ありがとうございました!
アルバロゴンサレス

2
@ÁlvaroGonzálezand gbn:明確にするために、「Subscript 2」は、列の照合ではなく、文字列リテラルと変数に使用される照合である、問題のデータベースのデフォルト照合で指定されたコードページでは使用できません同じコードページを使用している可能性があります)。ただし、「添字2」は、韓国語照合を介してコードページ949で利用できます。ここでは役に立ちませんが、参考にしてください。私の答えには詳細と例があります
ソロモンラツキー

21

@gbnはすでに基本的な理由と修正を説明しましたが、あなたが見ている振る舞いの特定の理由はこれです:

  1. あなたは、使用しているVARCHARリテラル(なしN接頭辞)の代わりに、NVARCHARリテラル(文字列とNプレフィックス)、したがって、Unicode文字を変換しまいますがVARCHAR
  2. VARCHARほとんどの場合、文字ごとに1バイトですが、文字ごとに2バイトにすることもできます。一方、NVARCHAR16ビットエンコーディング(UTF-16リトルエンディアン)は、1文字あたり2バイトまたは4バイトです。
  3. 文字のマッピングに使用できる使用可能なバイト数の違いにより、8ビットエンコーディングは、その性質上、マッピングできる文字数がはるかに制限されています。VARCHARデータは、シングルバイト文字セット(それらの大部分)で最大256文字、ダブルバイト文字セット(これらのほんの一部)で最大65,536文字です。一方、NVARCHARデータは110万個を超えるUnicode文字をマップできます(ただし、現在マップされているのは250k未満です)。
  4. 8ビット/ VARCHARデータで実行できるマッピングの数が限られているため、さまざまな文字グループ(言語/文化に基づく)が複数の「コードページ」(つまり文字セット)に分散しています
  5. 各照合順序は、VARCHARデータに使用するコードページ(ある場合)を指定します(NVARCHARすべての文字です)
  6. 文字列リテラルまたは変数をNVARCHAR(つまり、Unicode / UTF-16 /すべての文字)からVARCHAR(ほとんどの照合で指定されるコードページに基づく文字セット)に変換する場合、データベースのデフォルト照合が使用されます
  7. 変換に使用される照合のコードページに同じ文字が含まれておらず、「最適な」マッピングが含まれている場合、「最適な」マッピングが使用されます。
  8. 変換に使用される照合のコードページに同じ文字が含まれていないか、「最適な」マッピングが含まれていない場合、デフォルトの「置換」文字が使用されます(最も一般的?)。

だから、何を見ていることはあるNVARCHARVARCHAR欠落が原因への変換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_SpanishVARCHARデータにコードページ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₂

更新

何について詳しく調べることに興味を持っている人のために、正確にここで起こっている(つまり、血みどろの詳細のすべて)、私はちょうど掲示二部調査を参照してください。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.