在 SQL 服务器临时 table 上捕获 SysEndTime 删除

Capture SysEndTime on SQL Server temporal table delete

是否可以使用 OUTPUT 关键字捕获 SysEndTime 时间戳?

例如:

DECLARE @MyTableVar TABLE (sysendtime datetime2);
DELETE
FROM dbo.someTable
OUTPUT DELETED.sysendtime INTO @MyTableVar 
WHERE
    colA = 'something';
SELECT sysendtime FROM @MyTableVar;

最后一个 SELECT 返回 9999-12-31 23:59:59.000,这是 DELETE 执行之前的值。

我读到 SysEndTime 是在事务结束时设置的,因此在被阻止的所有调用完成之前它是不可见的,但这意味着我必须对 someTable table 使用 "for system_time all" 语法并检索 max(SysEndTime) 列以捕获最新的更改,因此我不能保证它是删除,因为 UPDATE 也会设置 SysEndTime。

你可以得到 ROW START 但是你说的不行 ROW END

create table dbo.someTable 
(
   --sysendtime datetime2 ,
   ColA varchar(15),
  [ValidFrom] datetime2 (2) GENERATED ALWAYS AS ROW START  
  , [ValidTo] datetime2 (2) GENERATED ALWAYS AS ROW END  
  , PERIOD FOR SYSTEM_TIME (ValidFrom, ValidTo)  
)
GO

✓

insert into  someTable (ColA) values ( 'something')
GO

1 rows affected

DECLARE @MyTableVar TABLE (sysendtime datetime2);

DELETE FROM dbo.someTable
OUTPUT DELETED.ValidFrom INTO @MyTableVar 
WHERE colA = 'something';

SELECT sysendtime FROM @MyTableVar;
GO

| sysendtime          |
| :------------------ |
| 06/02/2019 20:52:54 |
DECLARE @MyTableVar TABLE (sysendtime datetime2);

DELETE FROM dbo.someTable
OUTPUT DELETED.ValidTo INTO @MyTableVar 
WHERE colA = 'something';

SELECT sysendtime FROM @MyTableVar;
GO

| sysendtime          |
| :------------------ |
| 31/12/9999 23:59:59 |

*db<>fiddle here**

不,这不可能通过 OUTPUT 子句实现,因为该值不存在于系统版本 table 的列中。

SQL 服务器使用事务 start 时间 - 而不是 end 时间,因此从逻辑上讲,它本来就不是不可能的。执行计划在计算标量中调用 systrandatetime() 以获取插入到历史记录时要使用的值 table。

不过这是一个内部函数,没有向我们公开。以下查询 运行 在同一事务中 可能 return 接近,但这是 datetime 数据类型,因此将遗留舍入行为 1/300 秒。我怀疑你会发现任何保证这甚至使用完全相同的底层数据源。

SELECT transaction_begin_time
FROM   sys.dm_tran_active_transactions
WHERE  transaction_id = (SELECT transaction_id
                         FROM   sys.dm_tran_current_transaction);

我不建议直接使用交易 DMV。但是,由于当 DELETE 语句完成时,该行已经存在于历史记录 table 中,您可以(在同一事务中)查询历史记录 table 以获得最高的 sysendtime已删除行之一的主键(如果需要,可以使用 OUTPUT 捕获 PK)。

例如设置

CREATE TABLE dbo.someTable
(
PK   INT PRIMARY KEY,
ColA VARCHAR(15),
[ValidFrom] datetime2 (2) GENERATED ALWAYS AS ROW START ,
[ValidTo] datetime2 (2) GENERATED ALWAYS   AS ROW END ,
PERIOD FOR SYSTEM_TIME (ValidFrom, ValidTo)
)
WITH (SYSTEM_VERSIONING = ON (HISTORY_TABLE = dbo.someTableHistory))


INSERT INTO dbo.someTable
            (PK,
             ColA)
VALUES      (1,'something'),
            (2,'something');

那么你可以如下实现

DECLARE @DeletedPks TABLE
(
   PK INT 
)

BEGIN TRAN

DELETE FROM dbo.someTable
OUTPUT DELETED.PK
INTO @DeletedPks
WHERE  colA = 'something';

SELECT MAX(ValidTo)
FROM   dbo.someTableHistory
WHERE  PK = (SELECT TOP 1 PK /*Doesn't matter which PK we choose*/
             FROM   @DeletedPks)

COMMIT 

设置事务隔离级别可序列化;开始交易;

CREATE TABLE #SYSUTCTRANSBEGINTIME(PK int,ValidFrom datetime2(7)生成始终作为行开始,ValidTo datetime2(7)生成始终作为行结束,期间 SYSTEM_TIME(ValidFrom,ValidTo ));

等待延迟“00:00:00.100”;

SELECT SYSUTCDATETIME() AS SYSUTCDATETIME;

插入#SYSUTCTRANSBEGINTIME (PK) 值 (0);

select ValidFrom as SYSUTCTRANSBEGINTIME from #SYSUTCTRANSBEGINTIME;

回滚;