字符集转换的问题~

wh62592855 2009-10-23 01:37:44
刚在网上搜了些文章 可还是感觉自己对这个字符集理解的不够透彻 如果哪位有好点的文章给推荐一份吧

先来说说现在碰到的问题吧 如下面代码所示
C:\Documents and Settings\Admin>chcp
活动的代码页: 936
C:\Documents and Settings\Admin>set nls_lang=AMERICAN_AMERICA.UTF8

C:\Documents and Settings\Admin>sqlplus "/ as sysdba"

SQL*Plus: Release 10.2.0.1.0 - Production on Fri Oct 23 13:28:24 2009

Copyright (c) 1982, 2005, Oracle. All rights reserved.


Connected to:
Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - Production
With the Partitioning, OLAP and Data Mining options
SQL> create table tt(name varchar2(100));

Table created.

SQL> insert into tt values('一');

1 row created.

SQL> insert into tt values('二');

1 row created.

SQL> commit;

Commit complete.

SQL> select * from tt;

NAME
--------------------------------------------------------------------------------




SQL>
SQL> Disconnected from Oracle Database 10g Enterprise Edition Release 10.2.0.1.0
- Production
With the Partitioning, OLAP and Data Mining options

C:\Documents and Settings\Admin>set nls_lang=SIMPLIFIED CHINESE_CHINA.ZHS16GBK

C:\Documents and Settings\Admin>sqlplus "/ as sysdba"

SQL*Plus: Release 10.2.0.1.0 - Production on 星期五 10月 23 13:29:49 2009

Copyright (c) 1982, 2005, Oracle. All rights reserved.


连接到:
Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - Production
With the Partitioning, OLAP and Data Mining options

SQL> select * from tt;

NAME
--------------------------------------------------------------------------------


??

SQL> insert into tt values('三');

已创建 1 行。

SQL> insert into tt values('四');

已创建 1 行。

SQL> commit;

提交完成。

SQL> select * from tt;

NAME
--------------------------------------------------------------------------------


??



SQL>
SQL> 从 Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - Production
With the Partitioning, OLAP and Data Mining options 断开

C:\Documents and Settings\Admin>set nls_lang=AMERICAN_AMERICA.UTF8

C:\Documents and Settings\Admin>sqlplus "/ as sysdba"

SQL*Plus: Release 10.2.0.1.0 - Production on Fri Oct 23 13:30:27 2009

Copyright (c) 1982, 2005, Oracle. All rights reserved.


Connected to:
Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - Production
With the Partitioning, OLAP and Data Mining options

SQL> select * from tt;

NAME
--------------------------------------------------------------------------------






SQL>


1、
用chcp显示出来的936应该代表的是我操作系统的字符集吧?

2、
为什么
用SIMPLIFIED CHINESE_CHINA.ZHS16GBK插入的数据在UTF8下显示不出来
用UTF8插入的数据在set nls_lang=SIMPLIFIED CHINESE_CHINA.ZHS16GBK后也显示不出来
一个显示乱码 一个显示问号?

3、
我的环境是WINDOWS XP+ORACLE 10GR2
记得前几天看EYGLE的一本书上写着字符集分三个
数据库字符集 客户端字符集 客户端应用字符集
那SQL*PLUS算是客户端还是客户端应用呢

SQL> select * from nls_database_parameters;

PARAMETER VALUE
------------------------------ ------------------------------
NLS_LANGUAGE AMERICAN
NLS_TERRITORY AMERICA
NLS_CURRENCY $
NLS_ISO_CURRENCY AMERICA
NLS_NUMERIC_CHARACTERS .,
NLS_CHARACTERSET UTF8
NLS_CALENDAR GREGORIAN
NLS_DATE_FORMAT DD-MON-RR
NLS_DATE_LANGUAGE AMERICAN
NLS_SORT BINARY
NLS_TIME_FORMAT HH.MI.SSXFF AM

PARAMETER VALUE
------------------------------ ------------------------------
NLS_TIMESTAMP_FORMAT DD-MON-RR HH.MI.SSXFF AM
NLS_TIME_TZ_FORMAT HH.MI.SSXFF AM TZR
NLS_TIMESTAMP_TZ_FORMAT DD-MON-RR HH.MI.SSXFF AM TZR
NLS_DUAL_CURRENCY $
NLS_COMP BINARY
NLS_LENGTH_SEMANTICS BYTE
NLS_NCHAR_CONV_EXCP FALSE
NLS_NCHAR_CHARACTERSET UTF8
NLS_RDBMS_VERSION 10.2.0.1.0

20 rows selected.

SQL>

注册表里所有的NLS_LANG都设置的是AMERICAN_AMERICA.UTF8

希望通过这个帖子能让我彻底搞清楚字符集~大家帮帮忙~
...全文
320 19 打赏 收藏 转发到动态 举报
写回复
用AI写文章
19 条回复
切换为时间正序
请发表友善的回复…
发表回复
inthirties 2009-10-24
  • 打赏
  • 举报
