sql >> データベース >  >> RDS >> Oracle

OdbcConnectionは漢字を?として返します

    文字セットの問題は非常に一般的です。一般的な注意事項をいくつか挙げてみましょう。

    原則として、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=.WE8ISO8859P1NLS_LANG=_GERMANYNLS_LANG=AMERICANNLS_LANG=ITALIAN_.WE8MSWIN1252NLS_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のような値を選択できます 、ANSIISO-8859-1 、など。ANSI Windows ANSIコードページを意味し、通常はCP1252HKLM\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つの異なる値を設定する必要があります 単一のステートメントの場合-これは不可能です。




    1. Oracleでは値が先行ゼロで表示されていません

    2. XEvent Profilerを使用して、SQLServerでクエリをキャプチャします

    3. EnterpriseEditionでNOEXPANDヒントを使用するもう1つの理由

    4. Oracleを使用したAWSPythonLambda