PLSQL 将 NVARCHAR2 从 BASE64 解码为 UTF-8
Posted
技术标签:
【中文标题】PLSQL 将 NVARCHAR2 从 BASE64 解码为 UTF-8【英文标题】:PLSQL decode NVARCHAR2 from BASE64 to UTF-8 【发布时间】:2016-06-19 12:48:13 【问题描述】:我有一个数据库,目前只存储英文用户名。
我想合并 BASE64
和 UTF-8
以便以其他语言存储以及;我想将它存储在NVARCHAR2
类型的列中。
数据库过程接收BASE64
中的名称,我通过UTL_ENCODE.BASE64_DECODE
对其进行解码并使用UTL_RAW.CAST_TO_VARCHAR2
将字符串转换为VARCHAR2
。但我得到的是胡言乱语,而不是真正的词。
例如,我将 'алекс' 作为BASE64
中的名称。我能够对其进行解码,但对VARCHAR2/NVARCHAR2
的强制转换没有返回值:我得到的只是胡言乱语。
我正在使用 NLS_CHARACTERSET WE8ISO8859P1
Oracle 12c
上运行
这是我用来解码的代码:
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;
我该如何克服这个问题?
【问题讨论】:
我确认您的代码:它适用于“普通字符”,例如abc
,但不适用于您示例中的外来字符。
@J.Chomel,好的,我怎样才能让它为异国情调的人工作?
我今天做了很多研究,但我无法克服它。我在某处读到这可能来自您的客户端,该客户端未正确设置以处理希腊字符。因此,无论您多么努力,DBMS_OUTPUT 都永远无法输出希腊字符。但这不是最终的,因为我不太了解它!
【参考方案1】:
首先,WE8ISO8859P1(西欧 8 位 ISO 8859 第 1 部分,或 - ISO8859 第 1 部分)不支持西里尔字符:
看到这个链接:https://en.wikipedia.org/wiki/ISO/IEC_8859-1
因此,如果您尝试将алекс
之类的字符串存储到VARCHAR2 变量/列中,您将始终得到a????
作为结果。
可能在数据库安装过程中,有人没有考虑西里尔字符并选择了错误的代码页。
更好的选择是 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лекс
【讨论】:
太棒了。在 Oracle11g 上也一样。以上是关于PLSQL 将 NVARCHAR2 从 BASE64 解码为 UTF-8的主要内容,如果未能解决你的问题,请参考以下文章
如何将瑞典语字符插入 NVARCHAR2 Oracle 表列类型?
PLSQL PHP:如何将大型 xml 数据从 PLSQL 函数获取到 PHP