回复
我觉得自己讲的很清楚了呀,

星期一看我的blog吧。
inthirties 2009-10-24
  • 打赏
  • 举报
回复
啊,我这里解释的还不清楚么。
wh62592855 2009-10-24
  • 打赏
  • 举报
回复
自己对字符集方面的知识还是比较匮乏的

老大有没有什么好的文章推荐一份呀?
就比如说各种字符集的编码规则(比如说用2个字节还是3个字节...),他们之间的范围关系(比如说谁是谁的超级,谁是谁的子集),还有他们的转换关系(比如说从A到B可以转,而从B到A转就会出现乱码)

我刚才搜了下没搜到太好的 我再去搜搜看 不过马上就熄灯了 呵呵
wh62592855 2009-10-24
  • 打赏
  • 举报
回复
恩 好的我会的

好了
结贴
inthirties 2009-10-24
  • 打赏
  • 举报
回复
呵呵呵,清楚了就好,关注我周一早上的博客文章吧。
wh62592855 2009-10-24
  • 打赏
  • 举报
回复
[Quote=引用 14 楼 inthirties 的回复:]
啊,我这里解释的还不清楚么。
[/Quote]呵呵 你是讲的很清楚了呀
可是这里只涉及到了UTF8和GBK嘛
我的意思就是说还有些其他字符集之间的关系之类的
ty_tarena_pger 2009-10-24
  • 打赏
  • 举报
回复
不错,收藏了
wh62592855 2009-10-23
  • 打赏
  • 举报
回复
呵呵 先回一个
慢慢再看
免得你超过3次连续回帖限制
inthirties 2009-10-23
  • 打赏
  • 举报
回复
实验一,你应该不会有疑问,因为你知道客户端和服务器段一致。

关键是实验二
怎么我用SIMPLIFIED CHINESE_CHINA.ZHS16GBK的时候,看到了乱码,但是存进去却不是乱码。究竟是怎么回事呀。
我们来看 一,二两条记录,根据上面的回答,我们知道一,二进去的时候,没有转码,所以两个字节。 我们现在来显示,由于客户端是SIMPLIFIED CHINESE_CHINA.ZHS16GBK,和服务器不一致,这时候,服务器和客户端知道要转码了。由UTF8致GBK, 很显然,这里转是有错误的,所以一,二是乱码了。

在来看三 四, 三,四是在GBK的情况下进去的,这时候很显然了,不一致要转码,中文转为utf8,三个字节,显示的时候,一样的,不一致,要转码,本来进去就是utf8进去的,转成GBK当然没有问题了,所以也就正常显示了。

在看实验三

为什么我们set nls_lang=AMERICAN_AMERICA.UTF8后,再看刚刚做进去的三 四又乱码叻。

还是字符集的秘密,这是和服务器一致,不会转码,

一,二是GBK的两字节,既然不转码,过来就正常显示了。

三,四呢是UTF的三字节,现在不转码,三字节过来用GBK怎么能正常显示了。

当然就出现乱码了呀。

在字符集的问题中,抓住关键的地方,就是转码的问题,始终要记得,决定转码的是Oracle客户端和服务段的编码,和客户端系统的是没有关系的,虽然没有关系,只是决定显示的而已。

这里你可以在linux下用UTF8的系统, 做一下测试,你会发现和这里的结果又不一致。但是道理是相同的。

有兴趣,可以自己先分析一下结果,然后再做实验,看你是是不对的,如果分析对了,呵呵呵,我这里讲的就没有白费叻。
inthirties 2009-10-23
  • 打赏
  • 举报
回复
[Quote=引用 9 楼 inthirties 的回复:]
这里很好解释呀

一个一个来
实验一
C:\Documents and Settings\Admin>set nls_lang=AMERICAN_AMERICA.UTF8
和你数据库的代码一致了。

所以这个过程Oracle将不会转码,你输入一个中文,你的系统是GBK的编码,又不发生转码,原封不动的过去了,所以你看到的 dump(name)时候,第一二两条记录都是2个字节。虽然你的Oracle客户端是UTF8.
-------------------- ------------------------------
一                    Typ=1 Len=2: 210,187
二                  Typ=1 Len=2: 182,254

实验二,同上理,
你这次是set nls_lang=SIMPLIFIED CHINESE_CHINA.ZHS16GBK和数据库不一致了,将把GBK转为UTF8,也就是2个字节变3个字节。
也就是
三                            Typ=1 Len=3: 228,184,137
四                            Typ=1 Len=3: 229,155,155

实验三
第三次存的时候,和实验二一样
所以
一                            Typ=1 Len=3: 228,184,128
二                            Typ=1 Len=3: 228,186,140
[/Quote]

上面是你实验 的结果, 完全是合理的,下面我们来解释一下,为什么有时候select是乱码,有时有时正常的,完全把你都搞糊涂了。
inthirties 2009-10-23
  • 打赏
  • 举报
回复
这里很好解释呀

