将字母数字字符串转换为数字 - 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;
它工作得很好,但我刚刚发现有一些重复的字母数字字符串不同,例如
010000AA000001AA020019AA020047AA020138AA020139AA060018AA190016AA
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
我有这个字母数字字符串
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;
它工作得很好,但我刚刚发现有一些重复的字母数字字符串不同,例如
010000AA000001AA020019AA020047AA020138AA020139AA060018AA190016AA
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