我支持第三方软件包的SQL数据库。他们有很多所谓的“影子表”,实际上只是审计表。一切都很好,但是他们的系统不会清理这些表,所以我需要这样做。他们还将在每次升级时添加新的“影子表”,而无需另行通知。我们清除表的旧方法是使用一长串DELETE FROM语句,但是此列表变得非常长且难以维护。
DELETE FROM
为了使清除过程更易于维护并自动捕获新的“影子表”,我编写了以下存储过程。存储过程可以工作,但是我更想找出一种不使用游标和动态查询的方法,因为它将每天在许多不同的表上运行。有没有使用游标和动态查询的替代方法吗?
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
无论如何,当您提前不知道表名时,无论如何我都不知道要摆脱动态SQL。SQL Server具有一项功能,您可以在select语句中对返回的每一行进行一次变量分配。这可用于消除游标并将带有所有delete语句的一个字符串传递给SQL Server以执行
select
delete
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