SQL Server动态查询

时间:2008-11-04 23:01:18

标签: sql sql-server tsql dynamic

我有15个存储过程从公用表返回数据,然后将该表与特定表连接以检索库存。

示例:

Common: tblCommon
Specific: tblSpecific

有没有办法可以将名称“tblSpecific”作为变量传递给单个存储过程,如下所示?

SELECT ....
FROM tblCommon c
INNER JOIN @TABLE s on c.primaryKey = s.foreignKey

6 个答案:

答案 0 :(得分:10)

执行此操作的方法是使用动态生成的SQL,该SQL通过sp_executesql()存储过程运行。

通常,将所需的表名传递给主过程,构建要执行的SQL的ncharvar字符串,并将其传递给sp_executesql。

The curse and blessing of Dynamic SQL是关于描述所有输入和输出的最佳页面。

最大的问题之一是,如果使用动态SQL,那么调用存储过程的用户不仅必须具有该过程的执行权限,而且还必须具有访问基础表的权限。我给出的链接还描述了如何解决这个问题。

答案 1 :(得分:3)

是的,您可以动态生成SQL语句然后执行它。

例如,

DECLARE @specificTableName nvarchar(50)
DECLARE @specificColumnName nvarchar(50)

SET @specificTableName = 'tblSpecific'
SET @specificColumnName = 'colSpecific'

DECLARE @sql nvarchar(4000)

set @sql = 'SELECT ... FROM tblCommon c INNER JOIN ' +
@specificTableName + ' s ON c.PrimaryKey = s.' + @specificColumnName


exec (@sql)

答案 2 :(得分:1)

动态SQL很危险。您从不希望将传递的值直接替换为SQL字符串。幸运的是,听起来你已经知道了。

不幸的是,在这种情况下,您发现了一个问题,即您不能对表名使用SQL参数。那么该怎么办?您不希望在动态生成的SQL中使用传递的值,但不能以正常的安全方式将其放入查询中。

答案是查找表。创建一个“表”表,其中包含每个特定表的名称。看起来应该是这样的:

CREATE TABLE [tables] (table_name sysname)

然后你可以写一个看起来像这样的查询:

SELECT @tblSpecific = table_name FROM [tables] WHERE table_name = @tblSpecific

现在您只需检查@tblSpecific是否为NULL。如果不是,那么在动态SQL语句中使用是安全的(动态SQL最终是你的 only 选项:即使是用户定义的函数,你也可以在某种程度上这样做。)

哦,还有一件事 - 我为查询表选择的名称和类型并非偶然。 SQL Standard已经有了这样一个表(好吧,无论如何都是一个视图)。只需使用INFORMATION_SCHEMA.Tables

答案 3 :(得分:1)

以字符串形式构建/操纵您的查询,然后调用EXECUTE(@SQLStatement)

答案 4 :(得分:0)

另一种方法是,如果数据量不是太大,您可能需要考虑用户定义的函数,该函数可以返回一个可用于连接的表变量。

SELECT ....
FROM tblCommon c
INNER JOIN dbo.SomeFuntionThatReturnsData(@someparam) s on c.primaryKey = s.foreignKey

答案 5 :(得分:0)

我会将它们作为一个独特的存储过程保存。

尽可能地,我希望保持我的存储过程简单明了。它们非常难以一目了然,因为无论如何,表达式都非常广泛,并且添加了一堆与声明性代码片段相互混合的过程代码,这使得它变得更加困难。

您要么最终得到一个包含参数的更复杂存储过程的15个调用列表,要么最终会得到一个更简单的存储过程的等效列表。如果您的参数是表名,那么它将不是那种有效执行的参数化sp。至于表驱动方法,它仍然是效率较低且更危险的动态存储过程。表条目很可能被错误输入,除了在表中,任何表名错误都会更不可见。耦合已经上升,而且粘性已经下降(两者都走向了错误的方向)。