ITPub博客

首页 > 数据库 > Oracle > [20190930]oracle number类型存储转化脚本.txt

[20190930]oracle number类型存储转化脚本.txt

原创 Oracle 作者:lfree 时间:2019-10-04 20:13:20 0 删除 编辑

[20190930]oracle number类型存储转化脚本.txt

--//没事写了一个oracle number类型存储转化脚本。本来想用C来编写,感觉不好写。
--//还是采用自己擅长的bash编程。
--//关于oracle number如何编码可以看yangtingkun的blog,链接如下:
--//http://blog.itpub.net/4227/viewspace-68510/=>Oracle基本数据类型存储格式浅析(二)——数字类型

1.数据的输入问题:
--//可能输入的数据并不"归整",比如 0 ,可能输入 0.00,或者-0.可能输入有逗号空格等等。
--//另外就是输入的数字可能是2.1000000 或者 5.00000000之类的情况,必须先预处理。
--//另外说明一下:我脚本输入数据不支持科学记数法。比如1e4之类的写法。
--//通过简单的加0处理,另外如果字串太长,执行bc后会折行,必须删除"\n\\\r"字符(注:windows下bc的输出带\r字符。)
--//主要代码如下:
v_num=$(echo $v_num + 0 | bc -l | tr -d '\n\\\r' | sed -e "s/\.\([0-9]*[1-9]\)0\+$/.\1/" -e "s/\.0\+$//")

2.负数处理的问题:
--//负数结尾要补上0x66作为结束。实际上如果位数很多小数点后有40位,不需要加上0x66。
--//补上0x66实际上为了排序的需要,负数越大实际上越小。
--//我的处理先转化正数,设置v_sign=1表示负数。

3.如何获得幂指数。
--//oracle number采用百进制表示,我开始采用bc l函数(实际上ln函数)获得幂指数,感觉这个存在精度的问题,而且使用bc math库函数。
--//最终放弃这个方案。
--//后来仔细思考可以利用".",只要知道"."在数字串的位置就可以知道对于100的幂指数,具体看代码:
--//获得字串"."位置可以使用expr命令,例子如下:
v_pos=$(expr index $v_num ".")

4.剩余部分的编码(小数点部分):
--//我仅仅执行如下,特别定义scale=180,基本不会精度问题,删除尾部0(小数点之后),注意看sed部分,最后删除开头的小数点。
v_tmp=$(echo "scale=180 ; $v_num / 100^($v_exp) " | bc | tr -d '\n\\\r'| sed -e "s/\.\([0-9]*[1-9]\)0\+$/.\1/" -e "s/\.0\+$//" -e "s/^\.//")

--//因为oracle number采用百进制,要保证v_tmp的长度是偶数,如果不是在结尾不0。
--//剩下的就简单了。

5.测试:
$ cat test.txt
0
1
2
25
123
4100
-4100
41000000
-41000000
132004078
2.01
.3
.00000125
115.200003
-.00000125
-.3
-1
-5
-20032
-234.432
999999999999999999999999999999999999999900000000000000000000000000000000000000000000000000000000000000000000000000000000000000
-999999999999999999999999999999999999999900000000000000000000000000000000000000000000000000000000000000000000000000000000000000
.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001
-.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001
123456789012345678901234567890123456789012
-123456789012345678901234567890123456789012
0.123456789012345678901234567890123456789012
-0.123456789012345678901234567890123456789012

