2017-10-06 9 views
0

すべての変更(挿入、更新、削除)を保持するテーブルにトリガがあります。私は1つの時間当たり1行だけを挿入すると問題なく動作します。しかし、複数の行を一度に挿入しようとすると、次のエラーが表示されます。SQL Server 2012トリガ:行ごとに動的SQLを実行

サブクエリが2つ以上の値を返しました。 サブクエリが、=、!<、< =、>、> =、またはサブクエリが式 として使用されている場合は、これは許可されません。

ここトリガーのコード(I等変数宣言のようなコードを短くするために必要とされていないいくつかの部分を除去)

UPDATEである:実際のエラーは、これらの行にあるが#tempTrigTには複数の行が含まれています:

Select * into #tempTrigT from (select * from deleted where @Action in ('U','D')) A UNION (select * from inserted where @Action ='I') 

    set @sql = 'set @audit_oldvalue=(select cast([' [email protected] +'] as NVARCHAR(4000)) from #tempTrigT)'; 
    EXEC SP_EXECUTESQL @sql,N'@audit_oldvalue sql_variant OUTPUT',@audit_oldvalue OUTPUT -- If inserted @audit_oldvalue gets the new value 

    set @sql = 'set @audit_value=(select cast(i.[' [email protected] +'] as NVARCHAR(4000)) from dbo.TForms i inner join #tempTrigT d on i.id = d.id)'; 
    EXEC SP_EXECUTESQL @sql,N'@audit_value sql_variant OUTPUT',@audit_value OUTPUT 

どのように複数の行でも動作するように変更できますか?

+0

です。このエラーが発生した場合は、 '='を使ってサブクエリを探してください。次の2つがあります。 'set @ audit_oldvalue =(#tempTrigTからのキャスト(NVARCHAR(4000)としての '' + @ Item + ')とその下の次の' set'操作です。どちらも私に複数の価値を引き出すように見えます。 –

+0

@AaronDietzしかし、私はこのエラーを受け取ってはいけません...そうですか? – aggicd

+0

'=(サブクエリ)'を使用し、そのサブクエリが複数の値を返す場合、エラー –

答えて

2

行識別子がないため、ループごとに1つの行しか処理できません。そのidがの処理が完了したとき、あなたのループの最後でループ

  • DELETE FROM #tempTrigT WHERE id = @ID全体でこの行をフィルタリングするために、あなたのループ
  • WHERE id = @IDの開始時に列を定義するための

    • DECLARE @ID int = (SELECT MIN(id) FROM #tempTrigT):ような何か

    さらに、id#tempTrigTで繰り返すことができます。

    そして言ったすべてと

    ...

    私は間違いなく、複数のトリガにこれを分離を検討し、削除または挿入されたレコードをループするために試みることによって自分自身にあなたが直面している複雑さを保存し、それに応じてそれらをすべて処理します。また、監査プロセスの簡素化も検討します。最終目標は、あなたが本当に簡単に実現することができ、レコードがあることを使用したもので振り返ることができるようにすることです:

    INSERT INTO [dbo].[AuditTrailTForms] (TForms_Cols, ChangeDate, Change_User, Change_Type) 
        SELECT T.*, GETDATE(), COALESCE(ModifiedBy,suser_name()), 'Inserted' 
        FROM inserted i 
        JOIN TForms T on i.id = T.id 
    

    次に、あなたはそれが簡単に値を照会するときに、後で変更どの列を表示することを心配することができますこれらのテーブル:

    SELECT * 
    FROM (SELECT *, GETDATE(), 'Current', 'Current' 
         FROM TForms 
         WHERE ID = @AuditID 
         UNION ALL 
         SELECT * 
         FROM AuditTrailTForms 
         WHERE ID = @AuditID 
         --AND Change_Type = 
         --AND Change_User = 
        ) T 
    ORDER BY ChangeDate DESC 
    

    編集:あなたがそうのような各ループの行を定義するためにID列を使用することができます

    :ID列を使用して

    DECLARE @TotalRows int = (SELECT MAX(identityColumn) FROM #tempTrigT 
    DECLARE @RowID int = 1 
    WHILE @RowID <= @TotalRows 
        BEGIN 
         --Do stuff 
         --For Example 
          SET @sql = 'set @audit_oldvalue=(SELECT cast([' [email protected] +'] as NVARCHAR(4000)) 
                  FROM #tempTrigT 
                  WHERE T.IdentityColumn = @RowID)'; 
          EXEC SP_EXECUTESQL @sql,N'@audit_oldvalue sql_variant OUTPUT',@audit_oldvalue OUTPUT 
    
         --then increment to the next row when you're done 
         SET @RowID = @RowID + 1 
        END 
    
  • +0

    投稿の最初の部分について。 #tempTrigTテーブルにID列を挿入すると機能しますか? – aggicd

    +0

    @aggicdはい、各ループを1行に制限するものはどれでも動作します –

    +0

    これに基づいて解決策を提供することは可能ですか? ID列を追加しますか? – aggicd

    関連する問題