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


17

varchar列を持つテーブルがあります。以下に示すように、商標(™)、著作権(©)およびその他の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(®)シンボルはUnicode文字です。定義はvarcharデータ型のプロパティと矛盾しますか?最初のリンクと2つ目のリンクを読んだ。しかし、定義がユニコード文字列以外の値のみを許可すると言っているときに、ユニコード文字列を許可する理由を理解できませんでした。


12
すべての文字はUnicode文字です。
マーティンスミス

マイクロソフトは、UTF-16 / UCS-2を意味する場合にUNICODEをよく使用します。そのため、UNICODEは何らかのコンテキストであるため、UTF-8もカウントされない場合があります。
CodesInChaos

1
@CodesInChaos:コメントの解析に苦労しましたが、UnicodeがさまざまなUTF-nエンコーディングと混同されるのではないかと心配しています。
モニカとの明度レース

1
@Martin Smith:すべての文字がUnicode文字である場合、Microsoftのvarchar定義で Unicode以外の文字列データが許可されていると言われるのはなぜですか?
シヴァ

2
varchar型の文字のエンコーディングは、Unicodeではなく、全ての文字は、Unicodeに存在する
マーティン・スミス

回答:


15

ただし、Trademark(™)およびRegistered(®)シンボルはUnicode文字です。

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