一个一个来
实验一
C:\Documents and Settings\Admin>set nls_lang=AMERICAN_AMERICA.UTF8
和你数据库的代码一致了。

所以这个过程Oracle将不会转码,你输入一个中文,你的系统是GBK的编码,又不发生转码,原封不动的过去了,所以你看到的 dump(name)时候,第一二两条记录都是2个字节。虽然你的Oracle客户端是UTF8.
-------------------- ------------------------------
一 Typ=1 Len=2: 210,187
二 Typ=1 Len=2: 182,254

实验二,同上理,
你这次是set nls_lang=SIMPLIFIED CHINESE_CHINA.ZHS16GBK和数据库不一致了,将把GBK转为UTF8,也就是2个字节变3个字节。
也就是
三 Typ=1 Len=3: 228,184,137
四 Typ=1 Len=3: 229,155,155

实验三
第三次存的时候,和实验二一样
所以
一 Typ=1 Len=3: 228,184,128
二 Typ=1 Len=3: 228,186,140



wh62592855 2009-10-23
  • 打赏
  • 举报
回复
C:\Documents and Settings\Admin>set nls_lang=SIMPLIFIED CHINESE_CHINA.ZHS16GBK

C:\Documents and Settings\Admin>sqlplus "/ as sysdba"

SQL*Plus: Release 10.2.0.1.0 - Production on 星期五 10月 23 16:14:37 2009

Copyright (c) 1982, 2005, Oracle. All rights reserved.


连接到:
Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - Production
With the Partitioning, OLAP and Data Mining options

SQL> select * from tt;

NAME
--------------------------------------------------------------------------------


??



SQL> insert into tt values('一');

已创建 1 行。

SQL> insert into tt values('二');

已创建 1 行。

SQL> commit;

提交完成。
SQL> select name,dump(name) from tt;

NAME DUMP(NAME)
------------------------------ ------------------------------
? Typ=1 Len=2: 210,187
?? Typ=1 Len=2: 182,254
三 Typ=1 Len=3: 228,184,137
四 Typ=1 Len=3: 229,155,155
一 Typ=1 Len=3: 228,184,128
二 Typ=1 Len=3: 228,186,140

已选择6行。


好的 谢谢回答~呵呵 我自己再想想
vc555 2009-10-23
  • 打赏
  • 举报
回复
5L的问题你自己搜搜吧。

给你的那个查询sql你要最好在两种nls_lang下插入相同的数据后,再执行。这样你就会发现在数据库的相同字符集下,相同的插入字符却有完全不同的编码。这就是乱码的原因。
wh62592855 2009-10-23
  • 打赏
  • 举报
回复
SQL> select name,dump(name) from tt;

NAME DUMP(NAME)
-------------------- ------------------------------
一 Typ=1 Len=2: 210,187
二 Typ=1 Len=2: 182,254
涓? Typ=1 Len=3: 228,184,137
鍥? Typ=1 Len=3: 229,155,155
wh62592855 2009-10-23
  • 打赏
  • 举报
回复
先问个问题哦
注册表里的那些NLS_LANG和我在命令行下set nls_lang=SIMPLIFIED CHINESE_CHINA.ZHS16GBK有什么关联吗?

如你所说,ORACLE是通过NLS_LANG来判断客户端和数据库字符集是否一致的。那么ORACLE是通过我在命令行里SET的NLS_LANG还是根据注册表中的NLS_LANG呢?二者间存在什么优先级关系吗?

呵呵 不要嫌麻烦哦
vc555 2009-10-23
  • 打赏
  • 举报
回复
[Quote=引用 3 楼 wh62592855 的回复:]
不是说如果ORACLE发现服务器端和客户端的字符集不一致的时候会自动进行转换的么
[/Quote]
是的。但是oracle是怎么发现“服务器端和客户端的字符集不一致”的呢?
就是通过你设置的nls_lang参数中的字符集参数和数据库字符集对比知道的。
你把两者设置成一样,而os实际又没用nls_lang所指的字符集。这时insert数据的字符集就会出问题了。
具体你可以select name,dump(name) from t;看看。
wh62592855 2009-10-23
  • 打赏
  • 举报
回复
[Quote=引用 1 楼 vc555 的回复:]
1.是。
2.两个编码方式长度都不一样。不是乱码倒怪了。
3.总之就是用你os的nls_lang环境变量中的字符集设置值。
[/Quote]第二点和第三点能讲得详细点吗

不是说如果ORACLE发现服务器端和客户端的字符集不一致的时候会自动进行转换的么
ngx20080110 2009-10-23
  • 打赏
  • 举报
回复
关注,学习
vc555 2009-10-23
  • 打赏
  • 举报
回复
1.是。
2.两个编码方式长度都不一样。不是乱码倒怪了。
3.总之就是用你os的nls_lang环境变量中的字符集设置值。

17,377

社区成员

发帖
与我相关
我的任务
社区描述
Oracle 基础和管理
社区管理员
  • 基础和管理社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