Oracle
 sql >> Baza danych >  >> RDS >> Oracle

OdbcConnection zwraca chińskie znaki jako ?

Problemy z zestawem znaków są dość powszechne, spróbuję podać kilka ogólnych uwag.

W zasadzie musisz wziąć pod uwagę cztery różne ustawienia zestawu znaków.

1 i 2:NLS_CHARACTERSET i NLS_NCHAR_CHARACTERSET

Przykład:AL32UTF8

Są one zdefiniowane tylko w swojej bazie danych, możesz je przesłuchać za pomocą

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

Te ustawienia określają, które znaki (w jakim formacie) mogą być przechowywane w Twojej bazie danych — nie więcej, nie mniej. Wymaga to trochę wysiłku (zobacz Migracja zestawu znaków i/lub Asystent migracji bazy danych Oracle dla Unicode), jeśli musisz to zmienić w istniejącej bazie danych.

3:NLS_LANG

Przykład:AMERICAN_AMERICA.AL32UTF8

Ta wartość jest zdefiniowana tylko na twoim kliencie. NLS_LANG nie ma nic wspólnego z możliwością przechowywania znaków w bazie danych. Służy do poinformowania Oracle, jakiego zestawu znaków używasz po stronie klienta. Kiedy ustawisz wartość NLS_LANG (na przykład na AL32UTF8), po prostu poinformujesz bazę danych Oracle „mój klient używa zestawu znaków AL32UTF8” - niekoniecznie oznacza to, że twój klient naprawdę używa AL32UTF8! (patrz poniżej 4)

NLS_LANG można zdefiniować za pomocą zmiennej środowiskowej NLS_LANG lub przez Rejestr systemu Windows pod adresem HKLM\SOFTWARE\Wow6432Node\ORACLE\KEY_%ORACLE_HOME_NAME%\NLS_LANG (dla wersji 32-bitowej), ewent. HKLM\SOFTWARE\ORACLE\KEY_%ORACLE_HOME_NAME%\NLS_LANG (dla wersji 64-bitowej). W zależności od aplikacji mogą istnieć inne sposoby określenia NLS_LANG, ale trzymajmy się podstaw. Jeśli wartość NLS_LANG nie zostanie podana, Oracle domyślnie ustawi ją na AMERICAN_AMERICA.US7ASCII

Format NLS_LANG to NLS_LANG=language_territory.charset . {zestaw znaków } częścią NLS_LANG nie pokazane w dowolnej tabeli systemowej lub widoku. Wszystkie składniki definicji NLS_LANG są opcjonalne, więc wszystkie poniższe definicje są poprawne:NLS_LANG=.WE8ISO8859P1 , NLS_LANG=_GERMANY , NLS_LANG=AMERICAN , NLS_LANG=ITALIAN_.WE8MSWIN1252 , NLS_LANG=_BELGIUM.US7ASCII .

Jak wspomniano powyżej, {charset} część NLS_LANG nie jest dostępna w bazie danych w żadnej tabeli/widoku systemowym ani żadnej funkcji. Ściśle mówiąc to prawda, jednak możesz uruchomić to zapytanie:

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

Powinien zwrócić zestaw znaków z twojego obecnego NLS_LANG ustawienie - jednak z mojego doświadczenia wynika, że ​​wartość jest często NULL lub Unknown , czyli nie jest wiarygodne.

Więcej przydatnych informacji znajdziesz tutaj:NLS_LANG FAQ

