0

データベースに接続してそのデータを分析する C# で記述されたアプリケーションがあり、データベースには自動テストの実行に関する情報が保存されます。上記の条件を満たすテストを取得したいと考えています。しかし、私たちはさまざまなプロジェクトを持っており、ますますサポートする予定なので、それぞれに異なる手順を作成したくありませんが、名前を渡します-2番目のパラメーター 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

アドバイスをありがとう!

4

2 に答える 2

1

あなたの文字列には@build-これは文字列として解釈されます。実行時にその@SQLような変数が含まれていないため、失敗します。

を直接連結する必要があります。

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

実行の合間にもそれを行う必要があります。

于 2012-04-12T10:54:14.833 に答える
0

あなたの例にはいくつかの問題があります。ただし、これは包括的な考慮事項の 1 つです。

変数 (テーブルおよび/またはスカラー) は、それらが定義されている StoredProcedure でのみ表示さEXEC(@SQL)れます。これは、実行中の動的 SQL からは @result テーブルも他のパラメーターも見えないことを意味します。

テーブルに関しては、代わりに一時テーブルを作成することで回避できます。SP_EXECUTESQLまた、スカラー変数については、代わりにを使用するときにそれらを渡すことができますEXEC

現在、SQLサーバーにアクセスできませんが、このような何かがあなたの出発点になるかもしれません...

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 を回避できる可能性があります。これにはいくつかの利点がありますが、特に 1 つ:
- 現在、@deploy パラメータに対する SQL インジェクション攻撃にさらされています。

この SP を実行したり、@deploy パラメータの値を制御したりできる人は誰でも、データベースに大損害を与える可能性があります。


たとえば... すべての TestCaseExecutions を同じテーブルに格納できますか? ただし、追加のフィールドを使用すると、 TestCaseID*(またはTestCaseName)?

そうすれば、処理するデータ セットを制御するために動的 SQL を構築する必要がなくなります。WHERE TestCaseID = @TestCaseID代わりに、クエリに追加するだけです...

于 2012-04-12T11:38:36.607 に答える