DB SQLServer

SQLServerにおけるデータの「?」文字化けとカラムの型について

システム運用において、データベースの文字化けは思いがけない混乱の一つです。

特にSQL Serverを利用する際、慣れていないとデータの先頭にNを付けても「データが?に文字化けする」現象に直面することがあります。

SQL Serverに日本語のデータを入れるには、本来NVARCHARかNCHAR型を使う必要があり、この2つの型ではないカラムに日本語のデータを入れようとしていることが理由です。

文字型データとエンコーディング

データベースは、文字情報を保存するためにさまざまなデータ型が用意されています。

SQL Serverにおいて、標準的な文字列型にはCHAR型、VARCHAR型、そしてNCHAR型、NVARCHAR型があります。

  • CHAR型、VARCHAR型は、非Unicode文字列を扱います。
  • NCHAR型、NVARCHAR型は、Unicode文字列を扱います。

重要なのが、Unicodeは世界中の文字を統一して表現できる文字コード体系であり、日本語、中国語、ハングルなどの多言語を正確に扱うためには不可欠な仕組みです。

なぜ「?」に文字化けするのか

CHAR型やVARCHAR型を使用している場合、SQL Serverはデフォルトのコードページ(例えば、英語圏ならLatin1)に基づいて文字を保存します。

これらの型は、多バイト文字(日本語など)に対応していないため、登録できない文字があると、それを代替として「?」に置き換える仕様になっています。

これは、そもそも格納できない文字を無理に保存しようとする際の、システム側の仕様です。

一方、NCHAR型やNVARCHAR型は、Unicodeをベースにしているため、日本語をはじめとする幅広い文字体系を正確に保存することができます。

つまり、多言語対応が必要な場面では、常にNCHARまたはNVARCHARを使用することが推奨されます。

実例|違いの確認

たとえば、次のような例を考えてみましょう。

-- VARCHARに日本語を格納しようとする
CREATE TABLE [TestTable] (
[TextValue] VARCHAR(100)
);

INSERT INTO [TestTable] ([TextValue]) VALUES ('こんにちは');
SELECT * FROM [TestTable];

この場合、結果セットには「?????」と表示されるか、「?」だけが見えるかもしれません。一方、以下のようにNVARCHARを使用すると、

-- NVARCHARに日本語を格納する
CREATE TABLE [TestTable] (
[TextValue] NVARCHAR(100)
);

INSERT INTO [TestTable] ([TextValue]) VALUES (N'こんにちは');
SELECT * FROM [TestTable];

正しく「こんにちは」と表示されます。

ここでのポイントは、文字列リテラルの前に「N」を付与することも忘れてはいけない点です。

これにより、SQL Serverに「これはUnicode文字列ですよ」と明示的に伝えることができます。

非Unicodeカラムに日本語を入れる

望ましくはありませんが、誤った設計で本番運用が開始された場合、非Unicodeカラムにデータを入れる必要が出てくるかも知れません。

この場合、カラムの照合順序を「Japanese_XJIS_140_CS_AS_KS(Shift-JISで表現可能な文字)」に変更します。

-- カラム単位で照合順序を見る
SELECT COLUMN_NAME, COLLATION_NAME
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = 'TestTable';

-- またはDB全体のデフォルト照合順序
SELECT DATABASEPROPERTYEX(DB_NAME(), 'Collation') AS Collation;

-- 対象カラムの照合順序の変更を行う
ALTER TABLE [TestTable] ALTER COLUMN [TextValue] VARCHAR(100) COLLATE Japanese_XJIS_140_CS_AS_KS;

上記の例だとvarcharに日本語を入れても表在されますが、Shift-JIS範囲内のみなので最終的にはnvarcharに変更した方がいいです。

まとめ

SQL Serverにおいてデータが「?」に文字化けしてしまう最大の原因は、文字列型がNVARCHARやNCHARではないことにあります。

非Unicode型では表現できない文字を保存しようとすると、仕様上自動的に「?」に置き換わります。

日本語を含むマルチバイト文字を正しく取り扱うためには、データ型の選択が極めて重要です。

設計段階から意識的にNCHARやNVARCHARを採用することが、トラブル防止の第一歩といえるでしょう。

  • この記事を書いた人

朝倉卍丸

シングルモルトスコッチなどのお土産を持ってきた人を助けるのが好きです。サービスの分割が重要ですが、まあ昔ながらの方法でやりたいこともありますよね。

よく読まれている記事

条件の0=0は全てが正であるを意味するSQL 1

SQLの条件に0=0のような記述を見かけます。 変わった書き方の条件ですが、これは「全てが正である」事を意味しており、結合条件の場合はCROSS JOINと同じです。 下記の例で言えば、結合するsub ...

DISTINCTを使わないで重複排除を考えるSQL 2

SQLのDISTINCTはEXISTSとかGROUP BYでなんとかする事もできます。 DISTINCTは暗黙的なソートがされますが、何のDBを使うにせよ過去のバージョンならともかく、最近のバージョン ...

RFC 5322に準拠させた正規表現言語別 3

RFC5322で定義されている正規表現を、各言語の正規表現に変化させた形になります。 完全な電子メール正規表現は存在しないので、結局のところ何かの公式基準に従っていたとしても、自分が携わるサービスのル ...

-DB, SQLServer