Oracle里令人头疼的生僻字处理案例

2024-05-09 12:12

本文主要是介绍Oracle里令人头疼的生僻字处理案例,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

事情起因

有小伙伴找到我问一下生僻字的问题,数据库是oracle 11g,字符集是zhs16gbk
 

image.png


下图里显示的??应该是“𧿹”这个字,算是个生僻字。
 

image.png


问应用厂家就说数据库字符集建错了,要改库的字符集。what???,这库都用了好几年了,现在改库字符集也不现实啊。
检查下字典点,看表里也是??显示

image.png

模拟测试

为了测试, 先创建个测试表,第1列是varchar2,第2列是nvarchar2
这里为了方便测试,使用scott用户

CREATE TABLE "SCOTT"."TEST_NAME" ( "BIANMA" NUMBER NOT NULL ENABLE, "VARCHAR2_NAME" VARCHAR2(200 BYTE), "NVARCHAR2_NAME" NVARCHAR2(200), CONSTRAINT "TEST_NAME_PK" PRIMARY KEY ("BIANMA") USING INDEX PCTFREE 10 INITRANS 2 MAXTRANS 255 STORAGE( INITIAL 65536 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645 PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1 BUFFER_POOL DEFAULT FLASH_CACHE DEFAULT CELL_FLASH_CACHE DEFAULT) TABLESPACE "USERS" ENABLE ) SEGMENT CREATION DEFERRED PCTFREE 10 PCTUSED 40 INITRANS 1 MAXTRANS 255 NOCOMPRESS LOGGING STORAGE( INITIAL 65536 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645 PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1 BUFFER_POOL DEFAULT FLASH_CACHE DEFAULT CELL_FLASH_CACHE DEFAULT) TABLESPACE "USERS" ;

创建如下图
 

image.png


这里提供几个把生僻字转换为Unicode的网址

http://unicode.wiicha.com/
https://www.bejson.com/convert/unicode_chinese/

查询一下这个字
 

image.png


\u是转换字符,用的时候去掉
查询一下

select utl_raw.cast_to_nvarchar2('d85fdff9') from dual;

image.png

在库里组合查询一下,看出来也可以显示

select utl_raw.cast_to_nvarchar2('d85fdff96307') from dual;

image.png


更新一下两个列里的内容

insert into  test_name  values (1,(select utl_raw.cast_to_nvarchar2('d85fdff96307') from dual),(select utl_raw.cast_to_nvarchar2('d85fdff96307') from dual));
commit;
select * from test_name

image.png

可以看出来,使用这种unicode转换的方式,只对nvchar2生效,varchar2还是显示乱码

关于varchar2和nvchar2

引用ASKTOM里的解答
NVARCHAR Vs. VARCHAR - Ask TOM (oracle.com)

Thanks for the question, Andrew.
Asked: September 04, 2015 - 3:00 pm UTC
Last updated: February 25, 2020 - 8:20 am UTC
Version: 12.0.2
Viewed 50K+ times! This question is 

img

You Asked
In a database with character sets defined as:
NLS_CHARACTERSET = AL32UTF8
NLS_NCHAR_CHARACTERSET = UTF8
Would there be any difference in the (language) character sets that could be stored by VARCHAR2 Vs. NVARCHAR2? As in
NAME VARCHAR2(60 CHAR)
Vs.
NAME NVARCHAR2(60 CHAR)
and Chris said…
NVARCHAR2 is a unicode-only data type. It’s useful if you want to have unicode for some columns (those that are NVARCHAR2) but have the rest of the database use a different characterset. In all other cases stick with using VARCHAR2.
In your case the only difference between UTF8 and AL32UTF8 is the AL version includes “supplementary characters”.
See also:
http://www.oracle.com/technetwork/database/database-technologies/globalization/twp-appdev-unicode-10gr2-129234.pdf
and
http://docs.oracle.com/database/121/NLSPG/ch6unicode.htm#NLSPG006

解决办法

根据以上测试的情况来看,有几个方案:
方案1、列由原来的varchar2改为nvarchar2,再插入unicode编码。
方案2、新建个utf8字符集的库,导出现有全库,再导入回去。
方案3、𧿹改写成别的可识别字符,如(足母)代替。
下面一个一个说一下几个方案:
方案1
需要停业务改表,结构,测试了一下,varchar2可以直接改成nvarchar2,但是nvarchar2改成varchar2要求必须没有数据。实际生产我也没测试过直接改列的字段类型,不知道会不会有问题。。
目前从网上收录2个操作方法
操作A
1、将表字段修改类型为:NVARCHAR2(),无论该字段是否存值都可以直接修改 alter table 表名 modify (字段名 nvarchar2(20));
注:如果想从NVARCHAR2()改回VARCHAR2,会报错:“ORA-01439:要更改数据类型,则要修改的列必须为空”,
解决方案为:①、将该字段A改名B;②、新建表字段,命名为A,将B值更新到A;③、删除B字段
2、使用该sql将生僻字插入到表中: update 表名 set 字段名 = N’生僻字’ where …
注意set字段名字前一定要有N,且在’'外。
操作B
也有人提供一个中转的解决办法:
修改字段类型,需要先将该字段清空,如果需要保存数据,可以先建一个临时的字段存储这些数据,然后删除要修改的列,再重新创建

