在 Oracle PL/SQL 中, 如何實現 "N 進位" 與 "10 進位" 的互轉呢 ?
如: 16 進位與 10 進位互轉,
如: 36 進位與 10 進位互轉,
首先, 先建立一個轉換函數, 程式碼如下:
程式碼
create or replace function tomkuoConvertNumber( p_original_str varchar2 -- N 進位資料 (N 進位與十進位, 兩者資料擇一)
, p_original_num number -- 十進位資料 (N 進位與十進位, 兩者資料擇一)
, p_num_digital number := 16 -- 多少進位
, p_code_len number := 5 -- 資料長度 (資料不足時, 前面自動補 0)
, p_num_type number := 1 -- 1: N 進位轉 10 進位
-- 2: N 進位轉 N 進位
-- 3: 10 進位轉 N 進位
, p_add_value number := 0 -- 加多少值
) return varchar2
is
v_original_str varchar2(10) := p_original_str; -- N 進位資料
v_original_num number := p_original_num; -- 十進位資料
v_code_len number := p_code_len; -- 資料長度
v_num_digital number := p_num_digital; -- 多少進位
v_original_str_len number;
v_new_data_m number;
v_new_data_d number;
v_chr varchar2(1);
v_new_data varchar2(10) := '';
v_run boolean := true;
begin
-- "N 進位資料" 與 "十進位資料" 不能同時沒有
IF p_original_str is null AND p_original_num is null THEN
return 'Error: N 進位與十進位, 兩者資料擇一';
END IF;
-- "N 進位資料" 與 "十進位資料" 不能同時有
IF p_original_str is not null AND p_original_num is not null THEN
return 'Error: N 進位與十進位, 兩者資料擇一';
END IF;
-- "N 進位資料" 若要轉換, 則必須提供 "N 進位資料"
IF (p_num_type = 1 or p_num_type = 2) AND p_original_str is null THEN
return 'Error: 請提供 N 進位資料';
END IF;
-- "10 進位資料" 若要轉換, 則必須提供 "10 進位資料"
IF p_num_type = 3 AND p_original_num is null THEN
return 'Error: 請提供 10 進位資料';
END IF;
-- 將 N 進位轉換成 10 進位
IF p_num_type = 1 or p_num_type = 2 THEN
-- 原資料長度
v_original_str_len := lengthb(p_original_str);
-- 十進位值先歸零
v_original_num := 0;
-- 轉換
v_run := true;
for i in 1..v_original_str_len loop
v_chr := substr( v_original_str, i, 1 );
if ASCII(v_chr) > 55 then
v_original_num := v_original_num + (ASCII(v_chr) - 55) * power( v_num_digital, v_original_str_len - i);
else
v_original_num := v_original_num + to_number(v_chr) * power( v_num_digital, v_original_str_len - i);
end if;
end loop;
dbms_output.put_line( 'v_original_num 十進位 = ' || v_original_num );
END IF;
-- 加多少值
v_original_num := v_original_num + p_add_value;
-- 將 10 進位轉換成 N 進位
IF p_num_type = 2 or p_num_type = 3 THEN
v_run := true;
while v_run loop
-- 取得分母與分子
v_new_data_m := floor(v_original_num / v_num_digital);
v_new_data_d := mod( v_original_num, v_num_digital );
-- 若分子 >= 10, 則轉換成 A
-- 串接前面資料
if v_new_data_d < 10 then
v_new_data := v_new_data_d || v_new_data;
else
v_new_data := chr( v_new_data_d + 55 ) || v_new_data;
end if;
-- 若分母 = 0, 則表示轉換完成, 否則繼續轉換之
if v_new_data_m = 0 then
v_run := false;
else
v_original_num := v_new_data_m;
end if;
end loop;
-- 不足長度補零
v_new_data := lpad( v_new_data, v_code_len, '0' );
ELSE
v_new_data := v_original_num;
END IF;
-- 顯示結果
dbms_output.put_line( 'v_new_data = ' || v_new_data );
return v_new_data;
end;
然後, 參考下面的應用範例 :
範例程式碼
select tomkuoConvertNumber( '001F', null, 16, 4, 1, 0 ) from dual;
-- 001F 的 16 進位轉換成 10 進位
-- 結果: 31
select tomkuoConvertNumber( '001F', null, 16, 4, 2, 1 ) from dual;
-- 001F + 1 的 16 進位
-- 結果: 0020
select tomkuoConvertNumber( '001F', null, 36, 4, 1, 0 ) from dual;
-- 001F 的 36 進位轉換成 10 進位
-- 結果: 51
select tomkuoConvertNumber( '001F', null, 36, 4, 2, 1 ) from dual;
-- 001F + 1 的 36 進位
-- 結果: 001G
select tomkuoConvertNumber( '001Z', null, 36, 4, 1, 0 ) from dual;
-- 001Z 的 36 進位轉換成 10 進位
-- 結果: 71
select tomkuoConvertNumber( '001Z', null, 36, 4, 2, 1 ) from dual;
-- 001Z + 1 的 36 進位
-- 結果: 0020
select tomkuoConvertNumber( null, 12345, 16, 4, 3, 0 ) from dual;
-- 12345 的 10 進位轉換成 16 進位
-- 結果: 3039
select tomkuoConvertNumber( null, 12345, 16, 4, 3, 1 ) from dual;
-- 12345 + 1 的 10 進位轉換成 16 進位
-- 結果: 303A
select tomkuoConvertNumber( null, 12345, 36, 4, 3, 0 ) from dual;
-- 12345 的 10 進位轉換成 36 進位
-- 結果: 09IX
select tomkuoConvertNumber( null, 12345, 36, 4, 3, 1 ) from dual;
-- 12345 + 1 的 10 進位轉換成 36 進位
-- 結果: 09IY