- PR -

nvarcharについて

投稿者投稿内容
Jitta
ぬし
会議室デビュー日: 2002/07/05
投稿数: 6267
お住まい・勤務地: 兵庫県・海手
投稿日時: 2004-12-02 22:02
引用:

未記入さんの書き込み(2004-12-02 12:59)より:

本当に余計なことかな? 技術的な問題はないかもしれないけど。実際には「半角は文字幅が半分だから 2倍入力・表示できる」という発想は顧客側に根強く残っていて問題になることがあります。

技術的な動向はともかく「半角は幅が半分」というのは今でも重宝されていたりするわけです。私もできることなら nvarchar だけで設計したいのですが、泣く泣く varchar で実装することも多いです。今はユーザー定義関数で LenB() や LeftB() を作っているので、昔ほど varchar を使っても苦労はしないですけどね。

nvarchar/varchar の選択は、技術的な理由だけでなく業務適応性も考慮することをオススメします。VB のテキストボックスの MaxLength プロパティが Unicode 文字数での判定だから… などの安易な理由で nvarchar を選択するとヒドイめに遇います。


 おっしゃることはよくわかります。私も昔、データの最終登録先はUnixなので半角カナも2バイトなのに、データの入力をRupoで行ったために"半角カナ"はもちろん、"半角漢字"を使われて泣いたことがあります。だからこそいえますが、varcharかnvarcharかという文字コードの問題と、表示可能な文字数の問題は、別の問題でしょう。

 SQL Server Books Onlineの「char型とvarchar型」というトピックには、varcharは
引用:

n バイトの長さの可変長の UNICODE ではない文字型データです。


とあります。これより、varchar列に格納されるのは、Unicodeではないことがわかります。しかし、.NET Framework内では、文字列はUnicodeで扱われます。すると、Unicodeと何らかの文字コード間でコード変換が行われます。このときにデータがロストする可能性が否定できません。顕在化したのが、対Oracleにおける「Wave-Dash問題」ではないでしょうか。同じMicrosoft製品同士なので、このUnicode仕様の解釈による"不幸な副作用"はおこらないでしょうが、しなくてもよい変換であるなら、しないに越したことはない、と思います。
 また、「Unicodeデータの使用」というトピックには、
引用:

Unicode システムは一貫して同じビット パターンを使用してすべての文字を表すため、システム間で文字を移動したときに文字が誤って変換されるという問題は起こりません。システム全体で Unicode 型を使用することで、文字変換から生じる問題を最低限に抑えることができます。


と書かれています。これより、"文字化け"で悩まないためにも、日本語を格納するところにはnvarchar型を使うことを勧めます。varcharを使おうが、nvarcharを使おうが、ご指摘のような状況では、バイト数、というより"文字列幅"のチェックを行わなければならないことに変わりはありません。このとき、"文字列幅"は、実際には出力するデバイスによって変わりますよね。例えば、私が昔使っていたプリンタでは、全角文字と半角文字の比率は、デフォルトで2:3でした(1:2にすることもできた)。したがって、バイト数のチェックでは印字幅のチェックは兼ねられないのです。設定を変えれば…それこそ文字送りは1/2インチか、1/8インチ単位でできました!!つまり、「1バイト文字の幅=2バイト文字の半分の幅」として入力可能な文字のバイト数を表示可能文字幅と一致させるのも、『テキストボックスの MaxLength プロパティが Unicode 文字数での判定だから』というのも、安易さでは変わらないと思います。


 ちなみに、バイト数の計算はこのスレッドのような感じで、Shift_JISなどにエンコードして行います。


 なお、Unicodeは2バイトとは決まっていません。3バイトや4バイトかもしれません。なので、SQL Server 2000の仕様が「Unicodeは2バイト」と決めうちであるなら、そしてBooks Onlineからはそのようになっていると思われるのですが、間違っています。.NET Frameworkの方は大丈夫みたい。ただ、String.Lengthは"文字数"ではないので、注意が必要。日本語では文字数と等しくなるように思う。