--临时字段
alter table test_name add TEMP nvarchar2(200);
--赋转换后的值
update test_name set TEMP=cast(VARCHAR2_NAME as nvarchar2(200));
commit;
--删除字段
alter table test_name drop column VARCHAR2_NAME;
--重建
ALTER TABLE TEST_NAME ADD (VARCHAR2_NAME NVARCHAR2(200) );
--赋值
update test_name set VARCHAR2_NAME=TEMP;
--临时字段的使命完成了
alter table test_name drop column TEMP;
select * from test_name
insert into  test_name  values (2,(select utl_raw.cast_to_nvarchar2('d85fdff96307') from dual),(select utl_raw.cast_to_nvarchar2('d85fdff96307') from dual));

image.png


方法2:
基本不可行,一是停机时间太长,再就是改了字符集再重新导入的时候也可能会遇到字段长度不够的问题。
方法3:
就是真实案例,问了一下别家医院(几个不同厂家的HIS系统)是怎么解决这个问题的,结果。。。。就是写成(足母),别笑,真的好多家都这么搞的!!
 

image.png


另1家医院也是这样

image.png

总结后记

虽然这个能有办法解决。
但是还有一点我没想明白,人名生僻字他们咋解决的??难道人名的字段类型本来就是nvarchar2???
有知道的小伙伴可以告诉我一下,谢谢!

20240509

后来大佬们给的结果就是,在把varchar2改成nvarchar2,再重新录入。看来要整库都改生僻字是个大工程,1个1个改肯定是不好办。

image.png

 也欢迎关注我的公众号【徐sir的IT之路】,一起学习————————————————————————————
公众号:徐sir的IT之路
CSDN :https://blog.csdn.net/xxddxhyz?type=blog
墨天轮:https://www.modb.pro/u/3605
PGFANS:https://www.pgfans.cn/user/home?userId=5568————————————————————————————

这篇关于Oracle里令人头疼的生僻字处理案例的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/973381

相关文章

Golang操作DuckDB实战案例分享

《Golang操作DuckDB实战案例分享》DuckDB是一个嵌入式SQL数据库引擎,它与众所周知的SQLite非常相似,但它是为olap风格的工作负载设计的,DuckDB支持各种数据类型和SQL特性... 目录DuckDB的主要优点环境准备初始化表和数据查询单行或多行错误处理和事务完整代码最后总结Duck

Oracle数据库使用 listagg去重删除重复数据的方法汇总

《Oracle数据库使用listagg去重删除重复数据的方法汇总》文章介绍了在Oracle数据库中使用LISTAGG和XMLAGG函数进行字符串聚合并去重的方法,包括去重聚合、使用XML解析和CLO... 目录案例表第一种:使用wm_concat() + distinct去重聚合第二种:使用listagg,

Go语言使用Buffer实现高性能处理字节和字符

《Go语言使用Buffer实现高性能处理字节和字符》在Go中,bytes.Buffer是一个非常高效的类型,用于处理字节数据的读写操作,本文将详细介绍一下如何使用Buffer实现高性能处理字节和... 目录1. bytes.Buffer 的基本用法1.1. 创建和初始化 Buffer1.2. 使用 Writ

Python视频处理库VidGear使用小结

《Python视频处理库VidGear使用小结》VidGear是一个高性能的Python视频处理库,本文主要介绍了Python视频处理库VidGear使用小结,文中通过示例代码介绍的非常详细,对大家的... 目录一、VidGear的安装二、VidGear的主要功能三、VidGear的使用示例四、VidGea

Python结合requests和Cheerio处理网页内容的操作步骤

《Python结合requests和Cheerio处理网页内容的操作步骤》Python因其简洁明了的语法和强大的库支持,成为了编写爬虫程序的首选语言之一,requests库是Python中用于发送HT... 目录一、前言二、环境搭建三、requests库的基本使用四、Cheerio库的基本使用五、结合req

使用Python处理CSV和Excel文件的操作方法

《使用Python处理CSV和Excel文件的操作方法》在数据分析、自动化和日常开发中,CSV和Excel文件是非常常见的数据存储格式,ython提供了强大的工具来读取、编辑和保存这两种文件,满足从基... 目录1. CSV 文件概述和处理方法1.1 CSV 文件格式的基本介绍1.2 使用 python 内

MySQL不使用子查询的原因及优化案例

《MySQL不使用子查询的原因及优化案例》对于mysql,不推荐使用子查询,效率太差,执行子查询时,MYSQL需要创建临时表,查询完毕后再删除这些临时表,所以,子查询的速度会受到一定的影响,本文给大家... 目录不推荐使用子查询和JOIN的原因解决方案优化案例案例1:查询所有有库存的商品信息案例2:使用EX

oracle中exists和not exists用法举例详解

《oracle中exists和notexists用法举例详解》:本文主要介绍oracle中exists和notexists用法的相关资料,EXISTS用于检测子查询是否返回任何行,而NOTE... 目录基本概念:举例语法pub_name总结 exists (sql 返回结果集为真)not exists (s

Oracle的to_date()函数详解

《Oracle的to_date()函数详解》Oracle的to_date()函数用于日期格式转换,需要注意Oracle中不区分大小写的MM和mm格式代码,应使用mi代替分钟,此外,Oracle还支持毫... 目录oracle的to_date()函数一.在使用Oracle的to_date函数来做日期转换二.日

如何使用celery进行异步处理和定时任务(django)

《如何使用celery进行异步处理和定时任务(django)》文章介绍了Celery的基本概念、安装方法、如何使用Celery进行异步任务处理以及如何设置定时任务,通过Celery,可以在Web应用中... 目录一、celery的作用二、安装celery三、使用celery 异步执行任务四、使用celery