Oracle
 sql >> Teknologi Basis Data >  >> RDS >> Oracle

OdbcConnection mengembalikan Karakter Cina sebagai ?

Masalah dengan set karakter cukup umum, izinkan saya mencoba memberikan beberapa catatan umum.

Pada prinsipnya Anda harus mempertimbangkan empat pengaturan set karakter yang berbeda.

1 dan 2:NLS_CHARACTERSET dan NLS_NCHAR_CHARACTERSET

Contoh:AL32UTF8

Mereka didefinisikan hanya di database Anda, Anda dapat menginterogasi mereka dengan

    SELECT * 
    FROM V$NLS_PARAMETERS 
    WHERE PARAMETER IN ('NLS_CHARACTERSET', 'NLS_NCHAR_CHARACTERSET');

Pengaturan ini menentukan karakter (dalam format apa) yang dapat disimpan dalam database Anda - tidak lebih, tidak kurang. Ini memerlukan beberapa upaya (lihat Migrasi Kumpulan Karakter dan/atau Asisten Migrasi Database Oracle untuk Unicode) jika Anda harus mengubahnya pada database yang ada.

3:NLS_LANG

Contoh:AMERICAN_AMERICA.AL32UTF8

Nilai ini ditentukan hanya pada klien Anda. NLS_LANG tidak ada hubungannya dengan kemampuan untuk menyimpan karakter dalam database. Ini digunakan untuk memberi tahu Oracle set karakter apa yang Anda gunakan di sisi klien. Ketika Anda menetapkan nilai NLS_LANG (misalnya ke AL32UTF8) maka Anda cukup memberi tahu database Oracle "klien saya menggunakan set karakter AL32UTF8" - itu tidak berarti bahwa klien Anda benar-benar menggunakan AL32UTF8! (lihat di bawah #4)

NLS_LANG dapat didefinisikan oleh variabel lingkungan NLS_LANG atau dengan Windows Registry di HKLM\SOFTWARE\Wow6432Node\ORACLE\KEY_%ORACLE_HOME_NAME%\NLS_LANG (untuk 32 bit), resp. HKLM\SOFTWARE\ORACLE\KEY_%ORACLE_HOME_NAME%\NLS_LANG (untuk 64bit). Bergantung pada aplikasi Anda, mungkin ada cara lain untuk menentukan NLS_LANG, tetapi mari tetap berpegang pada dasar-dasarnya. Jika nilai NLS_LANG tidak diberikan maka Oracle default ke AMERICAN_AMERICA.US7ASCII

Format NLS_LANG adalah NLS_LANG=language_territory.charset . {charset } bagian dari NLS_LANG bukan ditampilkan dalam tabel atau tampilan sistem apa pun. Semua komponen definisi NLS_LANG adalah opsional, jadi semua definisi berikut valid:NLS_LANG=.WE8ISO8859P1 , NLS_LANG=_GERMANY , NLS_LANG=AMERICAN , NLS_LANG=ITALIAN_.WE8MSWIN1252 , NLS_LANG=_BELGIUM.US7ASCII .

Seperti yang dinyatakan di atas bagian {charset} dari NLS_LANG tidak tersedia dalam database di tabel/tampilan sistem apa pun atau fungsi apa pun. Sebenarnya ini benar, namun Anda dapat menjalankan kueri ini:

SELECT DISTINCT CLIENT_CHARSET
FROM V$SESSION_CONNECT_INFO
WHERE (SID, SERIAL#) = (SELECT SID, SERIAL# FROM v$SESSION WHERE AUDSID = USERENV('SESSIONID'));

Itu harus mengembalikan set karakter dari NLS_LANG Anda saat ini pengaturan - namun berdasarkan pengalaman saya, nilainya sering NULL atau Unknown , yaitu tidak dapat diandalkan.

Temukan lebih banyak informasi yang sangat berguna di sini:FAQ NLS_LANG

Perhatikan, beberapa teknologi tidak menggunakan NLS_LANG , pengaturan di sana tidak berpengaruh, misalnya:

  • Driver Terkelola ODP.NET bukan NLS_LANG peka. Ini hanya sensitif lokal .NET. (lihat Penyedia Data untuk Panduan Pengembang .NET)

  • OraOLEDB (dari Oracle) selalu menggunakan UTF-16 (lihat Fitur Khusus Penyedia OraOLEDB)

  • JDBC berbasis Java (misalnya SQL Developer) memiliki metodenya sendiri untuk menangani set karakter (lihat Panduan Pengembang JDBC Database - Dukungan Globalisasi untuk detail lebih lanjut)

4:Kumpulan karakter "asli" dari terminal Anda, aplikasi Anda, atau penyandian .sql file

Contoh:UTF-8

Jika Anda bekerja pada terminal Windows (yaitu dengan SQL*plus), Anda dapat menginterogasi halaman kode dengan perintah chcp , di Unix/Linux yang setara adalah locale charmap atau echo $LANG . Anda bisa mendapatkan daftar semua pengidentifikasi halaman kode Windows dari sini:Pengidentifikasi Halaman Kode. Catatan, untuk UTF-8 (chcp 65001 ) ada beberapa masalah, lihat diskusi ini.

Jika Anda bekerja dengan .sql file dan editor seperti TOAD atau SQL-Developer Anda harus memeriksa opsi simpan. Biasanya Anda dapat memilih nilai seperti UTF-8 , ANSI , ISO-8859-1 , dll.ANSI berarti halaman kode ANSI Windows, biasanya CP1252 , Anda dapat memeriksa di Registry Anda di HKLM\SYSTEM\ControlSet001\Control\Nls\CodePage\ACP atau di sini:Referensi API Dukungan Bahasa Nasional (NLS)

[Microsoft menghapus referensi ini, ambil dari arsip web Referensi API Dukungan Bahasa Nasional (NLS) web]

Bagaimana cara menyetel semua nilai ini?

Poin terpenting adalah mencocokkan NLS_LANG dan set karakter "asli" Anda dari terminal Anda, resp. aplikasi atau penyandian .sql . Anda file

Beberapa pasangan umum adalah:

  • CP850 -> WE8PC850

  • CP1252 atau ANSI (untuk PC "Barat") -> WE8MSWIN1252

  • ISO-8859-1 -> WE8ISO8859P1

  • ISO-8859-15 -> WE8ISO8859P15

  • UTF-8 -> AL32UTF8

Atau jalankan kueri ini untuk mendapatkan lebih banyak lagi:

SELECT VALUE AS ORACLE_CHARSET, UTL_I18N.MAP_CHARSET(VALUE) AS IANA_NAME
FROM V$NLS_VALID_VALUES
WHERE PARAMETER = 'CHARACTERSET';

Beberapa teknologi membuat hidup Anda lebih mudah, mis. ODP.NET (driver yang tidak diatur) atau driver ODBC dari Oracle secara otomatis mewarisi set karakter dari NLS_LANG nilai, jadi kondisi dari atas selalu benar.

Apakah nilai NLS_LANG klien harus disetel sama dengan basis data NLS_CHARACTERSET nilai?

Tidak, belum tentu! Misalnya, jika Anda memiliki database kumpulan karakter NLS_CHARACTERSET=AL32UTF8 dan klien kumpulan karakter NLS_LANG=.ZHS32GB18030 maka itu akan berfungsi tanpa masalah (asalkan klien Anda benar-benar menggunakan GB18030), meskipun rangkaian karakter ini sama sekali berbeda. GB18030 adalah kumpulan karakter yang biasa digunakan untuk bahasa Cina, seperti UTF-8 ini mendukung semua karakter Unicode.

Jika sudah, misalnya NLS_CHARACTERSET=AL32UTF8 dan NLS_LANG=.WE8ISO8859P1 itu juga akan berfungsi (sekali lagi, asalkan klien Anda benar-benar menggunakan ISO-8859-P1). Namun, database dapat menyimpan karakter yang tidak dapat ditampilkan oleh klien Anda, sebaliknya klien akan menampilkan placeholder (mis. ¿ ).

Bagaimanapun, adalah bermanfaat untuk memiliki nilai NLS_LANG dan NLS_CHARACTERSET yang cocok, jika cocok. Jika mereka sama, Anda dapat yakin bahwa karakter apa pun yang dapat disimpan dalam database juga dapat ditampilkan dan karakter apa pun yang Anda masukkan di terminal Anda atau tulis di file .sql Anda juga dapat disimpan dalam database dan tidak digantikan oleh placeholder.

Suplemen

Sering kali Anda dapat membaca saran seperti "Set karakter NLS_LANG harus sama dengan set karakter database Anda" (juga di sini di SO). Ini sama sekali tidak benar dan merupakan mitos yang populer!

Ini buktinya:

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.

Kedua, set karakter klien dan basis data adalah AL32UTF8 , namun karakternya tidak cocok. Alasannya adalah, cmd.exe saya dan dengan demikian juga SQL*Plus menggunakan Windows CP1252. Oleh karena itu saya harus mengatur NLS_LANG yang sesuai:

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.

Perhatikan juga contoh ini:

CREATE TABLE ARABIC_LANGUAGE (
    LANG_CHAR VARCHAR2(20), 
    LANG_NCHAR NVARCHAR2(20));

INSERT INTO ARABIC_LANGUAGE VALUES ('العربية', 'العربية');

Anda perlu menyetel dua nilai berbeda untuk NLS_LANG untuk satu pernyataan - yang tidak mungkin.




  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Bagaimana Mendapatkan Quarter From Date di Oracle?

  2. Tabel bermutasi, pemicu/fungsi mungkin tidak melihatnya (menghentikan nilai rata-rata turun di bawah 2,5)

  3. Jalankan 2 kueri secara bersamaan di Oracle SQL Developer?

  4. Parameter Oracle dengan pernyataan IN?

  5. ORACLE Hubungkan dengan klausa yang setara di SQL Server