搜索名称在变量中定义的表

时间:2009-07-24 13:56:56

标签: sql-server tsql

简单的问题,但也许没有简单的解决方案,至少我不能想到我的头脑之一,但那时我不是最好找到最好的解决方案。

我有一个存储过程,这个存储过程(以基本形式)在表上选择,设想这个:

SELECT * FROM myTable
好吧,很简单,除了它需要搜索的表名是不知道的,所以我们得到了一些非常类似的东西:

-- Just to give some context to the variables I'll be using
DECLARE @metaInfoID AS INT
SET @metaInfoID = 1

DECLARE @metaInfoTable AS VARCHAR(200)

SELECT @metaInfoTable = MetaInfoTableName FROM MetaInfos WHERE MetaInfoID = @MetaInfoID

DECLARE @sql AS VARCHAR(200)
SET @sql = 'SELECT * FROM ' + @metaInfoTable

EXEC @sql

所以,我认识到这最终是不好的,并且可以立即看到我可以执行sql注入攻击的地方。那么,问题是,有没有一种方法可以在不构建动态sql的情况下实现相同的结果?或者我是否必须超级,在我的客户代码中非常小心?

2 个答案:

答案 0 :(得分:1)

如果您事先不知道表名,则必须使用动态sql。但是,您应该在尝试在SQL语句中使用它之前验证该值。

e.g。

IF EXISTS(SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME=@metaInfoTable)
    BEGIN
        -- Execute the SELECT * FROM @metaInfoTable dynamic sql
    END

这将确保存在具有该名称的表。当您查询INFORMATION_SCHEMA时,显然会有这样做的开销。您可以改为验证@metaInfoTable仅包含某些字符:

-- only run dynamic sql if table name value contains 0-9,a-z,A-Z, underscores or spaces (enclose table name in square brackets, in case it does contain spaces)
IF NOT @metaInfoTable LIKE '%^[0-9a-zA-Z_ ]%'
    BEGIN
        -- Execute the SELECT * FROM @metaInfoTable dynamic sql
    END

答案 1 :(得分:0)

考虑到所描述的限制,我建议采用两种方式,性能与架构略有不同。

选择客户端&重新构建

我建议你应该尽可能考虑一个小的重新架构来强制调用者/客户端决定从哪个表中获取数据。将表名保存在另一个表中是code smell

我在这里假设@MetaInfoID正在从webapp,数据访问块等传递。这就是应该存放执行SELECT的表的逻辑的位置。我会说客户端应该根据GetCustomers知道要调用哪个存储过程(GetProducts@MetaInfoID)。在您的DAL中创建新方法,如GetCustomersMetaInfo()GetProductsMetaInfo()以及GetInvoicesMetaInfo(),它们会调用相应的sprocs(不需要动态SQL,也不需要维护数据库中的元表)。 / p>

也许尝试重新构建一下系统。

在SQL Server中

如果您必须在数据库中执行此查找,并且根据您拥有的表的数量,您可以执行少量IF语句(尽可能多的语句),如:

IF @MetaInfoID = 1
 SELECT * FROM Customers

IF @MetaInfoID =2 
 SELECT * FROM Products
-- etc

这可能会成为维持的噩梦。

也许你可以为每个MetaInfo编写一个存储过程。通过这种方式,您可以获得预编译的优势,并且此处不会发生SQL注入。 (想象一下,如果有人破坏了MetaInfoTableName列)

IF @MetaInfoID = 1
 EXEC GetAllCustomers
IF @MetaInfoID = 2
 EXEC GetAllProducts