DECLARE @tablename sysname; -- pretend this is a parameter
SET @tablename = N'this_is_not_a_table';
-- in procedure body:
IF NOT EXISTS (SELECT 1 FROM sys.tables WHERE name = @tablename)
BEGIN
RAISERROR(N'Table does not exist.', 1, 11);
RETURN;
END
SET @sql = N'SELECT ... FROM dbo.' + QUOTENAME(@tablename) + ...;
-- EXEC(@sql) or EXEC sys.sp_executesql @sql
对于某些类型的参数化,是否使用
EXEC()
or并不重要sp_executesql
,因为有些东西无论如何都无法参数化。例如,您在评论中表示(请更新您的问题以更具体地说明您的要求!)您正在参数化表名,但这些不能参数化,因为它们需要按字面意思表达给 SQL Server(它不能标记它并在运行时交换)。为了保护自己免受表名漏洞的影响,您可以像这样轻松保护自己:
现在,我更喜欢使用
sp_executesql
always,部分原因是它促进使用强类型参数(避免 SQL 注入问题以及双单引号问题),还因为在某些情况下,您将同时为可参数化和不可参数化的值传递参数(是的,我编造了这些话)。更多信息:现在您唯一需要担心的是是否有人能够创建表并可以创建一个名为的表
sys.objects; DROP TABLE foo; --
- 但是如果您有一个您不信任但有能力在您的数据库中创建表的人......看看使用sp_executeSQL代替。它是完全参数化的,因此为动态查询提供了更大的安全感(并且在具有严格权限集的过程中与EXECUTE AS USER一起使用会使它变得更好)。