4

裏話

プライマリテーブルの1つでNaturalKey列を廃止することを計画している職場で。プロジェクトは、このテーブル/列にリンクする100以上のアプリケーションで構成されています。この列を直接参照する400以上のストアドプロシージャ。また、この列を参照する、これらのアプリケーション間の膨大な数の共通テーブル。

BigBangとStartfromScratchの方法は理解できません。このコラムを一度に1つのアプリケーションで非推奨にし、変更を認証して、次の列に進みます...そして、この取り組みを実用化するための長い目標があります。

私が抱えている問題は、これらのアプリケーションの多くがストアドプロシージャとテーブルを共有していることです。アプリケーションAのすべてのテーブル/ストアドプロシージャを完全に変換すると、アプリケーションBとCは変換されるまで壊れます。これらは順番にアプリケーションD、E、F...Etcを壊す可能性があります。私はすでにコードクラスとストアドプロシージャのために実装された戦略を持っています、私が立ち往生している部分はデータベースの遷移状態です。

これが私たちが持っているものの基本的な例です:

Users
---------------------------
Code          varchar(32) natural key

Access
---------------------------
UserCode      varchar(32) foreign key
AccessLevel   int

そして、私たちは今、このような移行状態を目指しています:

Users
---------------------------
Code          varchar(32) 
Id            int         surrogate key

Access
---------------------------
UserCode      varchar(32)   
UserID        int         foreign key      
AccessLevel   int

移行フェーズでは、移行されていないアプリケーションとストアドプロシージャは引き続きすべての適切なデータにアクセスでき、新しいデータは正しい列にプッシュを開始できます。すべてのストアドプロシージャとアプリケーションの移行が完了すると、最終的に余分な列を削除します。

SQL Serverのトリガーを使用して、新しい挿入/更新を自動的にインターセプトし、影響を受ける各テーブルに対して次のようなことを実行したいと思いました。

CREATE TRIGGER tr_Access_Sync
ON Access
INSTEAD OF INSERT(, UPDATE)
AS
BEGIN
  DIM @code as Varchar(32)
  DIM @id as int

  SET @code = (SELECT inserted.code FROM inserted)
  SET @id = (SELECT inserted.code FROM inserted)

  -- This is a migrated application; find the appropriate legacy key
  IF @code IS NULL AND @id IS NOT NULL
     SELECT Code FROM Users WHERE Users.id = @id

  -- This is a legacy application; find the appropriate surrogate key
  IF @id IS NULL AND @code IS NOT NULL
     SELECT Code FROM Users WHERE Users.id = @id

  -- Impossible code:
  UPDATE inserted SET inserted.code=@code, inserted.id=@id
END

質問

私がこれまでに抱えている2つの大きな問題は次のとおりです。

  1. NULL制約により挿入が失敗するため、「AFTERINSERT」を実行できません。
  2. 私が言及した「不可能なコード」は、元のクエリをきれいにプロキシしたい方法です。元のクエリにx、y、z列が含まれている場合、またはxだけの場合、理想的には同じトリガーでこれらを実行します。また、別の列を追加/削除する場合は、トリガーを機能させたままにします。

これが可能なコード例、または値の1つだけがSQLに渡された場合でもこれらの列を適切に入力し続けるための代替ソリューションさえありますか?

4

3 に答える 3

2

トリッキーなビジネス...

OK、まず第一に:このトリガーは多くの状況では機能しません:

SET @code = (SELECT inserted.code FROM inserted)
SET @id = (SELECT inserted.code FROM inserted)

トリガーは、疑似テーブルの一連の行を使用して呼び出すことができます。Insertedここでどちらを選択しますか?テーブルに10行ある場合でもトリガーが機能するように、トリガーを作成する必要がありInsertedます。SQLステートメントが10行を挿入する場合、トリガーは10回(各行に1回)起動されませんが、バッチ全体で1回だけ起動されます。これを考慮する必要があります。

2番目のポイント:IDのフィールドを作成しようとすると、IDENTITY「レガシー」アプリの場合でも、常に値が取得されます。これらの「古い」アプリは、代わりにレガシーキーを提供する必要があります。そのため、問題はありません。私が見て、それらをどのように処理するかわからない唯一の問題は、すでに変換されたアプリからの挿入です-それらは「古いスタイル」のレガシーキーも提供しますか?そうでない場合-そのようなキーをどれくらい早く持っている必要がありますか?

私が考えているのは、テーブル上で実行され、NULLのレガシーキーを使用してすべての行を取得し、それに意味のある値を提供する「クリーンアップジョブ」です。これを通常のストアドプロシージャにして、毎日、4時間、30分など、ニーズに合ったものを実行します。そうすれば、トリガーとそれらが持つすべての制限に対処する必要はありません。

于 2010-10-15T05:26:34.280 に答える
1

スキーマを「bigbang」に変更することはできませんが、変更を「隠す」テーブルの上にビューを作成することはできませんか?

「このコラムは一度に1つのアプリケーションで非推奨にする」という、後の時点での破損を単に延期していることに気付くかもしれません。これは私の素朴なことかもしれませんが、それがどのように進んでいるかはわかりません。働くために。

確かに、さまざまなアプリケーションがさまざまなことをしていると、さらに悪い混乱が発生する可能性がありますか?

于 2010-10-14T23:44:00.310 に答える
1

問題について眠った後、これは私がSQL構文内で思いついた最も一般的で再利用可能な解決策のようです。挿入で「その他」の列をまったく参照していなくても、両方の列にNOTNULL制限がある場合でも正常に機能します。

CREATE TRIGGER tr_Access_Sync
ON Access
INSTEAD OF INSERT
AS 
BEGIN

    /*-- Create a temporary table to modify because "inserted" is read-only */
    /*-- "temp" is actually "#temp" but it throws off stackoverflow's syntax highlighting */
    SELECT * INTO temp FROM inserted

    /*-- If for whatever reason the secondary table has it's own identity column */
    /*-- we need to get rid of it from our #temp table to do an Insert later with identities on */
    ALTER TABLE temp DROP COLUMN oneToManyIdentity

    UPDATE temp 
    SET 
        UserCode = ISNULL(UserCode, (SELECT UserCode FROM Users U WHERE U.UserID = temp.UserID)),
        UserID = ISNULL(UserID, (SELECT UserID FROM Users U WHERE U.UserCode = temp.UserCode))

    INSERT INTO Access SELECT * FROM temp

END
于 2010-10-15T13:16:57.293 に答える