Oracle ORA_HASH 函数。结果会恒定吗?

问题描述 投票:0回答:2

我们需要为 ERP 系统中的多个表提供唯一的(每个表)数字 ID,因为第三方系统的接口需要它。这些 oracle 表中的键(包括 Objid)通常是 Varchar2。如果可以阻止的话,我不想在 20 多个表中创建新列,所以我想知道 ORA_HASH 是否可以解决问题。

我的问题是: 如果我跑步,例如

Select  ora_hash(order_no || release_no || line_no)  from purchase_order_line

随着表中数据的变化,对于某个 order_no || 我是否总是会得到相同的哈希值发布号 || line_no组合?或者,如果表中的整体数据发生变化,则该哈希值在不同时间会有所不同。如果哈希值保持不变,我可以将其限制为第 3 方系统所需的 bigint 的最大大小,并且对于特定组合始终获得相同的唯一值,对吧?我的思路有问题吗? 如果我们切换到新的数据库并迁移所有数据会发生什么。我强烈认为我们会在每个组合中获得不同的数据集,对吗?

表中的行数不会超过 BIGINT 的最大值。

我在从表中添加和删除数据时多次尝试查询,它总是返回相同的哈希值。

Select  ora_hash(order_no || release_no || line_no)  from purchase_order_line

我还快速检查了一些具有更多数据的表,我们似乎在主键上没有冲突。

sql oracle plsql hash
2个回答
0
投票

ora_hash 可能会导致一些冲突。更好的是使用standard_hash。返回原始数据,但发生冲突的可能性较小。而且,如果您对串联的列进行哈希处理,最好执行类似 standard_hash(order_no ||'|'||release_no ||'|'|| line_no, 'MD5') 的操作。使用 | 串联以避免混淆,例如 'ab'||'c' 给出与 'a'||'bc' 相同的结果。


0
投票

您需要向表中添加唯一的数字 ID,并且您希望避免这种情况,因为您的表已经具有唯一的 ID(尽管是字母数字)。您正在寻找一种获得确定性数字 ID 的方法。

根据这些 ID 中允许的不同字符数量以及这些 ID 的长度,以下 PL/SQL 函数可能足以从字母数字 ID 转换为数字 ID。 (允许的字符太多或字母数字 ID 太长会导致溢出异常。)

CREATE OR REPLACE FUNCTION get_unique_id(p_objid VARCHAR2) RETURN INTEGER DETERMINISTIC
IS
  PRAGMA UDF;
  v_allowed  VARCHAR2(4000) := 'ABCDEDGIJKLMNOPQRSTUVWXYZ1234567890';
  v_factor   INTEGER     := 1;
  v_result   INTEGER     := 0;
BEGIN
  FOR i IN 1 .. LENGTHC(p_objid) LOOP
    v_result := v_result + INSTRC(v_allowed, SUBSTRC(p_objid, i, 1)) * v_factor;
    v_factor := v_factor * (LENGTHC(v_allowed) + 1);
  END LOOP;
  RETURN v_result;
END get_unique_id;

毕竟很简单。您有一串允许的字符,可用于从 objid 字符获取数字。

假设允许使用 99 个字符。 objid 中的第一个字符将获得 1 到 99 之间的值,具体取决于其在允许的字符串中的位置。下一个字符将获得 1 到 99 乘以 100 之间的值。依此类推。所有这些值的总和就是生成的数字 ID。 (当然,如果您觉得这样更直观,您也可以从右到左遍历 objid 字符串。)

如何测试功能:

select get_unique_id('0000000000') from dual;

将“0000000000”更改为 objid 中允许的最大字符数和 v_allowed 中允许的最后一个字符的字符串。你得到结果或异常吗?结果数字是否太大或太小而无法满足要求?

© www.soinside.com 2019 - 2024. All rights reserved.