Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/sql-server-2005/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何对删除表的T-SQL存储过程进行参数化?_Sql_Sql Server 2005_Tsql - Fatal编程技术网

如何对删除表的T-SQL存储过程进行参数化?

如何对删除表的T-SQL存储过程进行参数化?,sql,sql-server-2005,tsql,Sql,Sql Server 2005,Tsql,我想要一个简单的存储过程来删除表。这是我的第一次尝试: CREATE PROC bsp_susf_DeleteTable (@TableName char) AS IF EXISTS (SELECT name FROM sysobjects WHERE name = @TableName) BEGIN DROP TABLE @TableName END 当我在MS Query Analyzer中解析此项时,我得到以下错误: Server: Msg 170, Level 15, State 1,

我想要一个简单的存储过程来删除表。这是我的第一次尝试:

CREATE PROC bsp_susf_DeleteTable (@TableName char)
AS
IF EXISTS (SELECT name FROM sysobjects WHERE name = @TableName)
BEGIN
DROP TABLE @TableName
END
当我在MS Query Analyzer中解析此项时,我得到以下错误:

Server: Msg 170, Level 15, State 1, Procedure bsp_susf_DeleteTable, Line 6
Line 6: Incorrect syntax near '@TableName'.
哪种类型有意义,因为单个表的常规SQL是:

IF EXISTS (SELECT name FROM sysobjects WHERE name = 'tbl_XYZ')
BEGIN
    DROP TABLE tbl_XYZ
END
注意tbl_XYZ的第一个实例(在WHERE子句中)周围有单引号,而DROP语句中的第二个实例没有。如果我使用一个变量(@TableName),那么我就不需要进行这种区分


那么,是否可以创建一个存储过程来执行此操作?或者如果存在,我必须复制。。。无处不在?

您必须使用EXEC以字符串形式执行该查询。换句话说,当您传入表名时,定义一个varchar并分配查询和表名,然后执行您创建的变量

编辑:但是,我不建议这样做,因为有人可能传入sql而不是表名,从而导致各种各样的问题。有关更多信息,请参阅Sql注入

最好是在客户端为此创建一个参数化查询。例如,在C#中,我会做如下操作:

// EDIT 2: on second thought, ignore this code; it probably won't work
SqlCommand sc = new SqlCommand();
sc.Connection = someConnection;
sc.CommandType = Command.Text;
sc.CommandText = "drop table @tablename";
sc.Parameters.AddWithValue("@tablename", "the_table_name");
sc.ExecuteNonQuery();

您应该能够使用动态sql:

declare @sql varchar(max)
if exists (select name from sysobjects where name = @TableName)
BEGIN
   set @sql = 'drop table ' + @TableName
   exec(@sql)
END
希望这有帮助


更新:是的,你可以把@sql缩小,这只是一个简单的例子。另外请注意关于SQL注入攻击的其他评论

我个人对此非常谨慎。如果您觉得出于管理目的需要此文件,请确保执行此文件的权限非常有限。此外,我将让proc将表名和日期以及执行它的用户复制到日志记录表中。这样至少你会知道是谁把桌子掉错了。你可能还需要其他保护措施。例如,您可能希望指定某些无法使用此过程删除的表

此外,这并不是在所有情况下都适用于所有表。不能删除与外键关联的表

在任何情况下,我都不允许用户或任何不是数据库管理员的人执行此过程。如果您有一个用户可以删除表格的系统设计,那么您的设计很可能存在严重错误,应该重新思考


另外,除非您有非常非常好的备份计划,并且有从备份中恢复的经验,否则不要使用此过程。

Make@SQL nvarchar(max),因为表名是nvarchar。(实际上是sysname,但相当于nvarchar(一些数字,可能是128?)您还应该将@TableName转义为方括号。SQL Server有一个命令可以为您执行此操作。Set@SQL='drop table'+QuoteName(@TableName);老实说,如果存储过程的目的是删除传入的任意表,那么SQL错误攻击会更糟糕吗?我的意思是,如果可以在不需要黑客攻击的情况下删除数据库中的任何表,为什么还要逃避sring呢?顺便说一句,这()这就是为什么您需要担心Sql注入的原因。这些都是很好的观点。我的情况是,这些都不是问题。我们有一个生产数据库,它会在一夜之间复制,形成我们的报告数据库。我们对这个副本运行报告,以生成包含派生数据(没有外键)的表。我们只删除这些派生表。但如果我们意外地丢弃了某些内容,这并不重要。