PLSQL将NVARCHAR2从BASE64解码为UTF-8

PLSQL将NVARCHAR2从BASE64解码为UTF-8,utf-8,plsql,oracle12c,Utf 8,Plsql,Oracle12c,我有一个数据库,目前只存储英文用户名 我想合并BASE64和UTF-8,以便以其他语言存储;我想将其存储在nvarhar2类型的列中 数据库过程在BASE64中接收名称,我通过UTL\u ENCODE.BASE64\u DECODE对其进行解码&使用UTL\u RAW.CAST\u to\u VARCHAR2将字符串转换为VARCHAR2。但我听到的是胡言乱语,而不是真正的单词 例如,我在BASE64中获得了'аааС'作为名称。我能够解码它,但是对VARCHAR2/NVARCHAR2的转换没有

我有一个数据库,目前只存储英文用户名

我想合并
BASE64
UTF-8
,以便以其他语言存储;我想将其存储在
nvarhar2
类型的列中

数据库过程在
BASE64
中接收名称,我通过
UTL\u ENCODE.BASE64\u DECODE
对其进行解码&使用
UTL\u RAW.CAST\u to\u VARCHAR2
将字符串转换为
VARCHAR2
。但我听到的是胡言乱语,而不是真正的单词

例如,我在
BASE64
中获得了'аааС'作为名称。我能够解码它,但是对
VARCHAR2/NVARCHAR2
的转换没有返回值:我只得到了胡言乱语

我正在使用
NLS\u字符集WE8ISO8859P1运行
Oracle12c

以下是我用来解码的代码:

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;

如何克服此问题?

首先,WE8ISO8859P1(西欧8位ISO 8859第1部分或-ISO8859第1部分)不支持cyryllic字符:
请参阅此链接:

因此,如果您尝试将一个字符串(如
ааС
存储到VARCHAR2变量/列中,您将始终得到
a???


可能在数据库安装过程中,有人没有考虑cyryllic字符,选择了错误的代码页。
更好的选择是ISO/IEC 8859-5(第5部分),请参见以下链接:

一种选择是改变这种编码方式——但这并不容易,而且根本不存在这个问题


您可以做的是在必须支持西里尔字符的应用程序的所有位置严格使用NVARCHAR2数据类型,而不是VARCHAR2数据类型。

尽管您需要注意,但仍存在一些陷阱:

  • 您不能使用
    DBMS\u OUTPUT
    包调试代码,因为此包只支持VARCHAR2数据类型,不支持NVARCHAR
  • 您必须在所有文本中使用
    N'some string'
    文本(带N前缀)-->“ааааааааааааааааааааааааа1072

下面的代码在版本12c上测试,我使用的是
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лекс




我确认您的代码:它适用于“普通字符”,如
abc
,但不适用于您示例中的外来字符。@J.Chomel,好吧,我如何才能让它适用于外来字符?我今天做了大量研究,但我无法克服它。我在某个地方读到,这可能来自您的客户,该客户没有正确设置以处理希腊字符。因此,DBMS_输出永远无法输出希腊字符,无论您如何努力。但这不是最后的决定,因为我不太明白!明亮的在Oracle11g上也是如此。
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лекс