_________________
未記入
ぬし
会議室デビュー日: 2004/09/17
投稿数: 667
投稿日時: 2004-12-03 00:33
引用:

varcharかnvarcharかという文字コードの問題と、表示可能な文字数の問題は、別の問題でしょう。


別の問題ではないと思います。単なる文字コードの違いとは思えません。固定幅フォント + MS932 を用いることで、簡単に バイト数 = 文字表示幅 と算定できるのは非常にメリットが大きいのですから。

引用:

ちなみに、バイト数の計算は(省略)Shift_JISなどにエンコードして行います。


Unicode を Shift_JIS にエンコードしてバイト数(=表示幅)を計算しても手遅れだと思いますが…。たとえば、半角4文字分しか印字幅を確保できない帳票があったとしましょう。その印字領域に対応するデータは nvarchar(4) になっており、"焼肉定食" が格納されていたとしましょう。これを Shift_JIS に変換して 8バイトだということが判明したとして、どうすればいいのでしょう? 切り捨てて "焼肉" だけを印字しますか。varchar + 固定幅フォントであれば、このような問題は発生しません。

データベースにデータを格納するすべてのアプリケーションが格納前にチェックする? データの正当性をアプリケーションに委ねるというのは、データベースの信頼性を低下させますね。

引用:

これより、"文字化け"で悩まないためにも、日本語を格納するところにはnvarchar型を使うことを勧めます。


Unicode のメリットも分かっているつもりです。が、それは技術者としての見解です。私は、顧客の「半角の幅は半分」という認識に varchar のほうがフィットすることがある、という事実を述べたまでです。あなたの説明は技術的にはそれなりの説得力を持っていますが、それが顧客に通じるかどうかは別だと思います。今まで、半角を使うことで印字できていたビル名が印字できなくなってしまう。あなたなら顧客にどのような回避策を提案しますか? 文字化けの危険性などの技術的な要因で、いままで出来ていた事ができなくなる、ということに抵抗を感じる顧客は少なくないと思うのですが。

引用:

"文字列幅"は、実際には出力するデバイスによって変わりますよね。例えば、私が昔使っていたプリンタでは、全角文字と半角文字の比率は、デフォルトで2:3でした(1:2にすることもできた)。したがって、バイト数のチェックでは印字幅のチェックは兼ねられないのです。


いいえ、兼ねられます。出力デバイスによって変わる・変えられる、というのが真であるのと同時に、出力デバイス(使用フォント)を都合の良いように設定することによって、バイト数 = 印字幅 とすることができるシステムが存在する、というのも真なのですよ。

引用:

なお、Unicodeは2バイトとは決まっていません。3バイトや4バイトかもしれません。(省略)ただ、String.Lengthは"文字数"ではないので、注意が必要。日本語では文字数と等しくなるように思う。


Unicode ってなんですか? Windows では UCS-2 を UTF-16LE で表すので、ひとつの文字が 3バイトや 4バイトになることはないと思います。将来的に UCS-4 をサポートしたときの布石でしょうか? > .NET のリファレンスの String.Length が文字数と一致しないという記述。

Unicode 1文字が 3バイトになるのは UTF-8 を使用した場合、4バイトになるのは UCS-4 を UTF-16 で表現した場合と、UTF-32 を用いた場合だと思いますが、いずれも現在の Windows ではサポートされていないと思います。IE などのアプリケーションレベルでは UTF-8 を扱えますけどね。
ぢゃん♪
大ベテラン
会議室デビュー日: 2003/06/12
投稿数: 208
お住まい・勤務地: 都内
投稿日時: 2004-12-03 07:28
引用:

未記入さんの書き込み (2004-12-03 00:33) より:

引用:

これより、"文字化け"で悩まないためにも、日本語を格納するところにはnvarchar型を使うことを勧めます。