以下は、あなたのキャラクターがすべてアスキーであることを示す簡単なテストです(+ extended ascii128から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;

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

ここに画像の説明を入力してください

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

ここでは、実際のUnicode文字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;

ここに画像の説明を入力してください

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

select nchar(8482), nchar(153)

1
しかし、あなたが言及した記事には「ASCII」という言葉はなく、それらはユニコードと非ユニコード文字のみについて話しているので、使用したTrademark(™)はユニコードではありません。
18

16
「拡張ASCII」は恐ろしく曖昧な用語です。実際にどの8ビットエンコーディングが使用されているかを確認すると便利です(ロケール/照合設定に基づいていますか?)。Windowsコードページ1252を推測しています。これは、文字153として™を実際にエンコードします
。– IMSoP

2
@sepupicコードポイントとエンコーディングの違いについてもっと読む必要があると思います。ウィキペディアが役立つ場合があります。「エンコードは、Unicode コードポイントの範囲(のサブセット)を、コード値と呼ばれる固定サイズの範囲内の値のシーケンスにマップします。」8482は™のコードポイントであり、Windows-1252では\ x99(153)、MacRomanでは\ xAA、UTF-8では\ xE2 \ x84 \ xA2などとしてエンコードできます
。– curiousdannii

7
127を超える8ビット文字には注意が必要です。127を超える各コードが表すものは、使用中のエンコードに応じて変化し、どの照合が使用されているかによって異なります。コードページ1252では、ユニコード8482は153にマップされます。コードページ850では、スポットは214(Ö)で取得され、ISO-8859-1(Latin1と呼ばれることもあります)では、印刷可能な表現のない制御コードです。あなたがない限り知っているあなたがします常に同じコードページを使用するには、ANSI文字(127以下)に固執またはUnicode型を使用する方が安全です。コードページ1252はSQL Serverで最も一般的ですが、どこにでもあるわけではありません。
デビッドスピレット

4
@Shiva 絶対最小値すべてのソフトウェア開発者は、ユニコードと文字セットについて絶対的かつ積極的に知っておく必要があります。ASCIIは多くのエンコーディングのサブセットであり、それらのエンコーディングのほとんどすべてに非ASCIIシンボルが含まれており、同時にUnicodeではありません。また、Unicodeにはさまざまなエンコーディング(UTF-8、UTF-32など)もあります。
jpmc26

7

コメントから、「拡張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;

4

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

他の答えは間違っていませんが、基本用語の混乱を指摘するのに役立つと思います。この混乱の例として、上記の引用から引用された2つの単語を強調しました。SQL Serverのマニュアルは、Unicodeと非Unicodeのことを話すときにデータ、彼らはされていないの話文字。彼らは、特定の文字を表すバイトシーケンスについて話しています。Unicodeの種類(主な違いNCHARNVARCHARXML、および非推奨/悪NTEXT)と非Unicodeの種類は(CHARVARCHAR、および非推奨/悪はTEXT)何種類のバイトシーケンスのは、彼らが保存することができます。

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

したがって、定義は正確です。非Unicodeタイプに保存できる文字は常に8ビットです(2つの8ビット値を組み合わせて単一の「文字」として使用する場合でも、バイト文字セット/ DBCSコードページで許可されます)。また、Unicodeデータ型は、2つの16ビット値を組み合わせて単一の「文字」(つまり、補助文字を表すサロゲートペア)として使用する場合でも、常に16ビットです。

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

VARCHAR「非ユニコード」と呼ぶことはできなくなりました。したがって、2018年9月のSQL Server 2019の最初のパブリックベータ版から、SQL Server 2019 VARCHARより前のバージョンに関して言えば、「8ビットデータ型」と呼ぶ必要があります。この用語は4つのタイプすべてに当てはまりますで使用できるエンコーディングの例VARCHAR

  1. 拡張ASCII
  2. 2バイト文字セット(DBCS)
  3. EBCDIC
  4. UTF-8(ユニコード)

のみTEXT(SQL Server 2005のの非推奨なので、それを使用していない)データ型は、「非Unicode」であり、それはただ専門的だし、「8ビットのデータ型」としてそれに言及正確です。

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

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

SQL Server 2019でのネイティブUTF-8サポート:救い主と偽りの預言者?

PSこれらの変更を反映するために、SQL Serverのドキュメントを更新する作業を徐々に進めています。

PPS Microsoftは、質問で参照されているcharおよびvarcharのドキュメントを含む、UTF-8情報でいくつかのページを既に更新しています。フレーズ「non-Unicode」は含まれなくなりました。しかし、それは単なる参考です。これは、誤ってUnicode専用と考えられていた文字を含む非Unicodeエンコーディングに関するものであるため、質問を変更しません。


3

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

テキスト表現は、2つの部分で広く考えることができます。異なる文字(文字、数字、記号など)を参照チャートの数字にマッピングする文字セット。そして、それらの数をビットのパターンとして表現するエンコード(ディスク上、ネットワーク接続など)。ここでは、特定の文字セットのチャートにどの文字がリストされているかという最初の部分に主に関係します。

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

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

保存されているように、「Unicode文字列」:だから、MS SQL Serverに戻ってきてncharnvarchar、またはntext表すことができ、列をすべて、それがデータを保存するためにエンコードするUnicodeを使用しているため、Unicode文字セットにマッピングされた文字が。「非Unicode文字列」は、のように格納されているcharvarcharまたはtextカラムにマッピングされた文字のみ表すことができ、いくつかの他の符号化を。非Unicode列に格納できるものはすべてUnicode列にも格納できますが、その逆はできません。

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

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

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

3
「Unicodeは、コンピューターで使用するテキストをエンコードする多くの方法の1つです」 –それは正しくありません。Unicodeは単なる文字と記号の集まりであり、各文字には数字である独自のコードポイントがあります。エンコーディングの仕事は、これらのコードポイントをバイトシーケンスに一致させることです。UTF-8およびUTF-16はエンコードですが、Unicodeはエンコードではありません。
突く

@poke答えでさらに説明するように、ここでは「エンコード」を使用して、「チャート上の位置への文字のマッピング」と「ビットのシーケンスとしてのそれらの位置の表現」の両方を表します。使用するより良い用語があるかもしれませんが、それがどうなるかはわかりません。
IMSoP

3
独自の定義で「エンコード」を使用することはできません。ここで情報を盗んで申し訳ありませんが、「Unicodeとは何かについての中心的な誤解が含まれています」で始まる回答ではできません。
突く

2
IMSoP(および@poke):エンコード以外の意味で「エンコード」を使用することの過剰については、私は完全に同意しますが、IMSoPのジレンマにも同情しています。私の好みは、Unicodeを複数のエンコーディングを持つ文字セットとして参照することですが、通常、ほとんどの場合(またはすべてですか?)1対1の関係であるため、文字セットとエンコーディングは互換的に使用されます。
ソロモンラツキー

2
いい答えです。私は絶対にすべてのソフトウェア開発者に絶対的、積極的に知っておくべき絶対最小リンクをそこに追加することを強くお勧めします。
jpmc26
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.