运行 针对没有动态的多个表的相同查询 sql
Run the same query against multiple tables without dynamic sql
我支持第三方软件包的 SQL 数据库。他们有很多他们称之为 "Shadow Tables" 的东西,实际上只是审计表。这一切都很好,但他们的系统不会清理这些表,所以这取决于我。他们还会在每次升级时添加新的 "Shadow Tables",恕不另行通知。我们清除表的旧方法是使用一长串 DELETE FROM
语句,但此列表变得非常长且难以维护。
为了尝试使清除过程更易于维护并自动捕获新的 "Shadow Tables" 我编写了以下存储过程。存储过程有效,但我更愿意找出一种不使用游标和动态查询的方法,因为这将是 运行 每天在很多不同的表上。有没有不使用游标和动态查询的替代方法?
DECLARE @workingTable varchar(128);
DECLARE @sqlText varchar(250);
DECLARE @CheckDate DATETIME = DATEADD(yy, -2, GETDATE());
DECLARE curKey SCROLL CURSOR FOR
SELECT name AS TableName
FROM dataTEST.sys.tables
WHERE (name like '%[_]h' OR name like '%[_]dh')
ORDER BY name
OPEN curKey
WHILE @@fetch_status = 0
BEGIN
FETCH NEXT FROM curKey INTO @workingTable
SET @sqlText = 'DELETE FROM DataTEST.dbo.' + @workingTable + ' WHERE LAST_MOD < ''' + CONVERT(CHAR(10), @CheckDate, 101) + ''';'
--PRINT @sqlText
EXEC (@sqlText)
END
CLOSE curKey
DEALLOCATE curKey
我不认为在这里使用 cursor
和 dynamic query
是个坏主意
一种方法是附加删除查询并在生成所有删除查询后在最后执行它。
顺便说一句,游标只是用于构建动态查询,所以没什么大不了的
DECLARE @workingTable varchar(128);
DECLARE @sqlText nvarchar(max)='';
DECLARE @CheckDate DATETIME = DATEADD(yy, -2, GETDATE());
DECLARE curKey SCROLL CURSOR FOR
SELECT name AS TableName
FROM dataTEST.sys.tables
WHERE (name like '%[_]h' OR name like '%[_]dh')
ORDER BY name
OPEN curKey
WHILE @@fetch_status = 0
BEGIN
FETCH NEXT FROM curKey INTO @workingTable
SET @sqlText += 'DELETE FROM DataTEST.dbo.' + @workingTable + ' WHERE LAST_MOD < ''' + CONVERT(CHAR(10), @CheckDate, 101) + ''';'
END
CLOSE curKey
DEALLOCATE curKey
--PRINT @sqlText
EXEC (@sqlText)
您可以通过执行以下操作获得更好的性能:
DECLARE @workingTable SYSNAME;
DECLARE @sqlText nvarchar(MAX);
DECLARE @CheckDate DATETIME = DATEADD(YEAR, -2, GETDATE());
DECLARE curKey CURSOR LOCAL FAST_FORWARD FOR
SELECT name AS TableName
FROM dataTEST.sys.tables
WHERE (name like '%[_]h' OR name like '%[_]dh')
ORDER BY name
OPEN curKey
WHILE @@fetch_status = 0
BEGIN
FETCH NEXT FROM curKey INTO @workingTable
SET @sqlText = 'DELETE FROM DataTEST.dbo.' + QUOTENAME(@workingTable)
+ ' WHERE LAST_MOD < @CheckDate'
Exec sp_executesql @sqlText
,N'@CheckDate DATETIME'
,@CheckDate
END
CLOSE curKey
DEALLOCATE curKey
改进:
- 为 sql 服务器对象名称 tables (SYSNAME) 使用适当的数据类型。
- 使用
sp_executesql
代替EXEC(@Sql)
- 将参数作为日期传递,不要将其转换为字符串,以便 sql 服务器可以使用在该列上定义的索引。
- 使用
QUOTENAME()
函数将 table 名称括在方括号中,以防任何 table 名称是 sql 服务器中的保留关键字,因此查询不会出错。
- 将光标设置为本地光标,fast_forward 光标默认设置为全局光标,您不需要那个,对吗?
当您提前不知道 table 名称时,我不知道如何摆脱动态 SQL。 SQL 服务器有一项功能,您可以在 select
语句中为每一行返回一次变量赋值。这可用于消除游标并将所有 delete
语句的一个字符串传递给 SQL 服务器以执行
DECLARE @sqlText nvarchar(MAX) = ''; -- initialize because NULL + 'x' is NULL
DECLARE @CheckDate DATETIME = DATEADD(YEAR, -2, GETDATE());
SELECT @sqlText = @SqlText + 'DELETE FROM dataTEST.dbo.' + QUOTENAME(name)
+ ' WHERE LAST_MOD < @CheckDate ; '
FROM dataTEST.sys.tables
WHERE (name like '%[_]h' OR name like '%[_]dh')
ORDER BY name
IF @@ROWCOUNT > 0
EXEC sp_executesql @sqlText
, N'@CheckDate DATETIME'
, @CheckDate
我支持第三方软件包的 SQL 数据库。他们有很多他们称之为 "Shadow Tables" 的东西,实际上只是审计表。这一切都很好,但他们的系统不会清理这些表,所以这取决于我。他们还会在每次升级时添加新的 "Shadow Tables",恕不另行通知。我们清除表的旧方法是使用一长串 DELETE FROM
语句,但此列表变得非常长且难以维护。
为了尝试使清除过程更易于维护并自动捕获新的 "Shadow Tables" 我编写了以下存储过程。存储过程有效,但我更愿意找出一种不使用游标和动态查询的方法,因为这将是 运行 每天在很多不同的表上。有没有不使用游标和动态查询的替代方法?
DECLARE @workingTable varchar(128);
DECLARE @sqlText varchar(250);
DECLARE @CheckDate DATETIME = DATEADD(yy, -2, GETDATE());
DECLARE curKey SCROLL CURSOR FOR
SELECT name AS TableName
FROM dataTEST.sys.tables
WHERE (name like '%[_]h' OR name like '%[_]dh')
ORDER BY name
OPEN curKey
WHILE @@fetch_status = 0
BEGIN
FETCH NEXT FROM curKey INTO @workingTable
SET @sqlText = 'DELETE FROM DataTEST.dbo.' + @workingTable + ' WHERE LAST_MOD < ''' + CONVERT(CHAR(10), @CheckDate, 101) + ''';'
--PRINT @sqlText
EXEC (@sqlText)
END
CLOSE curKey
DEALLOCATE curKey
我不认为在这里使用 cursor
和 dynamic query
是个坏主意
一种方法是附加删除查询并在生成所有删除查询后在最后执行它。
顺便说一句,游标只是用于构建动态查询,所以没什么大不了的
DECLARE @workingTable varchar(128);
DECLARE @sqlText nvarchar(max)='';
DECLARE @CheckDate DATETIME = DATEADD(yy, -2, GETDATE());
DECLARE curKey SCROLL CURSOR FOR
SELECT name AS TableName
FROM dataTEST.sys.tables
WHERE (name like '%[_]h' OR name like '%[_]dh')
ORDER BY name
OPEN curKey
WHILE @@fetch_status = 0
BEGIN
FETCH NEXT FROM curKey INTO @workingTable
SET @sqlText += 'DELETE FROM DataTEST.dbo.' + @workingTable + ' WHERE LAST_MOD < ''' + CONVERT(CHAR(10), @CheckDate, 101) + ''';'
END
CLOSE curKey
DEALLOCATE curKey
--PRINT @sqlText
EXEC (@sqlText)
您可以通过执行以下操作获得更好的性能:
DECLARE @workingTable SYSNAME;
DECLARE @sqlText nvarchar(MAX);
DECLARE @CheckDate DATETIME = DATEADD(YEAR, -2, GETDATE());
DECLARE curKey CURSOR LOCAL FAST_FORWARD FOR
SELECT name AS TableName
FROM dataTEST.sys.tables
WHERE (name like '%[_]h' OR name like '%[_]dh')
ORDER BY name
OPEN curKey
WHILE @@fetch_status = 0
BEGIN
FETCH NEXT FROM curKey INTO @workingTable
SET @sqlText = 'DELETE FROM DataTEST.dbo.' + QUOTENAME(@workingTable)
+ ' WHERE LAST_MOD < @CheckDate'
Exec sp_executesql @sqlText
,N'@CheckDate DATETIME'
,@CheckDate
END
CLOSE curKey
DEALLOCATE curKey
改进:
- 为 sql 服务器对象名称 tables (SYSNAME) 使用适当的数据类型。
- 使用
sp_executesql
代替EXEC(@Sql)
- 将参数作为日期传递,不要将其转换为字符串,以便 sql 服务器可以使用在该列上定义的索引。
- 使用
QUOTENAME()
函数将 table 名称括在方括号中,以防任何 table 名称是 sql 服务器中的保留关键字,因此查询不会出错。 - 将光标设置为本地光标,fast_forward 光标默认设置为全局光标,您不需要那个,对吗?
当您提前不知道 table 名称时,我不知道如何摆脱动态 SQL。 SQL 服务器有一项功能,您可以在 select
语句中为每一行返回一次变量赋值。这可用于消除游标并将所有 delete
语句的一个字符串传递给 SQL 服务器以执行
DECLARE @sqlText nvarchar(MAX) = ''; -- initialize because NULL + 'x' is NULL
DECLARE @CheckDate DATETIME = DATEADD(YEAR, -2, GETDATE());
SELECT @sqlText = @SqlText + 'DELETE FROM dataTEST.dbo.' + QUOTENAME(name)
+ ' WHERE LAST_MOD < @CheckDate ; '
FROM dataTEST.sys.tables
WHERE (name like '%[_]h' OR name like '%[_]dh')
ORDER BY name
IF @@ROWCOUNT > 0
EXEC sp_executesql @sqlText
, N'@CheckDate DATETIME'
, @CheckDate