在 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;
去
回滚;
是否可以使用 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;
去
回滚;