Записать SysEndTime на временную таблицу SQL Server удалить - PullRequest
0 голосов
/ 06 февраля 2019

возможно ли захватить временную метку времени SysEndTime с ключевым словом OUTPUT?

Например:

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 exec'd.

Я прочитал, что SysEndTime установлен в конце транзакции, поэтому он не будет виден, пока все вызовы в этом заблокированном не завершены, но это будет означать, что япришлось бы выполнить вторичный запрос к таблице someTable, используя синтаксис «for system_time all» и извлекая столбец max (SysEndTime), чтобы зафиксировать самое последнее изменение, и при этом я не был бы уверен, что это удаление, что какUPDATE также устанавливает SysEndTime.

Ответы [ 2 ]

0 голосов
/ 07 февраля 2019

Нет, это невозможно через предложение OUTPUT, так как значение не существует в столбце в системной версионной таблице.

SQL Server использует транзакцию время начала , а не время окончания , поэтому логически это не должно быть по своей сути невозможным.План выполнения вызывает systrandatetime() в вычисляемом скаляре, чтобы получить значение, используемое при вставке в таблицу истории.

enter image description here

Это внутренняя функция, которая нам не предоставляется.Следующий запрос, выполняемый в той же транзакции , вероятно, должен вернуть что-то близкое, но это тип данных 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 завершается, вы можете (внутри той же транзакции) просто запросить таблицу истории, чтобы получить наибольшее значение sysendtime для первичного ключа одной из удаленных строк (PK).может быть захвачен с помощью OUTPUT при необходимости).

например Настройка

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 
0 голосов
/ 06 февраля 2019

Вы можете получить 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 |

* дБ <> скрипка здесь **

...