【问题标题】:Checksum of row using ora_hash giving different results for different users使用 ora_hash 为不同用户提供不同结果的行校验和
【发布时间】:2018-10-26 13:32:08
【问题描述】:

尝试为 am 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。

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

【问题讨论】:

    标签: oracle ora-hash


    【解决方案1】:

    问题在于您依赖于隐式转换。您通过将多个值连接在一起来生成一个字符串,这意味着时间戳(可能来自名称)列正在使用会话的 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;
    

    【讨论】:

    • 我们有一个赢家。我们决定我们甚至不需要日期来获得有效的校验和,所以我们只是删除了它们。所有季度的结果都相同。
    猜你喜欢
    • 2021-05-31
    • 2020-05-29
    • 2020-10-01
    • 2020-08-20
    • 2017-06-12
    • 1970-01-01
    • 1970-01-01
    • 2018-11-07
    • 1970-01-01
    相关资源
    最近更新 更多