使用ora_hash的行校验和为不同的用户提供不同的结果

时间:2018-10-26 13:32:08

标签: oracle ora-hash

尝试为Oracle表中的数据行生成唯一的校验和,以确保在检索它们并尝试同时更新它们的两个用户之间不更改该行。

 SELECT ora_hash( KY_REFUND_ID CD_STATUS || KY_CHECK_NUM || 
        COMMENT || CREATED_BY || TS_CREATED || TX_UPDATED_BY || TS_UPDATED) as checksum
 INTO p_checksum
 FROM REFUND_CHECKS r
 WHERE ROWID = p_rowid;

奇怪的是,如果通过sqldeveloper在调试中调用该过程,而不是通过网站调用该过程,则会得到不同的校验和。当内部再次计算校验和以与我的值进行比较时,这就变成了一个问题-我得到了12345,但是内部相同的数据却得出78904,因此系统说它们不匹配。

据我所知,两个不同的用户在查看相同的数据时获得不同校验和的唯一方法是……他们不在查看相同的数据。我怀疑这两个呼叫之间存在一些看不见的“东西”。我唯一能看到的就是所使用的帐户。

在sqldeveloper中,使用架构名称进行调用,但是网站以dotnet_user身份进行调用。

在确定校验和时,是否有可能在数学中将帐户名用作额外的值?如果不是这样,可能还会存在哪些其他看不见的差异,从而导致不同的结果,更重要的是,如何将它们标准化,以便双方获得相同的结果?

1 个答案:

答案 0 :(得分:2)

问题在于您依赖隐式转换。您是通过将多个值串联在一起来生成字符串的,这意味着使用会话的NLS设置将时间戳列(大概是名称中的列)隐式转换为字符串。而且您在SQL Developer中以及通过Web客户端具有不同的NLS设置。

作为一个简单的演示:

alter session set nls_timestamp_format = 'YYYY-MM-DD HH24:MI:SS';

select ora_hash(timestamp '2018-01-01 00:00:00') as ts_hash,
       'abc' || timestamp '2018-01-01 00:00:00' as str,
       ora_hash('abc' || timestamp '2018-01-01 00:00:00') as str_hash
from dual;

   TS_HASH STR                      STR_HASH
---------- ---------------------- ----------
1986439397 abc2018-01-01 00:00:00  588765268

alter session set nls_timestamp_format = 'DD-Mon-YYYY HH:MI:SS AM';

select ora_hash(timestamp '2018-01-01 00:00:00') as ts_hash,
       'abc' || timestamp '2018-01-01 00:00:00' as str,
       ora_hash('abc' || timestamp '2018-01-01 00:00:00') as str_hash
from dual;

   TS_HASH STR                          STR_HASH
---------- -------------------------- ----------
1986439397 abc01-Jan-2018 12:00:00 AM 2809284723

相同的时间戳记值,以及时间戳记本身在其本机数据类型中的相同散列;但是对字符串的不同的隐式转换,以及这些字符串的不同的哈希值。

更改代码以将时间戳显式转换为特定的固定格式,它将不再依赖NLS,因此将变得一致,例如

 SELECT ora_hash( KY_REFUND_ID CD_STATUS || KY_CHECK_NUM || 
          COMMENT || CREATED_BY ||
          to_char(TS_CREATED, 'SYYYYMMDDHH24MISSFF9') || TX_UPDATED_BY ||
          to_char(TS_UPDATED, 'SYYYYMMDDHH24MISSFF9')) as checksum
 INTO p_checksum
 FROM REFUND_CHECKS r
 WHERE ROWID = p_rowid;