Uwaga, niektóre technologie nie wykorzystują NLS_LANG , ustawienia tam nie działają, na przykład:

  • Zarządzany sterownik ODP.NET nie jest NLS_LANG wrażliwy. Jest wrażliwy tylko na ustawienia regionalne platformy .NET. (zobacz Dostawca danych dla .NET Developer's Guide)

  • OraOLEDB (od Oracle) zawsze używaj UTF-16 (zobacz Specyficzne funkcje dostawcy OraOLEDB)

  • JDBC oparty na Javie (na przykład SQL Developer) ma własne metody radzenia sobie z zestawami znaków (więcej szczegółów znajdziesz w Database JDBC Developer's Guide - Globalization Support)

4:"Prawdziwy" zestaw znaków twojego terminala, twojej aplikacji lub kodowania .sql pliki

Przykład:UTF-8

Jeśli pracujesz na terminalu Windows (np. z SQL*plus), możesz sprawdzić stronę kodową poleceniem chcp , w systemie Unix/Linux odpowiednikiem jest locale charmap lub echo $LANG . Listę wszystkich identyfikatorów stron kodowych systemu Windows można pobrać stąd:Identyfikatory stron kodowych. Uwaga, dla UTF-8 (chcp 65001 ) są pewne problemy, zobacz tę dyskusję.

Jeśli pracujesz z .sql plików i edytora typu TOAD lub SQL-Developer musisz sprawdzić opcje zapisu. Zwykle możesz wybrać wartości takie jak UTF-8 , ANSI , ISO-8859-1 itp.ANSI oznacza stronę kodową Windows ANSI, zwykle CP1252 , możesz sprawdzić w swoim Rejestrze pod adresem HKLM\SYSTEM\ControlSet001\Control\Nls\CodePage\ACP lub tutaj:Dokumentacja API National Language Support (NLS)

[Microsoft usunął to odniesienie, weź je z archiwum internetowego Dokumentacja API obsługi języków narodowych (NLS)]

Jak ustawić wszystkie te wartości?

Najważniejszym punktem jest dopasowanie NLS_LANG i twój "prawdziwy" zestaw znaków twojego terminala, ewent. aplikacji lub kodowania twojego pliku .sql pliki

Niektóre popularne pary to:

  • CP850 -> WE8PC850

  • CP1252 lub ANSI (w przypadku „zachodniego” komputera PC) -> WE8MSWIN1252

  • ISO-8859-1 -> WE8ISO8859P1

  • ISO-8859-15 -> WE8ISO8859P15

  • UTF-8 -> AL32UTF8

Lub uruchom to zapytanie, aby uzyskać więcej informacji:

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

Niektóre technologie ułatwiają życie, m.in. ODP.NET (sterownik unmanged) lub sterownik ODBC firmy Oracle automatycznie dziedziczy zestaw znaków z NLS_LANG wartość, więc warunek z góry jest zawsze prawdziwy.

Czy wymagane jest ustawienie wartości NLS_LANG klienta równej bazie danych NLS_CHARACTERSET wartość?

Nie, niekoniecznie! Na przykład, jeśli masz bazę danych zestaw znaków NLS_CHARACTERSET=AL32UTF8 i klient zestaw znaków NLS_LANG=.ZHS32GB18030 wtedy będzie działać bez problemu (pod warunkiem, że twój klient naprawdę używa GB18030), chociaż te zestawy znaków są zupełnie inne. GB18030 to zestaw znaków powszechnie używany w języku chińskim, np. UTF-8 obsługuje wszystkie znaki Unicode.

Jeśli masz na przykład NLS_CHARACTERSET=AL32UTF8 i NLS_LANG=.WE8ISO8859P1 to też zadziała (znowu, pod warunkiem, że twój klient naprawdę używa ISO-8859-P1). Jednak baza danych może przechowywać znaki, których twój klient nie jest w stanie wyświetlić, zamiast tego klient wyświetli symbol zastępczy (np. ¿ ).

W każdym razie korzystne jest posiadanie pasujących wartości NLS_LANG i NLS_CHARACTERSET, jeśli jest to odpowiednie. Jeśli są równe, możesz być pewien, że każdy znak, który może być przechowywany w bazie danych, może być również wyświetlony, a każdy znak, który wprowadzisz w terminalu lub zapiszesz w pliku .sql, może być również przechowywany w bazie danych i nie jest zastępowany przez symbol zastępczy.

Suplement

Tak wiele razy można przeczytać porady, takie jak „Zestaw znaków NLS_LANG musi być taki sam, jak zestaw znaków bazy danych” (również tutaj w SO). To po prostu nieprawda i popularny mit!

Oto dowód:

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.

Zestawy znaków klienta i bazy danych to AL32UTF8 , jednak znaki się nie zgadzają. Powodem jest to, że mój cmd.exe dlatego też SQL*Plus używa Windows CP1252. Dlatego muszę odpowiednio ustawić 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.

Rozważ także ten przykład:

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

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

Będziesz musiał ustawić dwie różne wartości dla NLS_LANG dla jednego oświadczenia - co nie jest możliwe.




  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Oracle JDBC i typ danych Oracle CHAR

  2. Dlaczego nie mogę wprowadzić tej daty do tabeli za pomocą sql?

  3. REMAINDER() Funkcja w Oracle

  4. Jak korzystać z Oracle SQL*Plus

  5. Jak uzyskać szerokość i długość z sdo_geometry w Oracle?