我正在寻找删除系统版本的时态表的过程,理想情况下不使用动态SQL。我仔细阅读了Microsoft文档,并弄清楚了如何获取自动生成的历史记录表名称,但是我对游标知之甚少,而对动态SQL知之甚少。
You can't just drop a temporal table。您必须首先禁用版本控制,这会使历史记录表成为普通表。然后,您可以删除时态表及其对应的历史记录表。
ALTER TABLE [dbo].[TemporalTest] SET ( SYSTEM_VERSIONING = OFF )
GO
DROP TABLE [dbo].[TemporalTest]
GO
DROP TABLE [dbo].[TemporalTestHistory]
GO
我将临时表与自动生成的历史表一起使用,因此我不知道它们的名称。但是,Microsoft docs提供了有关如何列出历史记录表的信息,因此我有一种获取这些名称的方法。
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)。任何人都可以在Dynamic SQL上提供帮助或推荐游标,或者推荐其他技术吗?谢谢!
答案 0 :(得分:1)
您不能针对数据发出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
答案 1 :(得分:0)
我将临时表与自动生成的历史表一起使用,所以我 不知道他们的名字。但是,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
答案 2 :(得分:0)
我已经适应了亚伦的答案。这是最终的解决方案:
CREATE OR ALTER PROCEDURE [dbo].[DropTemporalTable]
@t as nvarchar(max),
@s as nvarchar(max) = 'dbo'
-- See https://stackoverflow.com/questions/55522278/procedure-to-drop-system-versioned-temporal-tables/55524067#55524067
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
答案 3 :(得分:0)
/****** 对象:表 [Intake].[MER_SF_Asset_Temporal] 脚本日期:04/05/2021 12:33:57 PM ******/
ALTER TABLE [Intake].[MER_SF_Asset_Temporal] SET ( SYSTEM_VERSIONING = OFF )
GO
/****** 对象:表 [Intake].[MER_SF_Asset_Temporal] 脚本日期:04/05/2021 12:33:57 PM ******/
IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[Intake].[MER_SF_Asset_Temporal]') AND type in (N'U'))
DROP TABLE [Intake].[MER_SF_Asset_Temporal]
GO
/****** 对象:表 [Intake].[MERSFAssetTemporalHistory] 脚本日期:04/05/2021 12:33:58 PM ******/
IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[Intake].[MERSFAssetTemporalHistory]') AND type in (N'U'))
DROP TABLE [Intake].[MERSFAssetTemporalHistory]
GO