web-dev-qa-db-ja.com

varcharデータ型がUnicode値を許可するのはなぜですか?

Varchar列のあるテーブルがあります。以下に示すように、Trademark(™)、copyright(©)およびその他のUnicode文字を許可しています。

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

しかし、 varcharの定義 は、非Unicode文字列データを許可することを示しています。ただし、Trademark(™)およびRegistered(®)の記号は nicode 文字です。定義はvarcharデータ型のプロパティと矛盾しますか? first onesecond one のようなリンクをいくつか読んだ。しかし、それでも非ユニコード文字列値のみを許可するという定義で定義されているのに、なぜユニコード文字列が許可されるのか理解できませんでした。

17
Shiva

ただし、Trademark(™)およびRegistered(®)の記号はUnicode文字です。

あなたはここで間違っています。文字列にはascii文字のみが含まれています。

以下は、文字がすべてASCIIである(+いくつかの_extended ascii_で、128〜255のASCIIコード)であることを示す簡単なテストです。

_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;
_

ここで、すべての文字が1バイトでエンコードされていることがはっきりとわかります。

enter image description here

はい、それらは純粋なASCII文字ではありませんが、 拡張ASCII です。

ここでは、実際のユニコード文字Trademark(™)と、そのコードおよびバイナリ表現を示します。

_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;
_

enter image description here

最後に、ユニコード文字Trademark(™)には153ではなく8482コードがあることがわかります。

_select nchar(8482), nchar(153)
_
15
sepupic

コメントから、「拡張ASCII」は本当に悪い用語であり、ASCIIで定義された標準の0-127コードポイント範囲を超えて、128-255の範囲の文字/コードポイントを実際にマップするコードページを意味することに同意します。

SQL Serverは、照合を介して多くのコードページをサポートします。非ASCII文字は、基礎となる照合が文字をサポートしている限り、varcharに格納できます。

'™'文字は、SQL Server照合コードページが1250以上の場合、varchar/char列に格納できます。以下のクエリはこれらをリストします:

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

ただし、これらのサブセットのみが「©」文字もサポートするため、列の照合順序は、両方をサポートする次のいずれかである必要があります。

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;
7
Dan Guzman

しかし、varcharの定義では、非Unicode文字列dataが許可されています。ただし、Trademark(™)およびRegistered(®)の記号はUnicode文字です。定義はvarcharデータ型のプロパティと矛盾しますか?

他の答えは不正確ではありませんが、基本用語の混乱を指摘するのに役立つと思います。この混乱の例として、質問からの引用の2つの単語を強調しました。 SQL ServerのドキュメントでUnicodeと非Unicodedataについて言及している場合、それらはではない文字。彼らは特定の文字を表すバイトシーケンスについて話している。 Unicodeタイプ(NCHARNVARCHARXML、および非推奨/悪NTEXT)と非Unicodeタイプ(CHARVARCHAR、および非推奨/悪TEXT)は、それらが格納できるバイトシーケンスのtypesです。

非Unicode型はいくつかの8ビットエンコーディングの1つを格納しますが、Unicode型は単一の16ビットUnicodeエンコーディングであるUTF-16リトルエンディアンを格納します。他の回答が述べたように、どの文字が8ビット/非Unicodeエンコードで格納できるかは、照合によって決定されるコードページによって異なります。他の人は、「文字」のバイト値が見つかったコードページ間で異なる可能性があることを指摘しましたが、複数のEBCDICコードページの1つ(Windowsのバリエーション) 1252)は、古いバージョンでのみ使用されているため、SQL Serverの照合順序(つまり、名前がSQL_で始まるもの)を実際に使用しないでください。

したがって、定義は正確です。Unicode以外のタイプに格納できる文字はすべて8ビットです(2つの8ビット値を1つの「文字」として組み合わせて使用​​する場合でも、これはDouble-バイト文字セット/ DBCSコードページで可能です)。また、Unicodeデータ型は常に2つの16ビット値を1つの「文字」(つまり、サプリゲート文字を表すサロゲートペア)として組み合わせて使用​​する場合でも、常に16ビットです。

さらに、SQL Server 2019では、SQL ServerがVARCHARおよびCHARデータ型のUTF-8エンコーディングをネイティブでサポートしているため、

