将字母数字字符串转换为数字 - Oracle

Convert alphanumeric string to numeric - Oracle

我有这个字母数字字符串

000193CA020008AA190038AA

我希望它是一个唯一的数字,例如

123456791011121314151617.

有没有办法在 PLSQL 上做到这一点? 并非所有字母数字的长度都相同,不只包含十六进制数字。

我试过了

create or replace FUNCTION FN_BOM_STEEL_CHAR_TO_NUMBER(
  value IN VARCHAR2
) RETURN NUMBER DETERMINISTIC
IS
  c        CHAR(1);
  up_value VARCHAR2(5000) := LTRIM(UPPER(value),'0');
  total    NUMBER  := 0;
  len      PLS_INTEGER    := COALESCE(LENGTH(up_value),0);
BEGIN
  FOR i IN 1 .. len LOOP
    c := SUBSTR(up_value,i,1);
    total := total * 36
                   + CASE
                     WHEN '0' <= c AND c <= '9'
                     THEN TO_NUMBER(c)
                     ELSE ASCII(c) - 55
                     END;
  END LOOP;
  RETURN total;
END FN_BOM_STEEL_CHAR_TO_NUMBER;

它工作得很好,但我刚刚发现有一些重复的字母数字字符串不同,例如

  1. 010000AA000001AA020019AA020047AA020138AA020139AA060018AA190016AA

  2. 010000AA000001AA020019AA020047AA020138AA020139AA060019AA190016AA

你可以看到有一个 18 和 19 使它们有所不同,但是当我 select 函数时,我得到了相同的 ID。还有很多这样的案例。

这是我正在尝试的 select 这些示例

SELECT FN_BOM_STEEL_CHAR_TO_NUMBER('010000AA000001AA020019AA020047AA020138AA020139AA060018AA190016AA
') AS ID
FROM   DUAL;

这是两者的 ID: 3095673299759705115226102843045930360610000000000000000000000000000000000000000000000000000000000

我需要它们与众不同。 提前致谢!

如果你只有字符 0123456789ABCDEF 那么你可以使用:

SELECT TO_NUMBER(
         '000193CA020008AA190038AA',
         'XXXXXXXXXXXXXXXXXXXXXXXX'
       ) AS from_hex_value
FROM   DUAL;

输出:

|            FROM_HEX_VALUE |
| ------------------------: |
| 1906840079024071083309226 |

如果您有字符 0-9A-Z 并想将其视为 base 36 字符串,那么您可以创建函数:

CREATE FUNCTION base36_to_number(
  value  IN VARCHAR2,
  -- The value to parse from base 36 to base 10.
  width  IN INT DEFAULT 0,
  -- The width of the substring to consider; 0 is the entire string.
  offset IN INT DEFAULT 0
  -- The number of widths to offset from the least-significant digit.
) RETURN NUMBER DETERMINISTIC
IS
  c         CHAR(1);
  total     NUMBER := 0;
  len       PLS_INTEGER    := COALESCE(LENGTH(value),0);
  start_pos PLS_INTEGER;
  end_pos   PLS_INTEGER;
BEGIN
  IF width < 0 THEN
    RAISE_APPLICATION_ERROR( -20000, 'Invalid width.' );
  ELSIF offset < 0 THEN
    RAISE_APPLICATION_ERROR( -20000, 'Invalid offset.' );
  ELSIF width = 0 THEN
    start_pos := 1;
    end_pos   := len;
  ELSIF width * offset > len THEN
    RETURN 0;
  ELSIF width * (offset + 1) > len THEN
    start_pos := 1;
    end_pos   := len - width  * offset;
  ELSE
    start_pos := len - width * ( offset + 1 ) + 1;
    end_pos   := start_pos + width - 1;
  END IF;

  FOR i IN start_pos .. end_pos LOOP
    c := SUBSTR(value,i,1);
    total := total * 36
                   + CASE
                     WHEN '0' <= c AND c <= '9'
                     THEN TO_NUMBER(c)
                     WHEN 'A' <= c AND c <= 'Z'
                     THEN ASCII(c) - 55
                     WHEN 'a' <= c AND c <= 'z'
                     THEN ASCII(c) - 87
                     ELSE NULL
                     END;
  END LOOP;
  
  total := total * POWER( 36, width * offset );
  RETURN total;
END;
/

然后:

SELECT BASE36_TO_NUMBER('000193CA020008AA190038AA') AS from_base36_value
FROM   DUAL;

输出:

|                FROM_BASE36_VALUE |
| -------------------------------: |
| 16743829188442650222733747166386 |

NUMBER 的最大长度为 38 位十进制数字,您不能将超过 24 个字符的 base-36 数字放入其中。如果您有更大的值,那么您需要将其转换为多个数字:

即:

CREATE TABLE table_name ( value ) AS
SELECT '010000AA000001AA020019AA020047AA020138AA020139AA060018AA190016AA' FROM DUAL UNION ALL
SELECT '010000AA000001AA020019AA020047AA020138AA020139AA060019AA190016AA' FROM DUAL UNION ALL
SELECT 'ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZzzzzzzzzzzzzzzzzzzzzzzzz' FROM DUAL;

然后:

SELECT BASE36_TO_NUMBER( value, 24, 0 ) AS low_value,
       BASE36_TO_NUMBER( value, 24, 1 ) AS mid_value,
       BASE36_TO_NUMBER( value, 24, 2 ) AS high_value
FROM   table_name;

输出:

                             LOW_VALUE |                                                                   MID_VALUE |                                                                                           HIGH_VALUE
-------------------------------------: | --------------------------------------------------------------------------: | ---------------------------------------------------------------------------------------------------:
   34663123071664682325935025837090322 |    777948567801018784511679412336101916888000000000000000000000000000000000 |    3095673299759705115226102065097362559570000000000000000000000000000000000000000000000000000000000
   34663123071664682329591184277153298 |    777948567801018784511679412336101916888000000000000000000000000000000000 |    3095673299759705115226102065097362559570000000000000000000000000000000000000000000000000000000000
22452257707354557240087211123792674815 | 504103876157462118901767181449118688664000000000000000000000000000000000000 | 4011991914547630480065052883598567655228000000000000000000000000000000000000000000000000000000000000

db<>fiddle here