【问题标题】:PL/SQL base conversion without functions不带函数的 PL/SQL 基本转换
【发布时间】:2010-06-21 15:41:50
【问题描述】:

在 Oracle 10g 中,有什么方法可以将十进制转换为二进制,或二进制转换为十进制,而无需先定义函数?我的数据库访问权限有限(仅限 SELECT),我在网上找到的所有解决方案似乎都涉及 CREATE FUNCTION,这对我不起作用。

【问题讨论】:

    标签: oracle plsql binary base-conversion


    【解决方案1】:

    如果十六进制足够好,那么 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() 函数将十六进制转换为二进制。

    【讨论】:

      【解决方案2】:

      专门研究复杂的 SQL 谜题的 Frank Zhou 为这个问题设计了一个纯 SQL 解决方案。您可以在his OraQA site 上找到它。但请注意:它真的很粗糙。

      更新

      OraQA 的原始链接已损坏:The Wayback Machine has an archived version here

      【讨论】:

      • 这真是扭曲。我喜欢。 ;)
      • 链接已失效。解决方案可能与此相同 - asktom.oracle.com/pls/apex/…
      • @jva - 感谢您的提示。我添加了一个存档链接。 FZ 解决方案更复杂,因为他不只是做 16 进制。
      【解决方案3】:

      你能像这样在 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 进行转换,尽管这可能会很尴尬并且只有在您知道位数的情况下才会起作用 - 也许(如果可以的话,我会尝试将它放在一起等几分钟,如果可能的话)。

      【讨论】:

      • 要明确一点:我们不能在嵌入匿名块的 SQL 语句中使用这样声明的函数。这引发了 PLS-00231,因为我们只能在 SQL 语句中使用 SQL 声明的函数。
      • 不,我想这个函数不能从 SELET 语句中使用,但是函数/过程 可以从 SQLPlus 脚本中的 PL/SQL 中使用 。我不知道脚本中的 PL/SQL 是否可行。
      【解决方案4】:

      十进制到二进制的粗略但直接的解决方案:

      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 添加某种唯一标识符。

      【讨论】:

        【解决方案5】:

        我在 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;
        

        【讨论】:

          猜你喜欢
          • 2011-08-08
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2014-07-12
          • 1970-01-01
          • 2014-08-24
          • 1970-01-01
          相关资源
          最近更新 更多