【问题标题】:Pass string variable into procedure and add it to a query将字符串变量传递给过程并将其添加到查询中
【发布时间】:2012-04-24 17:05:54
【问题描述】:

我有一个用 C# 编写的应用程序,它连接到数据库并分析其数据,数据库存储有关执行自动化测试的信息,我想做的是检索那些满足上述给定条件的测试。但是我们有不同的项目,并且支持的项目越来越多,所以我不想为每个项目构建不同的过程,而是传递名称 - 第二个参数 deploy 作为参数,这样查询将取决于项目并将数据返回到申请,然后我会在报告中发送。

暂时是这样的:

CREATE PROCEDURE [dbo].[SuspectsForFalsePositive](@build_id INT, @deploy VARCHAR(25)) 
AS
BEGIN

    SET NOCOUNT ON;

    DECLARE @i int, @build int, @deployname varchar(25), @SQL varchar(max)
    DECLARE @result table (tc int, fp float)
    SET @i = 0
    SET @build = @build_id
    SET @deployname = @deploy

    SET @SQL = 'insert '+@result+'select testcase_id, fail_percentage FROM [BuildTestResults].[dbo].['+@deployname+'TestCaseExecution]
                   where build_id = @build and fail_percentage >= 70'

--INSERT @result select testcase_id, fail_percentage FROM [BuildTestResults]
--.[dbo].[ABCTestCaseExecution]
--where build_id = @build and fail_percentage >= 70
--commented works
    EXEC(@SQL)
    WHILE (@@rowcount = 0)
    BEGIN
    SET @build = @build - 1
    EXEC(@SQL)
--INSERT @result select testcase_id, fail_percentage FROM [BuildTestResults].[dbo]. --[ABCTestCaseExecution]
--where build_id = @build and fail_percentage >= 70
--commented works
    END
    select * from @result order by fp DESC
END
GO

感谢您的建议!

【问题讨论】:

标签: sql sql-server-2008 stored-procedures concatenation


【解决方案1】:

您的示例存在一些问题。然而,这是一个首要考虑因素。

变量(表和/或标量)仅在定义它们的 StoredProcedure 中可见。调用 EXEC(@SQL) 是调用存储的。这意味着您的@result 表和其他参数都对您正在执行的动态 SQL 不可见。

就表而言,您可以通过创建临时表来解决这个问题。对于标量变量,您可以在使用 SP_EXECUTESQL 而不是 EXEC 时传递它们。

我目前无法访问 sql server,但也许像这样的东西可以让你开始......

CREATE PROCEDURE [dbo].[SuspectsForFalsePositive](@build_id INT, @deploy VARCHAR(25)) 
AS
BEGIN

  SET NOCOUNT ON;

  DECLARE
    @i          int,
    @build      int,
    @deployname varchar(25),
    @SQL        varchar(max)

  CREATE TABLE #result (
    tc int,
    fp float
  )

  SELECT
    @i          = 0,
    @build      = @build_id,
    @deployname = @deploy

  SET @sql = ''
  SET @sql = @sql + ' INSERT INTO #result'
  SET @sql = @sql + ' SELECT testcase_id, fail_percentage'
  SET @sql = @sql + '   FROM [BuildTestResults].[dbo].['+@deployname+'TestCaseExecution]'
  SET @sql = @sql + '  WHERE build_id = @build and fail_percentage >= 70'

  SP_EXECUTESQL
     @SQL,
     '@build INT',
     @build

  WHILE (@@rowcount = 0)
  BEGIN
    SET @build = @build - 1
     SP_EXECUTESQL
       @SQL,
       '@build INT',
       @build
  END

  SELECT * FROM #result ORDER BY fp DESC

END
GO


我还发现@@rowcount 现在可能会看到SP_EXECUTESQL 中的行正在处理。在这种情况下,您可能需要重新安排一些事情(使用输出参数,或将循环嵌入@SQL 等)。


总体感觉有点笨拙。有了有关您的架构等的更多信息,就有可能避免使用动态 SQL。这将有几个好处,但特别是一个:
- 现在你对@deploy 参数的 SQL 注入攻击持开放态度

任何可以执行此 SP 和/或控制 @deploy 参数中的值的人都可能对您的数据库造成严重破坏。


例如...您可以将所有 TestCaseExecutions 存储在同一个表中吗?但是有一个额外的字段:TestCaseID *(甚至是TestCaseName)?

那么您就不需要构建动态 SQL 来控制您正在处理的数据集。相反,您只需将 WHERE TestCaseID = @TestCaseID 添加到您的查询中...

【讨论】:

    【解决方案2】:

    在你的字符串中有@build - 这被解释为一个字符串。在您执行 @SQL 时,它不包含这样的变量,因此您会失败。

    你需要直接连接

    SET @SQL = 'insert '+@result+'select testcase_id, fail_percentage FROM [BuildTestResults].[dbo].['+@deployname+'TestCaseExecution]
                       where build_id = '+@build+' and fail_percentage >= 70'
    

    您也需要在两次执行之间执行此操作。

    【讨论】:

    • 你好,这个我忘了,但是result和deployname还是有问题。
    • @Artur - 它们将是类似的问题。您能否解释一下(在您的问题中),您究竟想要达到什么目标?不要向我们提供您的解决方案(这可能是不合适的),而是说明您遇到的问题以及应该解决的问题 - 我们可能会建议一种不同的更好的方法。
    • 是的,当然,所以问题如下 - 我有一个用 C# 编写的应用程序,它连接到数据库并分析其数据,数据库存储有关执行自动化测试的信息,我想做什么是检索那些满足上述给定条件的测试。但是我们有不同的项目,并且支持的项目越来越多,所以我不想为每个项目构建不同的过程,而是传递名称 - 第二个参数 deploy 作为参数,这样查询将取决于项目并将数据返回到申请,然后我会在报告中发送。
    • @Artur - 请编辑您的问题并在此处添加详细信息。评论不是此信息的好地方。
    猜你喜欢
    • 2017-11-15
    • 2012-06-25
    • 2016-03-08
    • 1970-01-01
    • 2019-02-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多