尝试为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身份进行调用。
在确定校验和时,是否有可能在数学中将帐户名用作额外的值?如果不是这样,可能还会存在哪些其他看不见的差异,从而导致不同的结果,更重要的是,如何将它们标准化,以便双方获得相同的结果?
答案 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;