是否可以在没有 WHERE 子句的情况下阻止执行 UPDATE 或 DELETE 语句?
Is it possible to prevent UPDATE or DELETE statements being executed without a WHERE clause?
正如标题所暗示的那样,我们希望防止 - 至少通过手动界面 - 在特定 SQL 服务器(2008 或更高版本)数据库或 table 如果他们没有 WHERE 子句。
这可能吗?
如果您谈论的是 Microsoft SQL Server Management studio,那么您可以选择使用名为 SSMSBoost.
的插件
有了它,当您 运行 DELETE
没有 WHERE
时,您将始终收到警告。现在我不是 100% 确定这是否可以配置为 UPDATE
,但可能是。
可以。这并不理想,但您可以创建 table 触发器来评估每个 UPDATE
和 DELETE
以确定它们将影响多少行。
Erik Darling 在 Brent Ozar's blog 上发表了关于它的博客。他和我都不一定会推荐它,但如果情况足够绝望,嗯,这会起作用。
这是来自 link 的相关代码,以防万一,您知道,Brent 关门了。他很轻浮。
CREATE OR ALTER TRIGGER dbo.UseAWhereClauseNextTime
ON dbo.TriggerTest
FOR UPDATE, DELETE
AS
BEGIN
DECLARE @rc INT = @@ROWCOUNT;
DECLARE @table_rows INT = ( SELECT row_count
FROM sys.dm_db_partition_stats
WHERE object_id = OBJECT_ID('dbo.TriggerTest')
AND index_id IN ( 0, 1 ));
IF EXISTS ( SELECT 1 FROM Inserted ) AND EXISTS ( SELECT 1 FROM Deleted )
BEGIN
IF (( @rc * 100 ) / ( @table_rows )) >= 98
BEGIN
RAISERROR('USE A WHERE CLAUSE DUMMY', 0, 1) WITH NOWAIT;
ROLLBACK;
END;
END;
IF NOT EXISTS ( SELECT 1 FROM Inserted ) AND EXISTS ( SELECT 1 FROM Deleted )
IF ( ( @table_rows = 0 )
OR ( @table_rows > 0
AND (( @rc * 100 ) / ( @table_rows + @rc )) >= 98 ))
BEGIN
RAISERROR('USE A WHERE CLAUSE DUMMY', 0, 1) WITH NOWAIT;
ROLLBACK;
END;
END;
GO
带有 (( @rc * 100 ) / ( @table_rows )) >= 98
的两个子句将 "bad" 语句的阈值设置为受影响的 table 的 98%,Erik 指出这有点随意,但也是可配置的。
我认为你问错了问题。您想要阻止删除所有行(或一些高百分比的行)的删除,而不是阻止没有 WHERE
子句的删除。
无论恶意或草率,有意或无意,我都可以轻松击败对显式 WHERE
子句的任何解析,并且仍然删除所有行。
DELETE dbo.table WHERE 1 = 1;
DELETE dbo.table WHERE key_column > 0;
无论是否有意,我都可以关闭、不阅读或不小心按下 Enter 键或对插件提供的任何弹出窗口执行错误的鼠标单击,所以仅仅因为插件给我警告,并不意味着它将能够阻止我做我想做的事情。
当然,如果您认为缺少 WHERE
子句意味着它将删除所有行,那么您可能会错误地阻止只影响单行的查询。即使没有找到 WHERE
子句,以下语句都应限制在一个受影响的行(或多个有联系的行):
DELETE TOP (1) dbo.table;
;WITH RowToDelete AS
(
SELECT key_column FROM dbo.table
GROUP BY key_column
HAVING (key_column = 1)
)
DELETE RowToDelete;
;WITH RowToDelete AS
(
SELECT key_column, rn = ROW_NUMBER() OVER (ORDER BY key_column)
FROM dbo.table
)
DELETE TOP (1) RowToDelete;
如果您想实际防止意外删除所有行,您可以按照另一个答案中的建议在触发器中执行此操作,只要记住触发器就在那里想要绕过它,请注意它没有帮助 truncate
或 drop
或 transfer
.
正如标题所暗示的那样,我们希望防止 - 至少通过手动界面 - 在特定 SQL 服务器(2008 或更高版本)数据库或 table 如果他们没有 WHERE 子句。
这可能吗?
如果您谈论的是 Microsoft SQL Server Management studio,那么您可以选择使用名为 SSMSBoost.
的插件有了它,当您 运行 DELETE
没有 WHERE
时,您将始终收到警告。现在我不是 100% 确定这是否可以配置为 UPDATE
,但可能是。
可以。这并不理想,但您可以创建 table 触发器来评估每个 UPDATE
和 DELETE
以确定它们将影响多少行。
Erik Darling 在 Brent Ozar's blog 上发表了关于它的博客。他和我都不一定会推荐它,但如果情况足够绝望,嗯,这会起作用。
这是来自 link 的相关代码,以防万一,您知道,Brent 关门了。他很轻浮。
CREATE OR ALTER TRIGGER dbo.UseAWhereClauseNextTime
ON dbo.TriggerTest
FOR UPDATE, DELETE
AS
BEGIN
DECLARE @rc INT = @@ROWCOUNT;
DECLARE @table_rows INT = ( SELECT row_count
FROM sys.dm_db_partition_stats
WHERE object_id = OBJECT_ID('dbo.TriggerTest')
AND index_id IN ( 0, 1 ));
IF EXISTS ( SELECT 1 FROM Inserted ) AND EXISTS ( SELECT 1 FROM Deleted )
BEGIN
IF (( @rc * 100 ) / ( @table_rows )) >= 98
BEGIN
RAISERROR('USE A WHERE CLAUSE DUMMY', 0, 1) WITH NOWAIT;
ROLLBACK;
END;
END;
IF NOT EXISTS ( SELECT 1 FROM Inserted ) AND EXISTS ( SELECT 1 FROM Deleted )
IF ( ( @table_rows = 0 )
OR ( @table_rows > 0
AND (( @rc * 100 ) / ( @table_rows + @rc )) >= 98 ))
BEGIN
RAISERROR('USE A WHERE CLAUSE DUMMY', 0, 1) WITH NOWAIT;
ROLLBACK;
END;
END;
GO
带有 (( @rc * 100 ) / ( @table_rows )) >= 98
的两个子句将 "bad" 语句的阈值设置为受影响的 table 的 98%,Erik 指出这有点随意,但也是可配置的。
我认为你问错了问题。您想要阻止删除所有行(或一些高百分比的行)的删除,而不是阻止没有 WHERE
子句的删除。
无论恶意或草率,有意或无意,我都可以轻松击败对显式 WHERE
子句的任何解析,并且仍然删除所有行。
DELETE dbo.table WHERE 1 = 1;
DELETE dbo.table WHERE key_column > 0;
无论是否有意,我都可以关闭、不阅读或不小心按下 Enter 键或对插件提供的任何弹出窗口执行错误的鼠标单击,所以仅仅因为插件给我警告,并不意味着它将能够阻止我做我想做的事情。
当然,如果您认为缺少 WHERE
子句意味着它将删除所有行,那么您可能会错误地阻止只影响单行的查询。即使没有找到 WHERE
子句,以下语句都应限制在一个受影响的行(或多个有联系的行):
DELETE TOP (1) dbo.table;
;WITH RowToDelete AS
(
SELECT key_column FROM dbo.table
GROUP BY key_column
HAVING (key_column = 1)
)
DELETE RowToDelete;
;WITH RowToDelete AS
(
SELECT key_column, rn = ROW_NUMBER() OVER (ORDER BY key_column)
FROM dbo.table
)
DELETE TOP (1) RowToDelete;
如果您想实际防止意外删除所有行,您可以按照另一个答案中的建议在触发器中执行此操作,只要记住触发器就在那里想要绕过它,请注意它没有帮助 truncate
或 drop
或 transfer
.