gpt4 book ai didi

c# - OdbcConnection返回汉字为“?”

转载 作者:行者123 更新时间:2023-11-30 13:30:29 29 4
gpt4 key购买 nike

我有一个Oracle数据库,以简体中文存储一些数据值。我创建了一个应该显示此信息的ASP.net MVC C#网页。我正在使用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;


t有数据,但是所有应该是汉字的内容只是一系列“ ?????”

最佳答案

字符集的问题很常见,让我尝试给出一些一般性注释。

原则上,您必须考虑四种不同的字符集设置。

1和2:NLS_CHARACTERSETNLS_NCHAR_CHARACTERSET

示例:AL32UTF8

它们仅在您的数据库上定义,您可以使用

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


这些设置定义了哪些字符(以哪种格式)可以存储在数据库中-不多也不少。如果必须在现有数据库上进行更改,则需要花费一些精力(请参见 Character Set Migration和/或 Oracle Database Migration Assistant for Unicode)。

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的{charset}部分未显示在任何系统表或视图中。 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托管驱动程序不敏感。它仅对.NET语言环境敏感。 (请参见 Data Provider for .NET Developer's Guide
OraOLEDB(来自Oracle)始终使用UTF-16(请参见 OraOLEDB Provider Specific Features
基于Java的JDBC(例如SQL Developer)具有自己的处理字符集的方法(有关更多详细信息,请参见 Database JDBC Developer's Guide - Globalization Support


4:终端,应用程序或 NLS_LANG文件的编码的“真实”字符集

示例: .sql

如果您在Windows终端上工作(即使用SQL * plus),则可以使用命令 UTF-8询问代码页,在Unix / Linux上等效为 chcplocale charmap。您可以从以下位置获取所有Windows代码页标识符的列表: Code Page Identifiers。注意,对于UTF-8( echo $LANG),存在一些问题,请参见 this discussion

如果使用 chcp 65001文件和TOAD或SQL-Developer之类的编辑器,则必须检查保存选项。通常,您可以选择 .sqlUTF-8ANSI等值。
  ISO-8859-1表示Windows ANSI代码页,通常为 ANSI,您可以在 CP1252或以下位置签入注册表: National Language Support (NLS) API Reference

[Microsoft删除了此引用,以网络存档 National Language Support (NLS) API Reference的形式使用]

如何设置所有这些值?

最重要的一点是分别匹配 HKLM\SYSTEM\ControlSet001\Control\Nls\CodePage\ACP和终端的“真实”字符集。应用程序或 NLS_LANG文件的编码

一些常见的对是:


CP850-> .sql
CP1252或ANSI(对于“西方” PC)-> WE8PC850
ISO-8859-1-> WE8MSWIN1252
ISO-8859-15-> WE8ISO8859P1
UTF-8-> WE8ISO8859P15


或运行此查询以获取更多信息:

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驱动程序会自动从 AL32UTF8值继承字符集,因此上述条件始终为true。

是否需要将客户端NLS_LANG值设置为等于数据库 NLS_LANG值?

不,不一定!例如,如果您具有数据库字符集 NLS_CHARACTERSET和客户端字符集 NLS_CHARACTERSET=AL32UTF8,则尽管这些字符集完全不同,但它可以正常工作(前提是您的客户端确实使用GB18030)。 GB18030是中文常用的字符集,例如 NLS_LANG=.ZHS32GB18030,它支持所有Unicode字符。

例如,如果有 UTF-8NLS_CHARACTERSET=AL32UTF8,它也将起作用(再次,前提是您的客户确实使用ISO-8859-P1)。但是,数据库可能会存储您的客户端无法显示的字符,而是客户端将显示一个占位符(例如 NLS_LANG=.WE8ISO8859P1)。

无论如何,具有匹配的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以及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.


还请考虑以下示例:

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

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


您需要为单个语句的 cmd.exe设置两个不同的值-这是不可能的。

关于c# - OdbcConnection返回汉字为“?”,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33783902/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com