Unicode のメリットも分かっているつもりです。が、それは技術者としての見解です。私は、顧客の「半角の幅は半分」という認識に varchar のほうがフィットすることがある、という事実を述べたまでです。あなたの説明は技術的にはそれなりの説得力を持っていますが、それが顧客に通じるかどうかは別だと思います。今まで、半角を使うことで印字できていたビル名が印字できなくなってしまう。あなたなら顧客にどのような回避策を提案しますか? 文字化けの危険性などの技術的な要因で、いままで出来ていた事ができなくなる、ということに抵抗を感じる顧客は少なくないと思うのですが。


そういうとき私なら、varchar(nバイト)の代わりにnvarchar(n文字)にしますね。
で、SQL文(INSERT/UPDATE)発行で文字数orバイト数チェックするのではなく、事前に(最悪でもSQL文発行直前までに)文字数orバイト数チェックをするでしょう。

そもそも、WAVE-DASH問題などの文字コード変換問題は、対処困難な、極めて深刻な問題です。
文字コード変換を事前に避ければ発生しないはずの問題が、システムが本番稼動してから不具合として顕在化したら、顧客に迷惑をかけ、損害をも与えてしまいます。そして、そのときはどう弁解しかつ対処しますか?

あるいは、あらかじめ文字コード変換で問題が発生する文字を使わせないとか、問題を避ける方法はあるでしょうけど……。

[ メッセージ編集済み 編集者: ぢゃん♪ 編集日時 2004-12-03 07:44 ]
にしざき
ぬし
会議室デビュー日: 2003/06/30
投稿数: 304
投稿日時: 2004-12-03 08:58
「未記入」氏の見解はわかるんですが、「こういう顧客がいる」というのを「顧客がこう思っている」というように一般化させているように見えるんですけど。

自分の接した顧客を一般化させてよいなら、私の経験したエンドユーザ(特に、普段PCを使わない人がほとんど)は「全角・半角」なんて意識していないほうが多かったので…
かつのり
ぬし
会議室デビュー日: 2004/03/18
投稿数: 2015
お住まい・勤務地: 札幌
投稿日時: 2004-12-03 09:20
引用:

そもそも、WAVE-DASH問題などの文字コード変換問題は、対処困難な、極めて深刻な問題です。
文字コード変換を事前に避ければ発生しないはずの問題が、システムが本番稼動してから不具合として顕在化したら、顧客に迷惑をかけ、損害をも与えてしまいます。そして、そのときはどう弁解しかつ対処しますか?



RDB操作のタイミングと不具合の話は関連性がありますか?
不具合の問題はただのテストケース漏れですよね。
それとも普段、環境の問題としてテスト対象から外してるんですか?

適正なテストが行われていたら、事前だろうが事後だろうが
変換のタイミングが導入後の不具合の原因にはなりえないです。
未記入
ぬし
会議室デビュー日: 2004/09/17
投稿数: 667
投稿日時: 2004-12-03 09:25
引用:

そういうとき私なら、varchar(nバイト)の代わりにnvarchar(n文字)にしますね。
で、(省略)事前に(省略)文字数orバイト数チェックをするでしょう。


これは、私の述べた…
引用:

「データベースにデータを格納するすべてのアプリケーションが格納前にチェックする? データの正当性をアプリケーションに委ねるというのは、データベースの信頼性を低下させますね。


と同じことだと思いますが、この方法にも問題が潜んでいます。それは、データを格納するすべてのアプリケーションについて注意を払わねばならなくなる、ということです。自作の入力プログラムだけを考えればいいわけではありません。エンタープライズマネージャなどのツールで緊急メンテする場合にも、表示幅を超過しないだろうか? と考えなければならないし、DTS インポートを使用して安易にデータを流し込むことさえ危険が伴うようになります。これが私の言う事前チェックに委ねることによるデータベースの信頼性低下です。

