Warn for DELETE All records
在 SQL Server Management Studio (SSMS) 中執行刪除所有資料時,是不會有任何提醒的!!
例如將 delete * from XX 看成 select * from XX,或者未加篩選條件時,都可以輕易地直接刪除整個資料表的所有資料。
防範類似的悲劇發生,可行做法:
異動大量資料前,手動備份一次。
PS: 這段語法查詢是需要授權
參考
Prevent accidental update or delete commands of all rows in a SQL Server table
例如將 delete * from XX 看成 select * from XX,或者未加篩選條件時,都可以輕易地直接刪除整個資料表的所有資料。
防範類似的悲劇發生,可行做法:
SQL Server 定期備份
當發生誤刪資料時,確保可以進行環原。異動大量資料前,手動備份一次。
自製警告訊息
SSMS (v17.9) 目前沒有類似提醒的設定,不過可以在 delete trigger 加上類似的檢查,預防不小心刪除整個資料表,若真需要全部刪除前,再手動停用 Trigger,執行刪除後再手動啟Trigger。建立刪除警告的 Trigger
FOR DELETE
AS
BEGIN
DECLARE @Count int
SET @Count = @@ROWCOUNT;
IF @Count >= (SELECT SUM(row_count)
FROM sys.dm_db_partition_stats
WHERE OBJECT_ID = OBJECT_ID('dbo.MyTable_LOG')
AND index_id = 1)
BEGIN
RAISERROR('Cannot delete all rows at once.',16,1)
ROLLBACK TRANSACTION
RETURN;
END
END
停用 Trigger 語法
DISABLE TRIGGER [dbo].[RPTIMG_LOG_delete_trigger] ON [dbo].[RPTIMG_LOG]
啟用 Trigger 語法
ENABLE TRIGGER [dbo].[RPTIMG_LOG_delete_trigger] ON [dbo].[RPTIMG_LOG]
所有資料表,建立預防刪除所有資料的 Trigger
/*--------------------------------------------------
description: 所有資料表,建立預防刪除所有資料的 Trigger
author: Robin
date: 2018/09/17
testing Code:
--------------------------------------------------
EXEC aDevTool_DBA_Create_Prevent_Delete_All
--------------------------------------------------*/
CREATE Procedure [dev].[aDevTool_DBA_Create_Prevent_Delete_All]
AS
BEGIN
DECLARE @ExampleString1 nvarchar(1024), @ExampleString2 nvarchar(1024)
SET @ExampleString1='
IF EXISTS (SELECT * FROM sys.objects WHERE type = ''TR'' AND name = ''MyTable_delete_all_trigger'')
BEGIN
DROP TRIGGER dbo.MyTable_delete_all_trigger
END'
SET @ExampleString2='
CREATE TRIGGER dbo.MyTable_delete_all_trigger ON dbo.MyTable
FOR DELETE
AS
BEGIN
DECLARE @Count int
SET @Count = @@ROWCOUNT;
IF @Count >= (SELECT SUM(row_count)
FROM sys.dm_db_partition_stats
WHERE OBJECT_ID = OBJECT_ID(''dbo.MyTable'')
AND index_id = 1)
BEGIN
RAISERROR(''Cannot delete all rows at once.'',16,1)
ROLLBACK TRANSACTION
RETURN;
END
END';
DECLARE @SchemaName varchar(8), @TableName varchar(32)
DECLARE CURSOR1 CURSOR READ_ONLY LOCAL FOR
SELECT SchemaName = t.table_schema,
TableName = t.table_name
FROM information_schema.tables t
where t.table_type = 'BASE TABLE'
--and t.TABLE_NAME='ADEVTOOL_SETALLSTOCKONORDER_LOG'
ORDER BY SchemaName, TableName;
OPEN CURSOR1
FETCH NEXT FROM CURSOR1 INTO @SchemaName, @TableName
WHILE @@FETCH_STATUS = 0
BEGIN
DECLARE @SqlString1 nvarchar(1024), @SqlString2 nvarchar(1024)
print @SchemaName+'.'+@TableName
SET @SqlString1 = REPLACE(@ExampleString1, 'dbo.MyTable', @SchemaName+'.'+@TableName)
SET @SqlString1 = REPLACE(@SqlString1, 'MyTable_', @TableName+'_')
print @SqlString1
EXECUTE sp_executesql @SqlString1;
SET @SqlString2 = REPLACE(@ExampleString2, 'dbo.MyTable', @SchemaName+'.'+@TableName)
SET @SqlString2 = REPLACE(@SqlString2, 'MyTable_', @TableName+'_')
print @SqlString2;
EXECUTE sp_executesql @SqlString2;
print 'done'
FETCH NEXT FROM CURSOR1 INTO @SchemaName, @TableName
END
CLOSE CURSOR1;
DEALLOCATE CURSOR1;
END
PS: 這段語法查詢是需要授權
GRANT VIEW SERVER STATE TO [AppUser1]; GO GRANT VIEW ANY DEFINITION TO [AppUser1]; GO
參考
Prevent accidental update or delete commands of all rows in a SQL Server table