2

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

例子:

Common: tblCommon
Specific: tblSpecific

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

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

6 回答 6

11

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

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

动态 SQL 的诅咒和祝福是我所见过的描述所有进出的最佳页面。

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

于 2008-11-04T23:10:05.173 回答
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)
于 2008-11-04T23:08:58.220 回答
1

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

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

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

CREATE TABLE [tables] (table_name sysname)

然后,您可以编写如下所示的查询:

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

现在你只需要检查是否@tblSpecificNULL. 如果不是,那么在动态 SQL 语句中使用是安全的(动态 SQL 最终是您在这里唯一的选择:即使用户定义的函数也让您在某种程度上这样做)。

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

于 2008-11-05T03:20:24.997 回答
1

将您的查询制定/操作为字符串,然后调用EXECUTE(@SQLStatement)

于 2013-05-22T10:19:00.133 回答
0

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

SELECT ....
FROM tblCommon c
INNER JOIN dbo.SomeFuntionThatReturnsData(@someparam) s on c.primaryKey = s.foreignKey
于 2008-11-04T23:11:55.920 回答
0

我会将它们分别保存为不同的存储过程。

尽可能地,我喜欢保持我的存储过程简单明了。它们很难一眼就能理解,因为无论如何表达式都延伸得太多了,并且添加一堆与声明性代码片段混合的过程代码只会让它变得更加困难。

您将得到一个包含 15 次调用的更复杂的带参数存储过程的列表,或者您将得到一个等效的更简单存储过程的列表。如果你的参数是一个表名,它就不会是那种高效执行的参数化 sp。至于表驱动的方法,它仍然是效率较低且更危险的动态存储过程。表条目很可能被错误输入,除了在表中,任何表名错误都将更不明显。耦合度上升了,粘性下降了(两者都朝着错误的方向发展)。

于 2008-11-05T05:23:16.840 回答