我应该如何传递一个表名到一个存储过程?(How should I pass a table name

2019-06-18 04:51发布

我只是碰到了一件奇怪的事情......还有我们的网站,走的是一条巨大的SQL语句一些代码,做一些搜索和基于一些用户值替换,然后将它传递到SQL Server,修改它的代码一个问题。

我在想,这将是作为一个参数化查询吸尘器一个存储过程,与用户值作为参数,但是当我看着更加紧密地我明白为什么他们可能会做它...他们是从选择表可变地依赖于那些用户的值。

举例来说,在一种情况下,如果值分别为(“FOO”,“BAR”)的查询将最终被类似“SELECT * FROM foo_bar这样的名称”

有一个简单而清晰的方式来做到这一点? 我想一切都显得不雅。

编辑:我当然可以,动态生成的存储过程的SQL,和exec那个(的Bleh),但在这一点上,如果我已经获得了什么我不知道。

EDIT2:在一些智能的方式重构表名,说让他们都在用不同的名称一个表作为新列将是解决这一切的好办法,这几个人指出,直接或暗示。 可悲的是,它不是在这种情况下的一个选项。

Answer 1:

首先,你应该从来不知道像这样的客户端应用程序SQL命令组成, 这是 SQL注入是什么。 (其为管理工具,有没有自己的PRIVS OK,但不共享使用的应用程序)。

其次,是的,到存储过程的参数化调用既清洁和更安全。

然而 ,正如你将需要使用动态SQL来做到这一点,你还是不希望包括在执行查询的文本传递的字符串。 相反,你要使用的传递的字符串来查找用户应该被允许的方式来查询的实际表的名称。

这里有一个简单简单的例子:

CREATE PROC spCountAnyTableRows( @PassedTableName as NVarchar(255) ) AS
-- Counts the number of rows from any non-system Table, *SAFELY*
BEGIN
    DECLARE @ActualTableName AS NVarchar(255)

    SELECT @ActualTableName = QUOTENAME( TABLE_NAME )
    FROM INFORMATION_SCHEMA.TABLES
    WHERE TABLE_NAME = @PassedTableName

    DECLARE @sql AS NVARCHAR(MAX)
    SELECT @sql = 'SELECT COUNT(*) FROM ' + @ActualTableName + ';'

    EXEC(@SQL)
END

有些人相当问为什么这样做很安全。 但愿,小鲍比表可以理解得更为清晰:


答案更多的问题:

  1. 单独QUOTENAME不能保证是安全的。 MS鼓励我们使用它,但他们并没有给出一个保证,它不能被黑客攻击,大感迷惑。 仅供参考,真正的安全是所有关于担保。 与QUOTENAME查表,则是另一回事,这是牢不可破的。

  2. QUOTENAME不是绝对必要在这个例子中,在INFORMATION_SCHEMA的查找转换独自通常是足够的。 QUOTENAME是在这里,因为它是安全的好形式,包括一个完整的,正确的解决方案。 QUOTENAME在这里其实就是防范独特的,但类似的潜在问题。你知道潜注射



Answer 2:

(联合国)幸好没有这样做的方式 - 你不能使用作为参数,以比动态SQL生成其他存储的代码通过表名。 当谈到决定在哪里生成SQL代码,我更喜欢的应用程序代码,而存储的代码。 应用程序代码通常是更快,更容易维护。

如果你不喜欢你正在使用的解决方案,我建议更深入的重新设计(即更改架构/应用逻辑,所以你不再需要通过表名作为参数的任何地方)。



Answer 3:

我认为对动态生成的存储过程的SQL; 这会让你陷入困境,并可能导致注入漏洞。

相反,我会分析所有可能的查询将受影响的表,并建立某种形式枚举将确定用于查询的表中。



Answer 4:

听起来像是你会与ORM解决方案更好。

我畏缩当我看到动态SQL存储过程。



Answer 5:

你可以考虑的一件事是,使包含要在同一个SQL命令的情况下发言,每进行一次有效的表,然后将表名作为一个字符串传递到这个程序并有选择的情况下要运行的命令。

顺便说作为一个安全的人上面的建议,告诉你从系统表,以确保你有一个有效的表似乎是一个浪费的操作,我选择。 如果有人可以注入通过QUOTENAME(),然后再注入将在系统表一样好基础表上工作。 唯一这与它有助于确保它是一个有效的表名,我觉得上面的建议是一个更好的办法,因为你不使用QUOTENAME()在所有。



Answer 6:

根据这些表中的列集是否是相同的或不同的,我想接近它在长期来看有两种方式:

1)如果它们是相同的,为什么不创建将被用作选择器,其值从用户提供的参数导出的新列? (它是一个性能优化?)

2)如果他们是不同的,有机会,他们的处理也不同。 因此,它似乎是分裂的选择/处理代码为单独的块,然后要求他们分开将是一个最模块化的方法给我。 你会重复“选择*”的一部分,但在这种情况下表集是希望有限。

允许调用代码提供表名的任意两个部分做一个选择,从感觉很危险。



Answer 7:

我不知道为什么你在几个表中的数据传播的原因,但它听起来像你打破了基本原则之一。 该数据应在表中,而不是表名。

如果表有或多或少相同的布局,考虑是否将是最好的将数据放在一个表来代替。 这将解决您的问题与动态查询,它将使数据库布局更加灵活。



Answer 8:

而不是查询基于用户输入值的表,你可以挑选的程序来代替。 也就是说
1.创建一个过程FOO_BAR_prc和里面你把查询“选择foo_bar这样的名称*”,这样的查询可以通过数据库进行预编译。
2.然后根据用户输入的,现在从应用程序代码执行的正确步骤。

既然你有大约50桌,这可能不是,虽然因为这需要大量的工作,你一个可行的解决方案。



Answer 9:

其实,我想知道如何通过表名来创建存储过程的表。 通过阅读一些问题的答案,在我结束试图做一些修改,我终于可以创建一个表名作为参数传递。 这里是别人来检查任何错误在它的存储过程。

使用[数据库名称] GO / ******对象:StoredProcedure的[DBO] [sp_CreateDynamicTable]脚本日期:2015年6月20日16时56分25秒****** / SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO CREATE PROCEDURE [DBO] [sp_CreateDynamicTable] @tName VARCHAR(255)AS SET BEGIN NOCOUNT ON。 DECLARE @SQL为nvarchar(最大)

SET @SQL = N'CREATE TABLE [DBO].['+ @tName + '] (DocID nvarchar(10) null);'

    EXECUTE sp_executesql @SQL

结束



Answer 10:

@RBarry年轻的时候你不需要括号添加到@ActualTableName查询字符串,因为它已经包含在从INFORMATION_SCHEMA.TABLES查询结果。 否则,在执行时会出现错误(S)。

CREATE PROC spCountAnyTableRows(@PassedTableName如NVARCHAR(255))AS -计数的行从任何非系统表中的数字, 安全地开始DECLARE @ActualTableName AS NVARCHAR(255)

SELECT @ActualTableName = QUOTENAME( TABLE_NAME )
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_NAME = @PassedTableName

DECLARE @sql AS NVARCHAR(MAX)
--SELECT @sql = 'SELECT COUNT(*) FROM [' + @ActualTableName + '];'

-- changed to this
SELECT @sql = 'SELECT COUNT(*) FROM ' + @ActualTableName + ';'

EXEC(@SQL)

结束



文章来源: How should I pass a table name into a stored proc?