процедура удаления системных версий временных таблиц - PullRequest
0 голосов
/ 04 апреля 2019

Я ищу процедуру для удаления системных версий временных таблиц, в идеале без использования динамического SQL.Я просмотрел документацию Microsoft и выяснил, как получить имя автоматически сгенерированной таблицы истории, но я знаю лишь немного о курсорах и еще меньше о динамическом SQL.

Вы не можете просто отброситьвременная таблица .Сначала необходимо отключить управление версиями, в результате чего таблица истории станет обычной таблицей.Затем вы можете удалить как временную таблицу, так и соответствующую ей таблицу истории.

ALTER TABLE [dbo].[TemporalTest] SET ( SYSTEM_VERSIONING = OFF )
GO
DROP TABLE [dbo].[TemporalTest]
GO
DROP TABLE [dbo].[TemporalTestHistory]
GO

Я использую временные таблицы с автоматически сгенерированными таблицами истории, поэтому я не знаю их имен.Однако документы Microsoft предоставляют информацию о том, как составить список таблиц истории, поэтому у меня есть способ получить эти имена.

select schema_name(t.schema_id) as temporal_table_schema,
     t.name as temporal_table_name,
    schema_name(h.schema_id) as history_table_schema,
     h.name as history_table_name,
    case when t.history_retention_period = -1 
        then 'INFINITE' 
        else cast(t.history_retention_period as varchar) + ' ' + 
            t.history_retention_period_unit_desc + 'S'
    end as retention_period
from sys.tables t
    left outer join sys.tables h
        on t.history_table_id = h.object_id
where t.temporal_type = 2
order by temporal_table_schema, temporal_table_name

Я надеялся, что смогу использовать подзапрос сОператор DROP, например, DROP TABLE (SELECT '#t').Это приводит к синтаксической ошибке.

Я ищу хранимую процедуру, которая принимает два параметра: имя удаляемой таблицы и должно ли произойти удаление, если в таблице есть какие-либо данные (например,должен ROWCOUNT = 0).Может кто-нибудь помочь, или порекомендовать курсоры над динамическим SQL, или порекомендовать другой метод?Спасибо!

Ответы [ 3 ]

1 голос
/ 04 апреля 2019

Нельзя выдавать DDL для данных (например, вывод подзапроса) или передавать имя объекта в качестве переменной в оператор;вам нужен динамический SQL.

CREATE PROCEDURE dbo.DropTemporalTable
  @schema sysname = N'dbo',
  @table  sysname
AS
BEGIN
  SET NOCOUNT ON;

  DECLARE @sql nvarchar(max) = N'';

  SELECT @sql += N'ALTER TABLE ' + src + N' SET (SYSTEM_VERSIONING = OFF);
    DROP TABLE ' + src  + N';
    DROP TABLE ' + hist + N';'
  FROM
  (
    SELECT src = QUOTENAME(SCHEMA_NAME(t.schema_id))
               + N'.' + QUOTENAME(t.name),
          hist = QUOTENAME(SCHEMA_NAME(h.schema_id))
               + N'.' + QUOTENAME(h.name)
    FROM sys.tables AS t
    INNER JOIN sys.tables AS h
    ON t.history_table_id = h.[object_id]
    WHERE t.temporal_type = 2
      AND t.[schema_id] = SCHEMA_ID(@schema)
      AND t.name = @table
  ) AS x;

  EXEC sys.sp_executesql @sql;
END
GO
0 голосов
/ 04 апреля 2019

Я адаптировал ответ Аарона. Вот окончательное решение:

CREATE OR ALTER PROCEDURE [dbo].[DropTemporalTable]
  @t as nvarchar(max),
  @s as nvarchar(max) = 'dbo'
-- See /9287510/protsedura-udaleniya-sistemnyh-versii-vremennyh-tablits
AS
BEGIN
-- TODO: check if src table is empty first
 DECLARE @sql nvarchar(max) = N'';

SELECT @sql += N'ALTER TABLE ' + src + N' SET (SYSTEM_VERSIONING = OFF);
DROP TABLE ' + src  + N';
DROP TABLE ' + hist + N';
'
FROM
(
  SELECT src = QUOTENAME(SCHEMA_NAME(t.schema_id))
             + N'.' + QUOTENAME(t.name),
        hist = QUOTENAME(SCHEMA_NAME(h.schema_id))
             + N'.' + QUOTENAME(h.name)
  FROM sys.tables AS t
  INNER JOIN sys.tables AS h
  ON t.history_table_id = h.[object_id]
  WHERE t.temporal_type = 2 AND t.name=@t AND t.schema_id=SCHEMA_ID(@s)
) AS x;

