表名占位符-TSQL

时间:2018-10-21 08:53:29

标签: sql-server tsql

有没有办法做这样的事情?人是表的名字。

declare @placeholder varchar(20) = 'People'
select * from @placeholder 

或者类似这样的表名称为People_Backup。

declare @placeholder varchar(20) = '_Backup'
select * from People@placeholder 

有没有一种方法可以在动态sql中添加变量的值? 像这样的东西:

declare @placeholder nvarchar(20) = 'people'
declare @name nvarchar(30) = 'antony'

declare @query nvarchar(1000) = 'select * from ' + @placeholder + ' where 
first_name=' + @name 
exec sp_executesql @query

我的意思是:不这样做

exec sp_executesql @query, N'@name varchar(30)', @name 

谢谢您的回答。

2 个答案:

答案 0 :(得分:3)

不是没有动态SQL。
SQL中的参数是 data 的占位符,不能用作其他任何内容(包括 commands ,例如selectupdate的占位符等”和标识符,例如数据库名称,架构名称,表名称,列名称等)。

参数化表名的唯一方法是使用动态SQL-这意味着您必须构建一个包含要执行的SQL的字符串,然后执行它。
当心-动态SQL可能是SQL injection攻击的门户-因此您必须明智地做-这是一些基本规则:

  • 始终将您的标识符列入白名单(使用系统表或视图,例如sys.TablesInformation_schema.Columns

  • 始终使用sysname作为标识符的数据类型。

      

    sysname数据类型用于存储对象名称的表列,变量和存储过程参数。 sysname的确切定义与标识符规则有关。因此,它在SQL Server实例之间可能有所不同。

  • 从不在参数中传递SQL命令或子句-set @placeholder = 'select a, b, c'set @placeholder = 'where x = y' 是安全隐患!

    < / li>
  • 始终使用参数存储数据。切勿将参数串联到您的sql字符串中:set @sql = 'select * from table where x = '+ @x是安全隐患。始终创建动态SQL以将参数用作参数:set @sql = 'select * from table where x = @x'

  • 始终使用sp_executeSql而不是EXEC(@SQL)来执行动态SQL语句。
    有关更多信息,请阅读Kimberly Tripp的EXEC and sp_executesql – how are they different?

  • 始终QUOTENAME()包装标识符,以确保正确的查询,即使标识符包含诸如空格之类的字符

回顾一下-您要求的安全版本(带有一个动态的where子句来说明其他要点)是这样的:

@DECLARE @TableName sysname = 'People',
         @ColumnName sysname = 'FirstName'
         @Search varchar(10) = 'Zohar';

IF EXISTS(
    SELECT 1
    FROM Information_Schema.Columns
    WHERE TABLE_NAME = @TableName 
    AND COLUMN_NAME = @ColumnName
)
BEGIN
    DECLARE @Sql nvarchar(4000) = 
    'SELECT * FROM +' QUOTENAME(@TableName) +' WHERE '+ QUOTENAME(@ColumnName) +' LIKE ''%''+ @Search +''%'';'

    EXEC sp_executesql @Sql, N'@Search varchar(10)', @Search

END
-- you might want to raise an error if not

直接编辑后回答您的问题:

  

我的意思是:不执行exec sp_executesql @query,N'@ name varchar(30)',@name

是的,您可以不使用sp_executeSql来做到这一点,但这很危险-攻击者可以使用类似'';DROP TABLE People;--的值作为{{1} },以便在执行sql时,您的@name表将被删除。

为此,您需要将People@name-

换行
'

答案 1 :(得分:0)

  

我的意思是:如果不这样做,exec sp_executesql @query, N'@name varchar(30)', @name

是的,您可以这样做

--Use MAX instead of 1000
DECLARE @SQL nvarchar(MAX) = N'SELECT * FROM ' + @placeholder + ' WHERE first_name = '''+@name +'''';
EXECUTE sp_executesql @SQL;