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

时间:2009-07-09 01:04:36

标签: 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, 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),那么我就无法做出这种区分。

创建存储过程也可以这样做吗?或者我是否必须复制IF EXISTS ......无处不在?

3 个答案:

答案 0 :(得分:3)

您应该能够使用动态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注入攻击的其他注释

答案 1 :(得分:2)

我个人非常担心这样做。如果您认为出于管理目的需要它,请确保执行此操作的权限非常有限。此外,我将proc复制表名和日期以及执行它的用户到日志表。这样至少你会知道是谁丢错了桌子。您可能还需要其他保护措施。例如,您可能希望指定使用此proc无法删除的某些表。

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

在任何情况下,我都不允许用户或不是数据库管理员的任何人执行此proc。如果你有一个系统设计,用户可以放弃表格,你的设计很可能会出现严重错误,应该重新考虑。

另外,请不要使用此proc,除非您有一个非常非常好的备份计划,并且可以从备份中恢复。

答案 2 :(得分:0)

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

编辑:但是,我不建议这样做,因为有人可以传入sql而不是TableName并导致各种奇妙的问题。有关更多信息,请参阅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();