我要求将二进制数转换为十进制数。转换后的十进制范围不大于256.(二进制1亿)
它涉及一个iOS应用程序,在哪里阅读问题调查报告,动态选择四个二进制整数,并以此为基础。 (内部的一些UI内容为0和1)。
然后,我们将它们与''连接起来。 as delimiter。(类似于IP地址)
根据最终形成的序列,我们在将它们转换为小数后获取报告ID。
说,10.100.1.11
(输入)可能会成为2.4.1.3
(输出)
已经浏览了大量报告和Objective-C。字面上失去了理智。在iOS开发中,我无法编译PL / SQL。所以,我必须用SQL来完成。
修改
幸运的是,我能写出这样的东西。 (但一次只有一个数字:()SQL> var NUM number;
SQL> exec :NUM := 100000000;
PL/SQL procedure successfully completed.
SQL> SELECT SUM(value)
FROM
(SELECT POWER(2,LENGTH(TO_CHAR(:NUM))-level)*to_number(SUBSTR(TO_CHAR(:NUM),level,1),'FM9') AS value
FROM DUAL
CONNECT BY level <= LENGTH(TO_CHAR(:NUM))
); 2 3 4 5 6
SUM(VALUE)
----------
256
答案 0 :(得分:6)
有不同的方法可以解决这个问题。所以,我选择看起来像是一种相当神秘的方式。这样做的动机是to_number()
接受十六进制格式但不接受二进制格式。支持二进制和八进制以及十六进制会有什么困难?嗯,这不是我要问的问题。 Oracle没有。
但是,我们可以轻松地从二进制转换为十六进制。您只处理8个二进制数字,因此只有两个十六进制数字。这是代码:
with bin2hex as (
select '0000' as bin, '0' as hex from dual union all
select '0001' as bin, '1' as hex from dual union all
select '0010' as bin, '2' as hex from dual union all
select '0011' as bin, '3' as hex from dual union all
select '0100' as bin, '4' as hex from dual union all
select '0101' as bin, '5' as hex from dual union all
select '0110' as bin, '6' as hex from dual union all
select '0111' as bin, '7' as hex from dual union all
select '1000' as bin, '8' as hex from dual union all
select '1001' as bin, '9' as hex from dual union all
select '1010' as bin, 'A' as hex from dual union all
select '1011' as bin, 'B' as hex from dual union all
select '1100' as bin, 'C' as hex from dual union all
select '1101' as bin, 'D' as hex from dual union all
select '1110' as bin, 'E' as hex from dual union all
select '1111' as bin, 'F' as hex from dual
)
select t.*, c1.bin as bin1, c2.bin as bin2, c1.hex as hex1, c2.hex as hex2,
to_number(c2.hex||c1.hex, 'xx')
from (select '10010010' as num from dual union all
select '10010' from dual
) t left outer join
bin2hex c1
on substr('00000000'||t.num, -4) = c1.bin left outer join
bin2hex c2
on substr('00000000'||t.num, -8, 4) = c2.bin;
答案 1 :(得分:3)
只是为了好玩,一个使用递归CTE的版本(所以需要11gR2),因为显然我现在寻找任何借口来玩这些:
with data as (
select '10.100.1.11' as str from dual
),
t as (
select level as pos,
regexp_substr(str, '[^\.]+', 1, level) as val
from data
connect by level <= regexp_count(str, '[^\.]+')
),
r (pos, val, len, lvl, pos_val) as (
select pos, val, length(val), 0, 0
from t
union all
select pos, val, len, lvl + 1,
power(2, lvl) * substr(val, len - lvl, 1)
from r
where lvl < length(val)
)
select listagg(sum(pos_val), '.') within group (order by pos)
from r
group by pos;
2.4.1.3
虽然不像戈登那样神秘......
答案 2 :(得分:1)
with bin2hex as (
select '0000' as bin, '0' as hex from dual union all
select '0001' as bin, '1' as hex from dual union all
select '0010' as bin, '2' as hex from dual union all
select '0011' as bin, '3' as hex from dual union all
select '0100' as bin, '4' as hex from dual union all
select '0101' as bin, '5' as hex from dual union all
select '0110' as bin, '6' as hex from dual union all
select '0111' as bin, '7' as hex from dual union all
select '1000' as bin, '8' as hex from dual union all
select '1001' as bin, '9' as hex from dual union all
select '1010' as bin, 'A' as hex from dual union all
select '1011' as bin, 'B' as hex from dual union all
select '1100' as bin, 'C' as hex from dual union all
select '1101' as bin, 'D' as hex from dual union all
select '1110' as bin, 'E' as hex from dual union all
select '1111' as bin, 'F' as hex from dual
)
select LISTAGG(t.num,'.')WITHIN GROUP (order by row_label) as source,
LISTAGG(c1.bin,'.') WITHIN GROUP (order by row_label) as bin1,
LISTAGG(c2.bin,'.') WITHIN GROUP (order by row_label) as bin2,
LISTAGG(c1.hex,'.')WITHIN GROUP (order by row_label) as hex,
LISTAGG(to_number(c2.hex||c1.hex, 'xx') ,'.') WITHIN GROUP (order by row_label) as deci
-- c1.bin as bin1, c2.bin as bin2, c1.hex as hex1, c2.hex as hex2,
--to_number(c2.hex||c1.hex, 'xx')
from (SELECT level as row_label,REGEXP_SUBSTR('10.100.1.11','[^.]+',1,LEVEL) AS num
FROM dual
CONNECT BY REGEXP_SUBSTR('10.100.1.11','[^.]+',1,LEVEL) IS NOT NULL
) t left outer join
bin2hex c1
on substr('00000000'||t.num, -4) = c1.bin left outer join
bin2hex c2
on substr('00000000'||t.num, -8, 4) = c2.bin;
<强>结果:强>
SOURCE BIN1 BIN2 HEX DECI
10.100.1.11 0010.0100.0001.0011 0000.0000.0000.0000 2.4.1.3 2.4.1.3
演示:SQL Fiddle
答案 3 :(得分:1)
有点受到Gordon方法的启发,这是一个非递归版本:
with data as (
select '10.100.1.11' as str from dual
),
t as (
select level as pos,
lpad(regexp_substr(str, '[^\.]+', 1, level), 16, '0') as val
from data
connect by level <= regexp_count(str, '[^\.]+')
),
r as (
select power(2, level - 1) as digit_val,
lpad(power(10, level - 1), 16, '0') as raw_val,
lpad('0', 16, '0') as zero_val
from dual
connect by level <= 16
)
select listagg(sum(
case when utl_raw.bit_and(t.val, r.raw_val) = r.zero_val then 0 else 1 end
* r.digit_val), '.') within group (order by pos)
from t
cross join r
group by pos;
2.4.1.3
在这个版本中r
生成所有二进制值及其十进制等值,并且主查询将这些和原始的“八位字节”视为原始进行bit_and
操作来决定是否bit已设置,因此是否应将{十进制等效值包含在sum
。
这将处理最多16位的二进制值,这比这里需要的多;但是8还不够,9似乎错了......
答案 4 :(得分:1)
我还制作了一个基于Gordon Linoff解决方案的版本,它更通用(你可以轻松放入更大的数字)
with bin2hex as (
select '0000' as bin, '0' as hex from dual union all
select '0001' as bin, '1' as hex from dual union all
select '0010' as bin, '2' as hex from dual union all
select '0011' as bin, '3' as hex from dual union all
select '0100' as bin, '4' as hex from dual union all
select '0101' as bin, '5' as hex from dual union all
select '0110' as bin, '6' as hex from dual union all
select '0111' as bin, '7' as hex from dual union all
select '1000' as bin, '8' as hex from dual union all
select '1001' as bin, '9' as hex from dual union all
select '1010' as bin, 'A' as hex from dual union all
select '1011' as bin, 'B' as hex from dual union all
select '1100' as bin, 'C' as hex from dual union all
select '1101' as bin, 'D' as hex from dual union all
select '1110' as bin, 'E' as hex from dual union all
select '1111' as bin, 'F' as hex from dual
)
select listagg(hex) within group (order by lv desc),
to_number(listagg(hex) within group (order by lv desc), LPAD('x', max(lv), 'x'))
from(
select substr('0000'||num, -4*level, 4) bin, level lv
from (select '1001010100000010111110010000000' num --change value here
from dual
) a
connect by level<=ceil(length(a.num)/4)) a
join bin2hex b on b.bin=a.bin
答案 5 :(得分:1)
不是那么神秘的版本......
with bit as (
select '0' b from dual union all
select '1' from dual
),
bin2dec as (
select b7.b || b6.b || b5.b || b4.b || b3.b || b2.b || b1.b || b0.b bin,
b7.b*128+b6.b*64+b5.b*32+b4.b*16+b3.b*8+b2.b*4+b1.b*2+b0.b*1 dec
from bit b0
cross join bit b1
cross join bit b2
cross join bit b3
cross join bit b4
cross join bit b5
cross join bit b6
cross join bit b7
),
testdata as (
select '10010010' as num from dual union all
select '10010' from dual
)
select testdata.num, bin2dec.dec from testdata join bin2dec
on substr('00000000'||testdata.num,-8) = bin2dec.bin
......实际上是一个基于conversion from binary to decimal的非常基本的,正如我们在学校学到的那样。通过使用一些交叉连接,我构建了8位的所有组合,存储它们的二进制表示和它们的十进制值。之后,转换本身就是对该表的简单查找。
答案 6 :(得分:0)
我在Oracle
上尝试使用CONNECT BY
在简单的SELECT
语句中将二进制转换为十进制。最后使用下面的代码得到了所需的输出。
WITH INPUT AS
(SELECT REVERSE('&N') AS X FROM DUAL)
SELECT SUM(TO_NUMBER(SUBSTR(X,LEVEL,1)*POWER(2,LEVEL-1))) AS OUTPUT
FROM INPUT CONNECT BY LEVEL<=LENGTH(X);