VARCHARを「非Unicode」と呼ぶことはできなくなりました。したがって、2018年9月のSQL Server 2019の最初のパブリックベータ版から、SQL Server 2019より前のバージョンの用語で話す場合でも、VARCHARを「8ビットデータ型」と呼ぶ必要があります。この用語VARCHARで使用できる4種類のエンコーディングすべてに当てはまります。

  1. 拡張ASCII
  2. 2バイト文字セット(DBCS)
  3. EBCDIC
  4. UTF-8(Unicode)

TEXTデータ型(SQL Server 2005以降では非推奨なので使用しないでください)のみが「非Unicode」ですが、これは単なる専門知識であり、「8ビットデータ型」と呼ぶと正確。

NVARCHARNCHAR、およびNTEXTは、「UTF-16」または「16ビットデータ型」と呼ぶことができます。 OracleはNVARCHARに「Unicodeのみ」という用語を使用していると思いますが、UTF-8(Unicodeエンコーディングも)を使用する可能性を明確に除外していないため、機能しません。したがって、おそらく最初の2つのオプションを使用するのが最善です。

新しいUTF-8エンコーディングの詳細については、私の投稿を参照してください。

SQL Server 2019のネイティブUTF-8サポート:救世主か偽預言者か

追伸SQL Serverのドキュメントを更新して、これらの変更を反映するようにゆっくりと作業しています。

P.P.S. Microsoftは、質問で参照されている charおよびvarchar のドキュメントを含む、一部のページをUTF-8情報ですでに更新しています。 「非Unicode」という語句は含まれなくなりました。しかし、それは単なる参考です。これは、誤ってUnicodeのみであると考えられていた文字を含む非Unicodeエンコーディングに関するものであるため、問題は変わりません。

4
Solomon Rutzky

質問には、Unicodeとは何かについての中心的な誤解が含まれています。 Unicode文字セットは、UTF-8やUTF-16などのエンコーディングとともに、コンピューターでテキストを表現する多くの方法の1つであり、他のすべての文字セットやエンコーディングに取って代わることを目的としています。 「非Unicodeデータ」が「Unicodeに存在しない文字」を意味する場合、この回答で使用したテキストはいずれもそのタイプで保存できません。ラテン語のアルファベットのすべての文字と日常の英語で使用される一般的な句読点は、 Unicodeに含まれています。

テキスト表現は、大きく2つの部分で考えることができます:文字セット異なる文字(文字、数字、記号など)を参照の数値にマッピングしますチャート; encodingは、ビットのパターンとして(ディスク上、ネットワーク接続などを介して)それらの数を表します。ここでは、主に最初の部分に関心があります。特定の文字セットのグラフにリストされる文字です。

Unicodeは、世界中のすべての文字に数字(「コードポイント」と呼ばれます)を持たせることを目的としているため、Wikipediaのような参照では、文字のUnicode位置を標準的な参照情報として参照することがよくあります。ただし、これは、他の文字セットにも同じ文字のマッピングがないことを意味するものではありません。

現在使用されている最も古くて単純な文字セット(およびエンコーディング)の1つはASCIIです。これは、7ビットを使用して各文字をエンコードするため、128の異なる文字(0〜127)のマッピングがあります。これは多くのアクセント付き文字と一般的な記号を除外するため、後のエンコーディングは8ビットを使用し、同じ最初の128文字をマッピングし、128から255の位置を埋めることによって文字セットに追加します。これらの中で注目すべきは標準 8859-1 および ISO 8859-15 、およびMicrosoft固有の Windowsコードページ1252

したがって、MS SQL Serverに戻るには、ncharnvarchar、またはntext列に格納されている「Unicode文字列」は、allUnicodeエンコーディングを使用してデータを格納するため、Unicode文字セットにマッピングされた文字。 charvarchar、またはtext列に格納されている「非Unicode文字列」は、その他のエンコーディング。非Unicode列に格納できるものはすべて、Unicode列にも格納できますが、その逆はできません。

保存できる文字を正確に知るには、使用中の「照合順序」を知る必要があります。これは、Microsoftが「コードページ」と呼んでいることを示し、 このMicrosoftリファレンスページで説明されています 。あなたの場合は、前述の非常に一般的なコードページ1252を使用している可能性があります。

あなたが言及した文字は、Unicodeとコードページ1252の両方に存在します。

  • Trademark(™)は8482の位置にUnicodeで、153の位置にCP1252で表示されます。
  • Registered(®)は、偶然にも、UnicodeとCP1252の両方の174番に表示されます
3
IMSoP