4

私はこれで炎上するつもりだと知っていますが....

テーブル ProductA、ProductB、および ProductC があり、スキーマは非常に似ていますが、それぞれに 2 つまたは 3 つの列があります。各テーブルには、すべての製品の統合である製品テーブルへの A、B、または C の各挿入に対して重複する行を起動する挿入トリガーがあります。さらに、A、B、または C の更新トリガーは、削除トリガーと同様に、Table Products の対応する行を同様に更新します。テーブル A、B、および C にも存在するテーブル製品列 A を更新するまで、すべて問題なく動作します。

テーブル A、B、および C の更新トリガーを呼び出さずに、列 A の更新を各テーブル A、B、および C の列 A に伝播するテーブル製品のトリガーを開発しようとしています。望ましい動作は、更新が無限ループを発生させずに両方向で機能することです。

オプションは次のとおりです。

  1. この状況が存在しないようにスキーマを再設計します (カードにはありません。これは簡単な解決策です。再設計は他の人が行うことができます)。
  2. テーブル製品を更新するときにトリガーを手動で無効にします (これはすべてアプリケーション レベルで行われます。ユーザーは、テーブル製品を更新するときに SSMA にログインしてトリガーを無効にすることはできません)。
  3. Stack Overflow に来て、誰かがこの種の問題に既に遭遇していることを願っています!

概念的には、これをどのように行うことができますか?

6/7 更新:

表Aのトリガーコードは次のとおりです(例):

    ALTER TRIGGER   [dbo].[GRSM_WETLANDS_Point_GIS_tbl_locations_update]
    ON  [dbo].[GRSM_WETLANDS_POINT]
    after update  
    AS   
    BEGIN   
      SET NOCOUNT ON;  

      update dbo.TBL_LOCATIONS
      set 
    X_Coord = i.X_Coord,
    Y_Coord = i.Y_Coord,
    PlaceName = i.PlaceName,
    FCSubtype = case
    when i.FCSubtype = 1 then 'Point: Too Small to Determin Boundary'
    when i.FCSubtype = 2 then 'Point: Boundary Determined by Contractor but not Surveyed' 
    when i.FCSubtype = 3 then 'Point: Wetland Reported but not yet Surveyed'
    end ,
    Landform = i.Landform

    from dbo.TBL_LOCATIONS
    Join inserted i
    on TBL_LOCATIONS.GIS_Location_ID = i.GIS_Location_ID
      end



GO

ALTER TRIGGER [dbo].[GRSM_WETLANDS_POINT_GIS_tbl_locations]
ON

[dbo].[GRSM_WETLANDS_POINT]
after INSERT
AS
BEGIN
SET NOCOUNT ON; 
INSERT dbo.TBL_LOCATIONS(
X_Coord, Y_Coord, 
PlaceName, 
FCSubtype, Landform
)

SELECT 
a.X_Coord, a.Y_Coord, 
a.PlaceName, 
a.FCSubtype, a.Landform

From
( 
SELECT 
X_Coord, Y_Coord, 
PlaceName, 
FCSubtype = case
when FCSubtype = 1 then 'Point: Too Small to Determin Boundary'
when FCSubtype = 2 then 'Point: Boundary Determined by Contractor but not Surveyed' 
when FCSubtype = 3 then 'Point: Wetland Reported but not yet Surveyed'
end , 
Landform

FROM inserted 
) AS a 

end

GO

また、テーブル製品で現在無効になっている更新トリガーは次のとおりです。

ALTER TRIGGER   [dbo].[tbl_locations_updateto_geo]
ON  [dbo].[TBL_LOCATIONS]
for update  
AS   

BEGIN 
--IF @@NESTLEVEL>1 RETURN  
  SET NOCOUNT ON;  
  update dbo.GRSM_Wetlands_Point 
  set 
X_Coord = i.X_Coord,
Y_Coord = i.Y_Coord,
PlaceName = i.PlaceName,
FCSubtype = i.FCSubtype,
Landform = i.Landform,
from dbo.TBL_LOCATIONS
Join inserted i
on TBL_LOCATIONS.GIS_Location_ID = i.GIS_Location_ID
where TBL_LOCATIONS.FCSubtype =  'Polygon: Determination Made by GPS Survey'
or TBL_LOCATIONS.FCSubtype =  'Polygon: Determination Derived from NWI' 
 or TBL_LOCATIONS.FCSubtype =  'Polygon: Determination Made by Other Means'
  or TBL_LOCATIONS.FCSubtype =  'Polygon: Legal Jurisdictional Determination';
  end
GO

(tbl の名前は、投稿テキストに合わせて変更されました)

4

1 に答える 1

5

再帰には、直接と間接の 2 種類があります: http://msdn.microsoft.com/en-us/library/ms190739.aspx

RECURSIVE_TRIGGERS オプションを使用して直接再帰を停止できますが、ケースは間接再帰であるため、ネストされたトリガー オプションを設定する必要があります。これで問題は解決しますが、システム内の他の何かが再帰に依存している場合、それは良い選択肢ではありません。

USE DatabaseName
GO
EXEC sp_configure 'show advanced options', 1
GO
RECONFIGURE
GO
EXEC sp_configure 'nested triggers', 0
GO
RECONFIGURE
GO

更新された投稿に応じて編集します。

あなたは最終的に本当にくだらないデザインを採用してそれを拡張しているので、私はあなたにこの解決策を提供することをほとんど嫌います. 正直なところ、2 つのテーブル間で同期する必要がある値を保持する別のテーブルを作成して、データが 1 か所だけになるようにし、それらのテーブルをキーを介してそのテーブルに関連付ける必要があります。しかし、それにもかかわらず...

一方のトリガーで更新していることを設定するには、フラグが必要です。これにより、もう一方のトリガーは、それが真であると判断した場合にその操作を中止できます。(私が知る限り)ローカルスコープの変数しか持てないため、このフラグ値を格納して検索するためのテーブルが必要になることを意味します。

このソリューションはさまざまなレベルの複雑さで実装できますが、最も簡単な方法は、開始時にすべてのトリガーのフラグを true に設定し、終了時に false に設定することです。そして、開始する前にフラグをチェックし、それが true の場合は実行を停止します。

これに関する問題は、同時に発生するトリガーに関連しない別の更新が存在する可能性があり、次のテーブルに反映されないことです。あなたがこの道を進みたいのなら、その問題を解決する方法を見つけるのはあなたに任せます。

于 2012-06-02T20:03:44.517 に答える