$ cat test.txt | xargs  -n 1 -I {}  bash -c "echo  {} ;./num2raw.sh {}" | paste - -
0       80
1       c1,02
2       c1,03
25      c1,1a
123     c2,02,18
4100    c2,2a
-4100   3d,3c,66
41000000        c4,2a
-41000000       3b,3c,66
132004078       c5,02,21,01,29,4f
2.01    c1,03,02
.3      c0,1f
.00000125       be,02,1a
115.200003      c2,02,10,15,01,04
-.00000125      41,64,4c,66
-.3     3f,47,66
-1      3e,64,66
-5      3e,60,66
-20032  3c,63,65,45,66
-234.432        3d,63,43,3a,51,66
999999999999999999999999999999999999999900000000000000000000000000000000000000000000000000000000000000000000000000000000000000  ff,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64
-999999999999999999999999999999999999999900000000000000000000000000000000000000000000000000000000000000000000000000000000000000 00,02,02,02,02,02,02,02,02,02,02,02,02,02,02,02,02,02,02,02,02
.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001     80,02
-.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001    7f,64,66
123456789012345678901234567890123456789012      d5,0d,23,39,4f,5b,0d,23,39,4f,5b,0d,23,39,4f,5b,0d,23,39,4f,5b
-123456789012345678901234567890123456789012     2a,59,43,2d,17,0b,59,43,2d,17,0b,59,43,2d,17,0b,59,43,2d,17,0b
0.123456789012345678901234567890123456789012    c0,0d,23,39,4f,5b,0d,23,39,4f,5b,0d,23,39,4f,5b,0d,23,39,4f,5b
-0.123456789012345678901234567890123456789012   3f,59,43,2d,17,0b,59,43,2d,17,0b,59,43,2d,17,0b,59,43,2d,17,0b

SCOTT@test01p> select a,dump(a,16) c80 from ty;
         A C80
---------- --------------------------------------------------------------------------------
         0 Typ=2 Len=1: 80
         1 Typ=2 Len=2: c1,2
         2 Typ=2 Len=2: c1,3
        25 Typ=2 Len=2: c1,1a
       123 Typ=2 Len=3: c2,2,18
      4100 Typ=2 Len=2: c2,2a
     -4100 Typ=2 Len=3: 3d,3c,66
  41000000 Typ=2 Len=2: c4,2a
 -41000000 Typ=2 Len=3: 3b,3c,66
 132004078 Typ=2 Len=6: c5,2,21,1,29,4f
      2.01 Typ=2 Len=3: c1,3,2
        .3 Typ=2 Len=2: c0,1f
 .00000125 Typ=2 Len=3: be,2,1a
115.200003 Typ=2 Len=6: c2,2,10,15,1,4
-.00000125 Typ=2 Len=4: 41,64,4c,66
       -.3 Typ=2 Len=3: 3f,47,66
        -1 Typ=2 Len=3: 3e,64,66
        -5 Typ=2 Len=3: 3e,60,66
    -20032 Typ=2 Len=5: 3c,63,65,45,66
  -234.432 Typ=2 Len=6: 3d,63,43,3a,51,66
         ~ Typ=2 Len=21: ff,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64
        -~ Typ=2 Len=21: 0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2
1.000E-130 Typ=2 Len=2: 80,2
-1.00E-130 Typ=2 Len=3: 7f,64,66
1.2346E+41 Typ=2 Len=21: d5,d,23,39,4f,5b,d,23,39,4f,5b,d,23,39,4f,5b,d,23,39,4f,5b
-1.235E+41 Typ=2 Len=21: 2a,59,43,2d,17,b,59,43,2d,17,b,59,43,2d,17,b,59,43,2d,17,b
.123456789 Typ=2 Len=21: c0,d,23,39,4f,5b,d,23,39,4f,5b,d,23,39,4f,5b,d,23,39,4f,5b
-.12345679 Typ=2 Len=21: 3f,59,43,2d,17,b,59,43,2d,17,b,59,43,2d,17,b,59,43,2d,17,b

28 rows selected.

--//我家里的电脑有点慢,大概每个需要2秒。

6.附上转化脚本如下:
$ cat num2raw.sh

#! /bin/bash
#! number convert oracle raw, input parameter do not like 1.1e3.

odebug=${ODEBUG:-0}