PRINT @sql;
--EXEC sys.sp_executesql @sql;
END
0 голосов
/ 04 апреля 2019

Я использую временные таблицы с автоматически сгенерированными таблицами истории, поэтому я не знаю их имен.Тем не менее, документы Microsoft предоставляют информацию о том, как составить список таблиц истории, поэтому у меня есть способ получить эти имена.

Я не знаю, знаете ли вы это, но вы можете указать имяТаблица истории несколькими способами.

Если вы создаете свою собственную таблицу истории:

ALTER TABLE [TemporalTable] SET (SYSTEM_VERSIONING = ON (HISTORY_TABLE = [dbo].[HistoryTable]))

Или, если вы хотите, чтобы ваша таблица истории была создана для вас:

CREATE TABLE [dbo].[TemporalTable](
    [Id] UNIQUEIDENTIFIER NOT NULL CONSTRAINT [DF_TemporalTable_Id] DEFAULT(NEWID()),
    [SysStartTime] DATETIME2(2) GENERATED ALWAYS AS ROW START NOT NULL CONSTRAINT [DF_TemporalTable_SysStartTime] DEFAULT(SYSUTCDATETIME()),
    [SysEndTime] DATETIME2(2) GENERATED ALWAYS AS ROW END NOT NULL CONSTRAINT [DF_TemporalTable_SysEndTime] DEFAULT(CONVERT(DATETIME2(2),'9999-12-31 23:59:59.99')),
 CONSTRAINT [PK_Product] PRIMARY KEY CLUSTERED 
(
    [Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 100) ON [PRIMARY],
    PERIOD FOR SYSTEM_TIME ([SysStartTime], [SysEndTime])
) ON [PRIMARY]
WITH
(
SYSTEM_VERSIONING = ON ( HISTORY_TABLE = [dbo].[HistoryTable] )
)

Кроме этого, я не знаю способа создания хранимой процедуры, которая принимает имя таблицы в качестве параметра и удаляет его без использования динамического SQL.Нечто подобное ниже будет необходимо.В зависимости от того, хотите ли вы, чтобы хранимая процедура искала имя таблицы истории, связанной с ней, вы можете добавить запрос, который вы упомянули в своем сообщении, вместо параметра.

CREATE PROCEDURE DeleteTemporalTable (@tableName NVARCHAR(MAX), @historyTableName) AS
BEGIN
    EXEC ('
    IF EXISTS (
        SELECT
            1
        FROM
            SYSOBJECTS
        WHERE
            id = OBJECT_ID(N''[dbo].[' + @tableName + ']'') AND
            OBJECTPROPERTY(id, N''IsTable'') = 1 AND
            OBJECTPROPERTY(id, N''TableTemporalType'') = 2
    )
    BEGIN
        ALTER TABLE [dbo].[' + @tableName + '] SET (SYSTEM_VERSIONING = OFF)
    END
    DROP TABLE IF EXISTS [dbo].[' + @tableName + ']
    DROP TABLE IF EXISTS [dbo].[' + @historyTableName + ']')
END

Если вы просто ищетедля способа удаления всех таблиц, и вы хотите что-то, что работает с временными таблицами, я использую скрипт:

DECLARE @temporalTableName varchar(max) = (SELECT TOP 1 [name] FROM sys.tables WHERE [temporal_type_desc] = 'SYSTEM_VERSIONED_TEMPORAL_TABLE')
WHILE @temporalTableName IS NOT NULL
BEGIN
    EXEC('ALTER TABLE [dbo].[' + @temporalTableName + '] SET (SYSTEM_VERSIONING = OFF)')
    SET @temporalTableName = (SELECT TOP 1 [name] FROM sys.tables WHERE [temporal_type_desc] = 'SYSTEM_VERSIONED_TEMPORAL_TABLE')
END
DECLARE @tableName varchar(max) = (SELECT TOP 1 [name] FROM sys.tables)
WHILE @tableName IS NOT NULL
BEGIN
    EXEC('DROP TABLE [dbo].[' + @tableName + ']')
    SET @tableName = (SELECT TOP 1 [name] FROM sys.tables)
END
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...