これは、数字4桁しか入力すべきでない項目に対して numeric(6) で設計するのと同じです。入力プログラムで 4桁に収まっているか常にチェックしたとしても 私は安心できません。技術的には、6桁のデータが混入している可能性を否定することができないからです。

引用:

そもそも、WAVE-DASH問題などの文字コード変換問題は、対処困難な、極めて深刻な問題です。(省略)顧客に迷惑をかけ、損害をも与えてしまいます。そして、そのときはどう弁解しかつ対処しますか?


私は、Shift_JIS ではなく MS932 を使用する SQL Server を採用しますので、WAVE DASH 問題をシステム不具合として顕在化させない自信があります。なので、弁解・対処については、今のところ考えていません。まずいですか?

引用:

「未記入」氏の見解はわかるんですが、「こういう顧客がいる」というのを「顧客がこう思っている」というように一般化させているように見えるんですけど。


そうですか。それは残念。一般化しているつもりはないんですけどね。ただ varchar が適応するケースがあることを強調しているだけなんですが。私は Unicode を使いたいが、泣く泣く varchar を使うことが「多い」と書いています。
Jitta
ぬし
会議室デビュー日: 2002/07/05
投稿数: 6267
お住まい・勤務地: 兵庫県・海手
投稿日時: 2004-12-03 21:42
引用:

未記入さんの書き込み(2004-12-03 00:33)より:

いいえ、兼ねられます。出力デバイスによって変わる・変えられる、というのが真であるのと同時に、出力デバイス(使用フォント)を都合の良いように設定することによって、バイト数 = 印字幅 とすることができるシステムが存在する、というのも真なのですよ。


 ん〜?「都合のいいように設定する」のであれば、「“文字数=印字幅”とすることができるシステムが存在する」というのも、また真ですよね。つまり、半角も全角と同じ幅で出力する、ということですけど。都合のよいように設定することができるなら、都合のよいように設定するアプリケーションを組めばいいわけで、バイト数と文字の表示幅は関連が無くなるのでは?例えば、Wordでは文字幅を半分にすることができます。Excelではセルの幅に合わせてフォントサイズを縮小させることができます。こういう風に設定するのも一手ですよね。
 先にも書きましたが、「入力文字数制限=データベースの最大文字数」が安易だと言われるなら、「バイト数=印字幅」も、同じように安易だと思いますよ。そして、それはデータベースに保存される文字コードを、Unicodeにするかそれ以外にするかという問題とは、別だと考えます。

 そうではなくて、“表示幅が固定されているデバイスを使用する。このデバイスでは、半角文字と全角文字は1:2の文字幅で出力される。このとき、表示される文字幅を、一定以下に抑えなければならない。”という要求が、問題なのではないでしょうか?この問題に対してデータベースの幅をバイト数で定義して、入力できる幅と表示できる幅を一致させた。これはこれで、一つの"解"だと思います。つまり、『技術的な理由だけでなく業務適応性も考慮することをオススメします』の部分です。

 それと、「ユーザの入力を、アプリケーションはデータベースにスルーする」と読み取ったのですが、それでいいでしょうか?確かに、データベース側にCHECKを組み込めば、データの妥当性をチェックする箇所を一カ所に絞れるので、何かと便利に思います。ただ、これを使ったことがないのでよくわからないのですが、例えば2カ所の列に挿入できない値があったとして、アプリケーションはこの"2カ所で入力違反があった"ということをユーザにフィードバックできるのでしょうか?ユーザにとって、後から「これも」「あれも」と言い足されるより、最初に「ここと、そこ」といわれた方がいいと思うのですけど?


 Unicodeの件。よくわかりません。MSDNを見ると、.NET Frameworkに関する記述に於いて、Unicodeという記述はUTF-16を指しているようです。ただ、Stringクラスの説明では、UTF-16エンコードしたCharオブジェクトのコレクションを扱っており、文字単位に処理したいならStringInfoクラスを使用せよ、と書かれています。補助コードポイントを使用すると2オブジェクト(4バイト)必要だよ、と。
 対して、SQL Server Books Onlineでは、nvarcharでは指定された文字数の2倍のバイト数が確保される、と書かれています。この2つは整合しない、と思ったのですけど、どうなんでしょう?
