我有一个Oracle数据库,以简体中文存储一些数据值.我创建了一个ASP.net MVC C#网页,该网页应该显示这些信息.我正在使用a OdbcConnection来检索数据,但是当我运行da.Fill(t)命令时,值返回为"?"
OdbcCommand cmd = new OdbcCommand();
cmd.CommandText = select;
OdbcConnection SqlConn = new OdbcConnection("Driver={Oracle in instantclient_11_2};Dbq=Database;Uid=Username;pwd=password;");
DataTable t = new DataTable();
cmd.Connection = SqlConn;
SqlConn.Open();
OdbcDataAdapter da = new OdbcDataAdapter(cmd);
SqlConn.Close();
da.Fill(t);
return t;
Run Code Online (Sandbox Code Playgroud)
t 有数据,但应该是汉字的一切只是一系列的"?????"
Wer*_*eit 11
字符集的问题很常见,让我试着给出一些一般性的注意事项.
原则上,您必须考虑四种不同的字符集设置.
NLS_CHARACTERSET和NLS_NCHAR_CHARACTERSET例: AL32UTF8
它们仅在您的数据库中定义,您可以使用它们进行查询
SELECT *
FROM V$NLS_PARAMETERS
WHERE PARAMETER IN ('NLS_CHARACTERSET', 'NLS_NCHAR_CHARACTERSET');
Run Code Online (Sandbox Code Playgroud)
这些设置定义了可以在数据库中存储哪些字符(以哪种格式存储) - 不多也不少.如果必须在现有数据库上进行更改,则需要一些工作(请参阅字符集迁移和/或Unicode的Oracle数据库迁移助手).
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 的{ charset }部分未显示在任何系统表或视图中.在NLS_LANG定义的所有组件都是可选的,所以下面的定义都是有效的:NLS_LANG=.WE8ISO8859P1,NLS_LANG=_GERMANY,NLS_LANG=AMERICAN,NLS_LANG=ITALIAN_.WE8MSWIN1252,NLS_LANG=_BELGIUM.US7ASCII.
如上所述,{charset}部分NLS_LANG在任何系统表/视图或任何函数的数据库中都不可用.严格来说这是真的,但是你可以运行这个查询:
SELECT DISTINCT CLIENT_CHARSET
FROM V$SESSION_CONNECT_INFO
WHERE (SID, SERIAL#) = (SELECT SID, SERIAL# FROM v$SESSION WHERE AUDSID = USERENV('SESSIONID'));
Run Code Online (Sandbox Code Playgroud)
它应该从您当前的NLS_LANG设置返回字符集- 但是根据我的经验,该值通常为NULL或者Unknown,即不可靠.
在此处查找更多非常有用的信息:NLS_LANG常见问题解答
注意,有些技术没有使用NLS_LANG,那里的设置没有任何影响,例如:
ODP.NET托管驱动程序不NLS_LANG敏感.它只对.NET语言环境敏感.(请参阅.NET Developer's Guide的数据提供程序)
OraOLEDB(来自Oracle)始终使用UTF-16(参见OraOLEDB Provider Specific Features)
基于Java的JDBC(例如SQL Developer)有自己的方法来处理字符集(有关详细信息,请参阅数据库JDBC开发人员指南 - 全球化支持)
.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或浏览:国家语言支持(NLS)API参考
[Microsoft删除了此引用,将其从Web存档国家语言支持(NLS)API参考中删除]
最重要的一点是匹配NLS_LANG终端的"真实"字符集.应用程序或.sql文件的编码
一些常见的配对是:
CP850 - > WE8PC850
CP1252或ANSI(在"Western"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';
Run Code Online (Sandbox Code Playgroud)
有些技术可以让您的生活更轻松,例如ODP.NET(非管理驱动程序)或Oracle的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.
Run Code Online (Sandbox Code Playgroud)
客户端和数据库字符集都是AL32UTF8,但字符不匹配.原因是,我cmd.exe和SQL*Plus也使用Windows CP1252.因此我必须相应地设置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.
Run Code Online (Sandbox Code Playgroud)
还要考虑这个例子:
CREATE TABLE ARABIC_LANGUAGE (
LANG_CHAR VARCHAR2(20),
LANG_NCHAR NVARCHAR2(20));
INSERT INTO ARABIC_LANGUAGE VALUES ('???????', '???????');
Run Code Online (Sandbox Code Playgroud)
您需要NLS_LANG为单个语句设置两个不同的值- 这是不可能的.
| 归档时间: |
|
| 查看次数: |
4256 次 |
| 最近记录: |