我有一个数据库,目前仅以英文存储用户名。
我想合并 BASE64
& UTF-8
以便存储其他语言;我想将其存储在NVARCHAR2
类型的列中。
数据库程序在BASE64
中收到名称,我正在通过UTL_ENCODE.BASE64_DECODE
&使用VARCHAR2
将字符串转换为UTL_RAW.CAST_TO_VARCHAR2
。但是我得到了胡言乱语而不是实际的话。
例如,我将'алекс'作为BASE64
中的名称。我能够解码它,但是VARCHAR2/NVARCHAR2
的强制转换不会返回值:我只是乱码。
我使用 Oracle 12c
NLS_CHARACTERSET WE8ISO8859P1
以下是我用来解码的代码:
DECLARE
lv_OrgUserName VARCHAR2(2000);
lv_encodedUserName VARCHAR2(2000);
lv_UserName VARCHAR2(2000);
BEGIN
lv_OrgUserName := 'алекс';
lv_encodedUserName := UTL_RAW.CAST_TO_VARCHAR2(UTL_ENCODE.BASE64_ENCODE(UTL_RAW.CAST_TO_RAW(lv_OrgUserName)));
DBMS_OUTPUT.PUT_LINE (lv_encodedUserName);
lv_UserName := UTL_RAW.CAST_TO_VARCHAR2(UTL_ENCODE.BASE64_DECODE(UTL_RAW.CAST_TO_RAW (lv_encodedUserName)));
DBMS_OUTPUT.PUT_LINE (lv_UserName);
END;
我怎样才能克服这个?
答案 0 :(得分:2)
首先,WE8ISO8859P1(西欧8位ISO 8859第1部分,或 - ISO8859第1部分)不支持cyryllic字符:
请看这个链接:https://en.wikipedia.org/wiki/ISO/IEC_8859-1
因此,如果您尝试将алекс
这样的字符串存储到 VARCHAR2 变量/列中,您将始终获得a????
作为结果。
可能在数据库安装过程中,有人没有考虑过cyryllic字符并且选择了错误的代码页
更好的选择是ISO / IEC 8859-5(第5部分),请看这个链接:https://en.wikipedia.org/wiki/ISO/IEC_8859-5
一种选择是改变这种编码 - 但这并不容易,而且这是这个问题的重点。
您可以做的是在应用程序的所有必须支持西里尔字符的地方严格使用 NVARCHAR2 数据类型而不是 VARCHAR2 数据类型。
你需要注意的是,仍有一些陷阱:
DBMS_OUTPUT
包来调试您的代码,因为此包仅支持VARCHAR2数据类型,它不支持NVARCHAR N'some string'
文字(带有N前缀) - > 'алекс'
是VARCHAR2数据类型,并且在编码中始终自动转换为'a????'
,而n'алекс'
是NVARCHAR2数据类型,并且不会发生此类转换。以下代码在版本12c上进行了测试,我正在使用EE8MSWIN1250
代码页(它也不支持西里尔字符):
select * from nls_database_parameters
where parameter like '%CHARACTERSET%';
PARAMETER VALUE
----------------------- ------------
NLS_NCHAR_CHARACTERSET AL16UTF16
NLS_CHARACTERSET EE8MSWIN1250
请试一试:
CREATE OR REPLACE PACKAGE my_base64 AS
FUNCTION BASE64_ENCODE( str nvarchar2 ) RETURN varchar2;
FUNCTION BASE64_DECODE( str varchar2 ) RETURN nvarchar2;
END;
/
CREATE OR REPLACE PACKAGE BODY my_base64 AS
FUNCTION BASE64_ENCODE( str nvarchar2 ) RETURN varchar2
IS
lv_encodedUserName VARCHAR2(2000);
BEGIN
lv_encodedUserName := UTL_RAW.CAST_TO_VARCHAR2(UTL_ENCODE.BASE64_ENCODE(UTL_RAW.CAST_TO_RAW(str)));
RETURN lv_encodedUserName;
END;
FUNCTION BASE64_DECODE( str varchar2 ) RETURN nvarchar2
IS
lv_UserName nVARCHAR2(2000);
BEGIN
lv_UserName := UTL_RAW.CAST_TO_nVARCHAR2(UTL_ENCODE.BASE64_DECODE(UTL_RAW.CAST_TO_RAW (str)));
RETURN lv_UserName;
END;
END;
/
一些例子:
select 'aлекс' As A, n'aлекс' As B from dual;
A B
----- -----
a???? aлекс
select my_base64.BASE64_ENCODE( n'аaaлекс' ) As aleks from dual;
ALEKS
--------------------------------------------------------------------------------
BDAAYQBhBDsENQQ6BEE=
select my_base64.BASE64_DECODE( 'BDAAYQBhBDsENQQ6BEE=' ) as aleks from dual;
ALEKS
--------------------------------------------------------------------------------
аaaлекс
select my_base64.BASE64_DECODE( my_base64.BASE64_ENCODE( n'аaaлекс' ) ) as Aleks from dual;
ALEKS
--------------------------------------------------------------------------------
аaaлекс