_________________
未記入
ぬし
会議室デビュー日: 2004/09/17
投稿数: 667
投稿日時: 2004-12-03 23:41
引用:

Excelではセルの幅に合わせてフォントサイズを縮小させることができます。


これは私も是非実現したいと思って取り組んだことがあるのですが…。ダメでした。文字全体が縮小されると非常に読みにくくなってしまうのです。varchar(20) を nvarchar(20) とした場合、全角文字だけが格納された最悪の場合、自動縮小によって文字が半分のサイズになってしまうのです。あまりにも読みにくいので却下されました。帳票出力に関しては、高さを維持して幅だけを縮小(つまり長体に)することができたのですが、画面表示では対応できませんでした。

半角/全角の問題だけではなく、プロポーショナルフォントを使用する上でもデータを印字領域に自動的に合わせこむことが必要になってくるでしょうね。OS でサポートしてくれないものかしら?

引用:

都合のよいように設定することができるなら、都合のよいように設定するアプリケーションを組めばいいわけで、バイト数と文字の表示幅は関連が無くなるのでは?


組めればの話ですね。私の技術力では、そこまでできませんでしたので、varchar で妥協しているわけです。なにか良いスケーリング技術があったら 教えてください。

引用:

「入力文字数制限=データベースの最大文字数」が安易だと言われるなら、


安易だなんて言っていません。むしろ逆で、制限するのが困難だと言っているのです。そういう困難な道を選択するのが「安易」だとは言いましたけど。

引用:

「バイト数=印字幅」も、同じように安易だと思いますよ。


安易でもいいじゃないですか。結果として実装が容易なのですから。この「バイト数 = 印字幅」という特徴は便利に利用できると思いませんか?

引用:

そして、それはデータベースに保存される文字コードを、Unicodeにするかそれ以外にするかという問題とは、別だと考えます。


「バイト数 = 印字幅」を実現するためには、半角文字が全角文字の半分の幅で表示される固定幅フォントと、半角文字は 1バイト/全角文字は 2バイトで保持される文字コード体系が必要になるのです。Unicode ではダメのなのですよ。

引用:

それと、「ユーザの入力を、アプリケーションはデータベースにスルーする」と読み取ったのですが、それでいいでしょうか?


よくないんじゃないでしょうか? 入力プログラムでの検査では不十分である旨の発言はしましたが、入力プログラムでの検査が不要である、と言ったつもりはありませんので。私自身はマスタの参照可能性(外部参照整合性)もアプリケーションで事前に確認します。(これは、コードに対する名称を画面に表示するので自然とそうなっているだけですけどね。)

引用:

アプリケーションはこの"2カ所で入力違反があった"ということをユーザにフィードバックできるのでしょうか?


少なくとも SQL Server では、できません。

引用:

Unicodeの件。よくわかりません。(省略)補助コードポイントを使用すると2オブジェクト(4バイト)必要だよ、と。


ええ、確かにそのように書いてあります。しかし、UCS-4 をサポートしていない Windows において サロゲートペアが必要になることなどないと思うのです。だから、将来への布石かなあ? と思ったのです。それよりも、String.Length の仕様を変更して、UCS-4 を扱う場合にも、"文字数" を返すようにして欲しいですね。となると Char 型は 32ビットにしないといけなくなるかな。

引用:

対して、SQL Server Books Onlineでは、nvarcharでは指定された文字数の2倍のバイト数が確保される、と書かれています。この2つは整合しない、と思ったのですけど、どうなんでしょう?


現時点の Windows の実装においては、Unicode は 2バイトなので、BOL の記述も正しいと言えると思います。むしろ、.NET リファレンスの記述は誤解を招くような気がしますね。

スキルアップ/キャリアアップ(JOB@IT)