Cannot delete rows from a temporal history table

If you make the DELETE dynamic, your stored procedure will successfully ALTER the table, DELETE the records in question, and then ALTER it back.

CREATE PROCEDURE [dbo].[OrderHistoryDelete]
     (@Id UNIQUEIDENTIFIER)
AS
BEGIN
    DECLARE @sql VARCHAR(MAX)

    BEGIN TRANSACTION

        ALTER TABLE [dbo].[Order] SET ( SYSTEM_VERSIONING = OFF )

        SET @sql = 'DELETE FROM [dbo].[OrderHistory] WITH (TABLOCKX) 
        WHERE [Id] = ''' + CAST(@Id AS VARCHAR(40)) + ''''
        EXEC (@sql)

        ALTER TABLE [dbo].[Order] SET ( SYSTEM_VERSIONING = ON (HISTORY_TABLE = [dbo].[OrderHistory]))

    COMMIT TRANSACTION
END

I have never have issues like this, but my stored procedure is a little bit different - I am getting CSV of records to be deleted, then STRING_SPLIT them and materialized in a temporary table. Then, this table is joined to the target history table.

Here is full working example (only one input value). First create the table and add some sample data:

DROP TABLE IF EXISTS [dbo].[StackOverflow];
GO

CREATE TABLE [dbo].[StackOverflow]
(
    [Col1] INT PRIMARY KEY
   ,[Col2] VARCHAR(32)
   ,[SysStartTime] DATETIME2 GENERATED ALWAYS AS ROW START HIDDEN NOT NULL 
   ,[SysEndTime] DATETIME2 GENERATED ALWAYS AS ROW END HIDDEN NOT NULL 
   ,PERIOD FOR SYSTEM_TIME ([SysStartTime],[SysEndTime])
)
WITH (SYSTEM_VERSIONING = ON (HISTORY_TABLE = dbo.StackOverflowChanges));

GO

INSERT INTO [dbo].[StackOverflow] ([Col1], [Col2])
VALUES (1, 'value 1')
      ,(2, 'value 2')
      ,(3, 'value 3');

GO

UPDATE [dbo].[StackOverflow]
SET [Col2] = [Col2] + ' v2'

GO

SELECT *
FROM [dbo].[StackOverflow];

SELECT *
FROM [dbo].[StackOverflowChanges];

GO

enter image description here

Then, create the stored procedure:

SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO


CREATE OR ALTER PROCEDURE [dbo].[usp_StackOverflow_Delete]
(
    @Col1 INT
)
AS
BEGIN;

    SET NOCOUNT, XACT_ABORT ON;

        DROP TABLE IF EXISTS #RecordsTobeDeleted; 

        CREATE TABLE #RecordsTobeDeleted
        (
            [Col1] INT
        );

        INSERT INTO #RecordsTobeDeleted ([Col1])
        VALUES (@Col1);

        BEGIN TRY

            BEGIN TRANSACTION;

                ALTER TABLE [dbo].[StackOverflow] SET ( SYSTEM_VERSIONING = OFF )

                DELETE [dbo].[StackOverflowChanges]
                FROM [dbo].[StackOverflowChanges] SOC
                INNER JOIN #RecordsTobeDeleted R
                    ON SOC.[Col1] = R.[Col1];

                ALTER TABLE [dbo].[StackOverflow] SET ( SYSTEM_VERSIONING = ON (HISTORY_TABLE = [dbo].[StackOverflowChanges]))
            
            COMMIT TRANSACTION;

        END TRY

        BEGIN CATCH 
  
            IF @@TRANCOUNT > 0
            BEGIN;
                ROLLBACK TRANSACTION;
            END;

            THROW;
            
        END CATCH

    SET NOCOUNT, XACT_ABORT ON;

END;

GO

and now delete a record from the history table:

EXEC  [dbo].[usp_StackOverflow_Delete] @Col1 = 1;
 

SELECT *
FROM [dbo].[StackOverflow];

SELECT *
FROM [dbo].[StackOverflowChanges];

enter image description here

Clean up:

ALTER TABLE [dbo].[StackOverflow] SET ( SYSTEM_VERSIONING = OFF )
DROP TABLE IF EXISTS [dbo].[StackOverflow];
DROP TABLE IF EXISTS [dbo].[StackOverflowChanges];