2

在下面的示例代码中,表名是一个输入参数。在这种情况下,如何避免使用sp_executesql. 下面是示例代码,我试图用sp_executesql它来避免它,但它不起作用。谁能告诉我如何纠正它?

ALTER PROC Test @param1  NVARCHAR(50), 
                 @param2  INT, 
                 @tblname NVARCHAR(100) 
AS 
  BEGIN 
      DECLARE @sql NVARCHAR(1000) 

      SET @sql= N'  select * from ' + @tblname 
                + ' where name= @param1 and id= @param2'; 

      PRINT @sql 

      EXEC Sp_executesql 
        @sql, 
        N'@param1 nvarchar(50), @param2 int', 
        @param1, 
        @param2; 
  END 

EXEC Test 
  'John', 
  2, 
  ' emp; delete from emp where id = 567; select * from emp ' 

输出:打印消息:

select * from  emp; delete from emp where id = 567; select * from emp  where name= @param1 and id= @param2;

所有输入参数都被完全替换,并删除了一行。请让我知道如何处理这种情况。

4

2 回答 2

1

您可以首先检查参数值是否确实是表名:

ALTER PROC Test @param1  NVARCHAR(50), 
             @param2  INT, 
             @tblname NVARCHAR(100) 
AS 
BEGIN 
  DECLARE @sql NVARCHAR(1000) 

  IF EXISTS(SELECT 1 FROM sys.objects WHERE type = 'u' AND name = @tblname)
  BEGIN
      SET @sql= N'  select * from ' + @tblname 
                + ' where name= @param1 and id= @param2'; 

      PRINT @sql 

      EXEC Sp_executesql 
        @sql, 
        N'@param1 nvarchar(50), @param2 int', 
        @param1, 
        @param2; 
  END
END 

如果传递的值不是表名,您的过程将不会做任何事情;或者您可以更改它以引发错误。这样,如果参数包含查询,您就安全了。

于 2015-03-25T17:51:40.057 回答
-1

您可以将表名包含在[]

SET @sql= N'  select * from [' + @tblname + '] where name= @param1 and id= @param2'; 

但是,如果您使用由两部分组成的命名约定,例如dbo.tablename,您必须添加额外的解析,因为[dbo.tablename]这将导致:

无效的对象名称 [dbo.tablename]。

您应该对其进行解析,使其等于dbo.[tablename].

于 2015-03-25T03:44:43.790 回答