【发布时间】:2010-06-21 15:41:50
【问题描述】:
在 Oracle 10g 中,有什么方法可以将十进制转换为二进制,或二进制转换为十进制,而无需先定义函数?我的数据库访问权限有限(仅限 SELECT),我在网上找到的所有解决方案似乎都涉及 CREATE FUNCTION,这对我不起作用。
【问题讨论】:
标签: oracle plsql binary base-conversion
在 Oracle 10g 中,有什么方法可以将十进制转换为二进制,或二进制转换为十进制,而无需先定义函数?我的数据库访问权限有限(仅限 SELECT),我在网上找到的所有解决方案似乎都涉及 CREATE FUNCTION,这对我不起作用。
【问题讨论】:
标签: oracle plsql binary base-conversion
如果十六进制足够好,那么 TO_CHAR 和 TO_NUMBER 可以工作:
SQL> select to_char(31, '0x') from dual;
TO_
---
1f
SQL> select to_number('1f', '0x') from dual;
TO_NUMBER('1F','0X')
--------------------
31
您也可以使用RAWTOHEX() 和HEXTORAW() 函数将十六进制转换为二进制。
【讨论】:
专门研究复杂的 SQL 谜题的 Frank Zhou 为这个问题设计了一个纯 SQL 解决方案。您可以在his OraQA site 上找到它。但请注意:它真的很粗糙。
更新
OraQA 的原始链接已损坏:The Wayback Machine has an archived version here。
【讨论】:
你能像这样在 SQLPlus 脚本中执行 PL/SQL:
declare
procedure bin_2_dec(/*some parameters here*/) is
begin
/*do computation and print result*/
end;
begin
bin_2_dec('11110000');
end;
/
我不确定,但我认为该函数不会在数据库中永久创建,我认为它只会在脚本执行期间暂时存在,所以这个 可能 工作。值得一试,对吧? ;)
或者,如果这不起作用,您可以 SELECT ... from dual 进行转换,尽管这可能会很尴尬并且只有在您知道位数的情况下才会起作用 - 也许(如果可以的话,我会尝试将它放在一起等几分钟,如果可能的话)。
【讨论】:
十进制到二进制的粗略但直接的解决方案:
SELECT REPLACE
(REPLACE
(REPLACE
(REPLACE
(REPLACE
(REPLACE
(REPLACE
(REPLACE
(REPLACE
(REPLACE
(REPLACE
(REPLACE
(REPLACE
(REPLACE
(REPLACE
(REPLACE
(TO_CHAR (100,'FMxxx'),
'0','0000'),
'1','0001'),
'2','0010'),
'3','0011'),
'4','0100'),
'5','0101'),
'6','0110'),
'7','0111'),
'8','1000'),
'9','1001'),
'A','1010'),
'B','1011'),
'C','1100'),
'D','1101'),
'E','1110'),
'F','1111')
FROM DUAL;
二进制转十进制会比较棘手。您也许可以使用connect by 将字符串拆分为 4 个字符的段,以类似的方式将它们转换,然后将它们连接在一起(第二个 connect by 使用 SYS_CONNECT_BY_PATH?),但这有点太乏味了让我今晚去锻炼。
再想一想,这是二进制到十进制的解决方案(我很喜欢 connect by 问题):
SELECT TO_NUMBER(
REPLACE (
SYS_CONNECT_BY_PATH (octet, '!'),
'!', ''),
'xxxxxx')
FROM (SELECT CASE SUBSTR
(LPAD (a,
CEIL (LENGTH(a)/4)*4, '0'),
(LEVEL-1)*4+1, 4)
WHEN '0000'
THEN '0'
WHEN '0001'
THEN '1'
WHEN '0010'
THEN '2'
WHEN '0011'
THEN '3'
WHEN '0100'
THEN '4'
WHEN '0101'
THEN '5'
WHEN '0110'
THEN '6'
WHEN '0111'
THEN '7'
WHEN '1000'
THEN '8'
WHEN '1001'
THEN '9'
WHEN '1010'
THEN 'A'
WHEN '1011'
THEN 'B'
WHEN '1100'
THEN 'C'
WHEN '1101'
THEN 'D'
WHEN '1110'
THEN 'E'
WHEN '1111'
THEN 'F'
END AS octet,
LEVEL AS seq,
CEIL (LENGTH(a)/4) AS max_level
FROM (SELECT '101010101010101010' AS a
FROM DUAL)
CONNECT BY LEVEL <= CEIL(LENGTH(a)/4))
WHERE LEVEL = max_level
CONNECT BY PRIOR seq = seq-1
此解决方案一次仅适用于当前编写的一行。要使其适用于多行,您需要向最外层的connect by 添加某种唯一标识符。
【讨论】:
我在 Oracle 中尝试使用 CONNECT BY 在简单的 SELECT 语句中将十进制转换为二进制。终于得到了想要的输出。你可以使用下面的,它工作正常。
WITH INPUT AS
(SELECT &N AS X FROM DUAL)
SELECT SUM(MOD(FLOOR(X*POWER(0.5,LEVEL-1)),2)*POWER(10,LEVEL-1)) AS
OUTPUT FROM INPUT CONNECT BY POWER(2,LEVEL-1)<=X;
【讨论】: