文字セットの問題は非常に一般的です。一般的な注意事項をいくつか挙げてみましょう。
原則として、4つを考慮する必要があります 異なる文字セット設定。
1および2:NLS_CHARACTERSET
およびNLS_NCHAR_CHARACTERSET
例:AL32UTF8
それらはのみで定義されています データベース上で、
を使用してそれらを問い合わせることができます SELECT *
FROM V$NLS_PARAMETERS
WHERE PARAMETER IN ('NLS_CHARACTERSET', 'NLS_NCHAR_CHARACTERSET');
これらの設定は、データベースに保存できる文字(形式)を定義します。これ以上でもそれ以下でもありません。既存のデータベースで変更する必要がある場合は、ある程度の労力が必要です(Unicode用の文字セット移行および/またはOracle Database Migration Assistantを参照)。
3:NLS_LANG
例:AMERICAN_AMERICA.AL32UTF8
この値はのみで定義されます あなたのクライアントに。 NLS_LANGは、データベースに文字を格納する機能とは何の関係もありません。これは、クライアント側で使用している文字セットをOracleに通知するために使用されます。 NLS_LANG値を(たとえばAL32UTF8に)設定する場合、Oracleデータベースに「クライアントは文字セットAL32UTF8を使用しています」と伝えるだけです。これは、クライアントが実際にAL32UTF8を使用していることを必ずしも意味しません。 (以下の#4を参照)
NLS_LANGは、環境変数NLS_LANG
で定義できます。 または、WindowsレジストリのHKLM\SOFTWARE\Wow6432Node\ORACLE\KEY_%ORACLE_HOME_NAME%\NLS_LANG
(32ビットの場合)、それぞれHKLM\SOFTWARE\ORACLE\KEY_%ORACLE_HOME_NAME%\NLS_LANG
(64ビットの場合)。アプリケーションによっては、NLS_LANGを指定する他の方法があるかもしれませんが、基本に固執しましょう。 NLS_LANG値が指定されていない場合、OracleはデフォルトでAMERICAN_AMERICA.US7ASCII
に設定します。
NLS_LANGの形式はNLS_LANG=language_territory.charset
です。 。 {文字セット }NLS_LANGの一部はない システムテーブルまたはビューに表示されます。 NLS_LANG定義のすべてのコンポーネントはオプションであるため、次の定義がすべて有効です。NLS_LANG=.WE8ISO8859P1
、NLS_LANG=_GERMANY
、NLS_LANG=AMERICAN
、NLS_LANG=ITALIAN_.WE8MSWIN1252
、NLS_LANG=_BELGIUM.US7ASCII
。
上記のように、NLS_LANG
の{charset}部分 データベースのシステムテーブル/ビューまたは関数では使用できません。厳密に言えば、これは真実ですが、次のクエリを実行できます:
SELECT DISTINCT CLIENT_CHARSET
FROM V$SESSION_CONNECT_INFO
WHERE (SID, SERIAL#) = (SELECT SID, SERIAL# FROM v$SESSION WHERE AUDSID = USERENV('SESSIONID'));
現在のNLS_LANG
から文字セットを返す必要があります 設定-ただし、私の経験に基づくと、値は多くの場合NULLまたはUnknown
、つまり信頼できない。
ここでさらに役立つ情報を見つけてください:NLS_LANG FAQ
一部のテクノロジーはNLS_LANG
を利用しないことに注意してください 、設定は効果がありません。例:
-
ODP.NETマネージドドライバーは
NLS_LANG
ではありません センシティブ。 .NETロケールのみに依存します。 (Data Provider for .NET開発者ガイドを参照) -
OraOLEDB(Oracle製)は常にUTF-16を使用します(OraOLEDBプロバイダー固有の機能を参照)
-
JavaベースのJDBC(たとえば、SQL Developer)には、文字セットを処理する独自のメソッドがあります(詳細については、データベースJDBC開発者ガイド-グローバリゼーションサポートを参照してください)
4:端末、アプリケーション、または.sql
のエンコーディングの「実際の」文字セット ファイル
例:UTF-8
Windowsターミナルで作業している場合(つまり、SQL * plusを使用している場合)、コマンドchcp
を使用してコードページに問い合わせることができます。 、Unix / Linuxでは、同等のものはlocale charmap
またはecho $LANG
。ここからすべてのWindowsコードページ識別子のリストを取得できます:コードページ識別子。 UTF-8(chcp 65001
)の場合は注意してください )いくつかの問題があります。このディスカッションを参照してください。
.sql
を使用する場合 ファイルとTOADやSQL-Developerなどのエディタでは、保存オプションを確認する必要があります。通常、UTF-8
のような値を選択できます 、ANSI
、ISO-8859-1
、など。ANSI
Windows ANSIコードページを意味し、通常はCP1252
、HKLM\SYSTEM\ControlSet001\Control\Nls\CodePage\ACP
でレジストリをチェックインできます。 またはここ:National Language Support(NLS)APIリファレンス
[Microsoftはこの参照を削除しました。WebアーカイブのNationalLanguageSupport(NLS)API参照から取得してください]
これらすべての値を設定するにはどうすればよいですか?
最も重要なポイントは、NLS_LANG
と一致させることです そして、端末の「実際の」文字セット、それぞれ。アプリケーションまたは.sql
のエンコーディング ファイル
一般的なペアは次のとおりです。
-
CP850->
WE8PC850
-
CP1252またはANSI(「ウエスタン」PCの場合)->
WE8MSWIN1252
-
ISO-8859-1->
WE8ISO8859P1
-
ISO-8859-15->
WE8ISO8859P15
-
UTF-8->
AL32UTF8
または、このクエリを実行してさらに取得します:
SELECT VALUE AS ORACLE_CHARSET, UTL_I18N.MAP_CHARSET(VALUE) AS IANA_NAME
FROM V$NLS_VALID_VALUES
WHERE PARAMETER = 'CHARACTERSET';
テクノロジーによっては、生活が楽になります。 OracleのODP.NET(管理されていないドライバ)またはODBCドライバは、NLS_LANG
から文字セットを自動的に継承します。 値なので、上からの条件は常に真です。
クライアントのNLS_LANG値をデータベースのNLS_CHARACTERSET
と等しく設定する必要がありますか 価値?
いいえ、必ずしもそうとは限りません。たとえば、データベースがある場合 文字セットNLS_CHARACTERSET=AL32UTF8
およびクライアント 文字セットNLS_LANG=.ZHS32GB18030
これらの文字セットは完全に異なりますが、問題なく動作します(クライアントが実際にGB18030を使用している場合)。 GB18030は、UTF-8
のように、中国語で一般的に使用される文字セットです。 すべてのUnicode文字をサポートします。
たとえば、NLS_CHARACTERSET=AL32UTF8
がある場合 およびNLS_LANG=.WE8ISO8859P1
それも機能します(クライアントが実際にISO-8859-P1を使用している場合)。ただし、データベースには、クライアントが表示できない文字が格納されている場合があります。代わりに、クライアントはプレースホルダーを表示します(例:¿
。
とにかく、適切な場合は、NLS_LANGとNLS_CHARACTERSETの値を一致させると便利です。それらが等しい場合は、データベースに格納されている可能性のある文字も表示でき、ターミナルに入力したり、.sqlファイルに書き込んだ文字もデータベースに格納でき、プレースホルダーに置き換えられないことを確認できます。
補足
「NLS_LANG文字セットはデータベースの文字セットと同じである必要があります」(ここでもSOにあります)のようなアドバイスを何度も読むことができます。これは単に真実ではなく、一般的な神話です!
証拠は次のとおりです:
C:\>set NLS_LANG=.AL32UTF8
C:\>sqlplus ...
SQL> SET SERVEROUTPUT ON
SQL> DECLARE
2 CharSet VARCHAR2(20);
3 BEGIN
4 SELECT VALUE INTO Charset FROM nls_database_parameters WHERE parameter = 'NLS_CHARACTERSET';
5 DBMS_OUTPUT.PUT_LINE('Database NLS_CHARACTERSET is '||Charset);
6 IF UNISTR('\20AC') = '€' THEN
7 DBMS_OUTPUT.PUT_LINE ( '"€" is equal to U+20AC' );
8 ELSE
9 DBMS_OUTPUT.PUT_LINE ( '"€" is not the same as U+20AC' );
10 END IF;
11 END;
12 /
Database NLS_CHARACTERSET is AL32UTF8
"€" is not the same as U+20AC
PL/SQL procedure successfully completed.
クライアントとデータベースの両方の文字セットはAL32UTF8
です ただし、文字が一致しません。理由は、私のcmd.exe
したがって、SQL*PlusもWindowsCP1252を使用します。したがって、それに応じてNLS_LANGを設定する必要があります:
C:\>chcp
Active code page: 1252
C:\>set NLS_LANG=.WE8MSWIN1252
C:\>sqlplus ...
SQL> SET SERVEROUTPUT ON
SQL> DECLARE
2 CharSet VARCHAR2(20);
3 BEGIN
4 SELECT VALUE INTO Charset FROM nls_database_parameters WHERE parameter = 'NLS_CHARACTERSET';
5 DBMS_OUTPUT.PUT_LINE('Database NLS_CHARACTERSET is '||Charset);
6 IF UNISTR('\20AC') = '€' THEN
7 DBMS_OUTPUT.PUT_LINE ( '"€" is equal to U+20AC' );
8 ELSE
9 DBMS_OUTPUT.PUT_LINE ( '"€" is not the same as U+20AC' );
10 END IF;
11 END;
12 /
Database NLS_CHARACTERSET is AL32UTF8
"€" is equal to U+20AC
PL/SQL procedure successfully completed.
この例も検討してください:
CREATE TABLE ARABIC_LANGUAGE (
LANG_CHAR VARCHAR2(20),
LANG_NCHAR NVARCHAR2(20));
INSERT INTO ARABIC_LANGUAGE VALUES ('العربية', 'العربية');
NLS_LANG
には2つの異なる値を設定する必要があります 単一のステートメントの場合-これは不可能です。