【问题标题】:Passing table name in sql stored procedure在sql存储过程中传递表名
【发布时间】:2012-05-24 09:13:28
【问题描述】:

是否可以将表名作为输入参数传递给存储过程?

例如:

create procedure test
@tablename char(10)
as
begin
select * from @tablename
end
go

我知道这行不通。那么如果我想将表名传递到存储过程中,最好的方法是什么?

非常感谢

【问题讨论】:

标签: tsql stored-procedures


【解决方案1】:

最安全的方法是通过视图。

创建一个视图,它将您可能希望访问的所有表联合起来(并且这些表必须具有相同的列结构),并在行前加上表名。

CREATE VIEW MultiTable
AS
    SELECT 'table1' AS TableName, * FROM table1
    UNION ALL
    SELECT 'table2' AS TableName, * FROM table2
    UNION ALL
    SELECT 'table3' AS TableName, * FROM table3

您的存储过程现在可以过滤表名:

CREATE PROCEDURE test
    @TableName varchar(100)
AS
    SELECT * FROM MultiTable WHERE TableName = @TableName

这比使用动态 SQL 创建和执行更安全。

【讨论】:

  • 需要注意的是,使用“*”的例子是假设三个表的列数相同。我相信否则你会得到一个错误。即使是这种情况,作为最佳实践,您也应该在每个 SELECT 中枚举它们。
  • @Buggieboy 可能会收到该错误,如果列仅在其中一个表中发生更改是值得的........
【解决方案2】:

您需要使用动态 SQL,但您需要注意潜在的 sql 注入风险,就像 @tablename 包含一些狡猾的东西一样,您可能会陷入痛苦的世界。

例如

-- basic check to see if a table with this name exists
IF NOT EXISTS(SELECT * FROM sys.tables WHERE name = @tablename)
    RETURN

DECLARE @sql NVARCHAR(100)
SET @sql = 'SELECT * FROM ' + QUOTENAME(@tablename)
EXECUTE(@sql)

你需要非常小心这种方法,确保你没有打开一罐安全蠕虫。

我的另一个顾虑是您可能正在尝试创建通用数据访问存储过程,这通常是个坏主意。显然我不知道你的用例。

【讨论】:

  • 非常感谢。 sql注入的可能性几乎可以忽略不计,因为表名没有用户条目。它仅由应用程序内部使用 - 我想避免创建多个具有相同逻辑的存储 prc,但表名不同
  • @Bridge - 是的,我完全同意。在我真正需要使用动态表名的情况下,我个人在应用程序代码中生成了 SQL。但我发现真正的用例并不常见
  • @user1414575 - 我强烈推荐阅读 Erland Sommerskog 的文章(@Bridge 的链接)。这听起来确实像您正在寻找的一种节省时间/通用数据访问方法,根据我的经验,这是不好的
【解决方案3】:
DECLARE @Name VARCHAR(50)
SET @Name='Company'

EXEC('SELECT * from ' + @Name )

使用这种方式从数据库中获取记录。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-07-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-09-26
    相关资源
    最近更新 更多