Oracle PL/SQL "N 進位" 與 "十進位" 的互轉 (如: 36 進位的 000Z 下一個數值為 0010)


在 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


Related Posts Plugin for WordPress, Blogger...