# process input parameter ,delete "," and all spaces. save to variable v_num. and length to variable v_len.
v_num="$*"
v_num=${v_num//[, ]/}

# strip trailing 0s in decimals or 0000.000 output 0
v_num=$(echo $v_num + 0 | bc | tr -d '\n\\\r' | sed -e "s/\.\([0-9]*[1-9]\)0\+$/.\1/" -e "s/\.0\+$//")

if [[ "$v_num" =~ ^-.*$ ]]; then
    v_sign=1
    v_num=${v_num:1:180}
else
    v_sign=0
fi

if [ $odebug -eq 1 ] ; then
    echo v_num="$v_num"
fi    

v_res=""
if [ "$v_num" == "0" ]; then
    v_res="80"
    echo "$v_res"
    exit 0
fi

# Guarantee . occur
# v_tmp1=$(echo "scale=180; $v_num/1" | bc |tr -d '\n\\\r' | sed -e "s/\.\([0-9]*[1-9]\)0\+$/.\1/")
# v_pos=$(expr index $v_tmp1 ".")

v_pos=$(expr index $v_num ".")

if [ $v_pos -gt 1 ]; then
    v_exp=$(( v_pos/2 ))
elif [ $v_pos -eq 0 ]; then
    v_exp=$(( (${#v_num}+1) /2 ))
elif [ $v_pos -eq 1 ]; then
    v_tmp1=${v_num:1:180}
    v_tmp2=$(echo $v_tmp1 | sed 's/^0\+//g')
    v_exp=$(( (${#v_tmp2} - ${#v_tmp1})/2 ))
else
    echo "number $v_num don't find dot!!"
    exit 1
fi

v_exp1=$(printf "%02x" $(( $v_exp+192 )))
if [ $v_sign -eq 1 ]; then
    v_exp1=$(printf "%02x" $(( 0xff - 0x${v_exp1} )))
fi

v_res=${v_exp1}${v_res}

v_tmp=$(echo "scale=180 ; $v_num / 100^($v_exp) " | bc | tr -d '\n\\\r'| sed -e "s/\.\([0-9]*[1-9]\)0\+$/.\1/" -e "s/\.0\+$//" -e "s/^\.//")

# oracle number type max length is 22 bytes (not 22 is 21 bytes??), 1 bytes exponent.
v_tmp=${v_tmp:0:40}
v_len=${#v_tmp}
v_tmp1=$(( $v_len % 2 ))

if [ $v_tmp1 -ne 0 ]; then
    v_tmp=${v_tmp}"0"
    v_len=$(( $v_len+1 ))
fi

if [ $odebug -eq 1 ] ; then
    echo v_num="$v_num" v_len="$v_len" v_exp="$v_exp" v_exp1="$v_exp1" v_tmp="$v_tmp"
fi    

if [ $v_sign -eq 0 ]; then
    for ((i=0;i<$v_len;i+=2))
    do
        v_tmp1=$(printf "%02x" $(( ${v_tmp:i:2} + 1 )))
        v_res=${v_res}","${v_tmp1}
    done
else
    for ((i=0;i<$v_len;i+=2))
    do
        v_tmp1=$(printf "%02x" $(( 101 - ${v_tmp:i:2} )))
        v_res=${v_res}","${v_tmp1}
    done
fi

# for ((i=0;i<$v_len;i+=2))
# do
#     if [ $v_sign -eq 0 ]; then
#         v_tmp1=$(printf "%02x" $(( ${v_tmp:i:2} + 1 )))
#     else        
#         v_tmp1=$(printf "%02x" $(( 101 - ${v_tmp:i:2} )))
#     fi
#     v_res=${v_res}","${v_tmp1}
# done

if [ $v_sign -eq 1 -a $v_len -lt 40 ]; then
    v_res=${v_res}",""66"
fi

echo "$v_res"

来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/267265/viewspace-2658887/ ,如需转载,请注明出处,否则将追究法律责任。

请登录后发表评论 登录
全部评论
熟悉oracle相关技术,擅长sql优化,rman备份与恢复,熟悉linux shell编程。

注册时间:2008-01-03

  • 博文量
    4006
  • 访问量
    7971604