为什么我第一次调用 current_timestamp 产生的时间比第二次调用晚?

Why does my first call to current_timestamp produce a later time than the second call?

我正在尝试编写 PL/SQL 单元测试(使用 utPLSQL),以确保某个过程更新 table.[=13= 中的时间戳值]

测试结构有点像这样:

PROCEDURE my_fancy_test IS
    v_test_start_time TIMESTAMP;
    v_timestamp_in_table TIMESTAMP;
BEGIN
    v_test_start_time := CURRENT_TIMESTAMP;

    -- Make some assertions
    -- ...

    -- Call the procedure which - amongst other changes - sets a TIMESTAMP column to CURRENT_TIMESTAMP
    -- The procedure updates the time like so:
    UPDATE mytable SET lastchange = CURRENT_TIMESTAMP WHERE id = 42;

    -- Test if the date was set to a current timestamp
    SELECT lastchange INTO v_timestamp_in_table FROM mytable WHERE id = 42;
    ut.expect( v_timestamp_in_table ).to_be_greater_or_equal( v_test_start_time );

END;

令我惊讶的是,这个测试总是(或者可能只是经常)失败,因为存储在过程变量中的时间戳比在 UPDATE 语句中查询的时间戳晚几毫秒(更新)。

有人知道这是什么原因吗?执行 PL/SQL 程序和 SQL 查询

我当然可以添加一秒钟的“epsilon”之类的东西,但我想首先了解在编写这样的单元测试时是否需要记住其他类似的情况。

如果 table 声明的 TIMESTAMP 数据类型的精度低于 CURRENT_TIMESTAMP 创建的数据类型,则插入的值将四舍五入到适当的精度:

CREATE TABLE mytable (
  lastchange TIMESTAMP(0)
);
INSERT INTO mytable VALUES (NULL);

然后:

DECLARE
  v_test_start_time TIMESTAMP;
  v_timestamp_in_table TIMESTAMP;
BEGIN
  v_test_start_time := CURRENT_TIMESTAMP;

  UPDATE mytable
  SET   lastchange = v_test_start_time
  RETURNING lastchange INTO v_timestamp_in_table;

  DBMS_OUTPUT.PUT_LINE( 'Time:          ' || v_test_start_time);
  DBMS_OUTPUT.PUT_LINE( 'Time in table: ' || v_timestamp_in_table);
END;
/

输出:

Time:          2021-11-11 14:42:01.400733
Time in table: 2021-11-11 14:42:01.000000

那么table中的时间已经四舍五入了


您可以通过声明变量具有与 table:

相同的数据类型(和精度)来修复它
DECLARE
  v_test_start_time    mytable.lastchange%TYPE;
  v_timestamp_in_table mytable.lastchange%TYPE;
BEGIN
  v_test_start_time := CURRENT_TIMESTAMP;

  UPDATE mytable
  SET   lastchange = v_test_start_time
  RETURNING lastchange INTO v_timestamp_in_table;

  DBMS_OUTPUT.PUT_LINE( 'Time:          ' || v_test_start_time);
  DBMS_OUTPUT.PUT_LINE( 'Time in table: ' || v_timestamp_in_table);
END;
/

输出:

Time:          2021-11-11 14:42:01.
Time in table: 2021-11-11 14:42:01.

db<>fiddle here

一切都按预期工作 - 我只是测试了错误的时间戳列(有最后更改日期和最后传输日期,我不知道,因为我从员工那里“继承”了要测试的程序谁退出了)。

“最后更改”日期(在本例中)是测试插入测试数据的日期,该日期发生在测试之前调用的单独过程中。

因此,最后一次更改实际上应该是在测试用例开始前几毫秒。更改代码以使用“上次传输”日期修复此测试。