web-dev-qa-db-ja.com

SQL Server更新トリガー:機能させる方法

「ブロックバスターのような」映画会社のSQLサーバー更新トリガーを記述しようとしています。私のMOVIESテーブルには、PKとしてmovie_idがあり、映画がレンタルされた回数の合計を保持するnum_rentedという別の列があります。この合計は、挿入、削除、および更新トリガーを介して行われます。 (これを行うにははるかに良い方法があることを理解していますが、私の割り当てでは特にこれを求めているので、この点を理解してください)。 MOVIESのPKおよびmovie_idはFKであるため、CUSTOMER_RENTALSテーブルにはitem_rental_idがあります。

CUSTOMER_RENTALSが更新されるたびに、MOVIESのnum_rentals列を更新する更新トリガーが必要です。たとえば、movie_id 1が入力されたが、それはエラーで実際はmovie_id 2だったとします。num_rentalsに更新を反映させます。

これが私がこれまで持ってきたものですが、これを実現するためにSET部分に何を入れるべきか本当にわかりません:

CREATE TRIGGER tr_num_rentals_update
ON customer_rentals
AFTER UPDATE
AS
BEGIN
UPDATE m
SET num_rentals = ??????
FROM movies AS m
INNER JOIN inserted as i on m.movie_id=i.movie_id;
END;

削除されたテーブルの値にアクセスして、num_rental列を以前の値に復元する必要があるのか​​と思っていますが、方法がわかりません。事前に10億に感謝します!

7
Steve

DMLステートメントは複数の行に影響を与える可能性があることを考慮する必要があります(この場合、INSERTEDおよびDELETEDテーブルにも複数の行が含まれます)。

また、映画が別のIDに更新された場合(および新しい映画の数を増やす場合)、映画のレンタル数を減らす必要があることも考慮する必要があります。

以下は、挿入と削除のカウントを統合し、最終的な変更を関連する映画IDに適用します。

CREATE TRIGGER tr_num_rentals_update
ON customer_rentals
AFTER INSERT, UPDATE, DELETE
AS
  BEGIN
      IF UPDATE(movie_id) /*If column not affected skip*/
        BEGIN
            WITH T1(Cnt, movie_id)
                 AS (SELECT COUNT(*),
                            movie_id
                     FROM   inserted
                     GROUP  BY movie_id
                     UNION ALL
                     SELECT -COUNT(*), /*negative for deletes*/
                            movie_id
                     FROM   deleted
                     GROUP  BY movie_id),
                 T2
                 AS (SELECT SUM(Cnt) AS NetCnt,
                            movie_id
                     FROM   T1
                     GROUP  BY movie_id)
            UPDATE m
            SET    num_rentals = num_rentals + NetCnt
            FROM   movies AS m
                   INNER JOIN T2
                     ON m.movie_id = T2.movie_id;
        END
  END; 
10
Martin Smith

私はあなたがm.num_rentals + 1を追加することでこれを達成できると信じています

また、削除されたものの更新ステートメントも追加します

UPDATE M
SET num_rentals = m.numrentals - 1
FROM
Movies M
INNER JOIN Deleted D ON
M.movie_id = D.Movie_ID

ただし、これをトリガーに含める代わりに、アプリケーションがこれを取得するために使用できるビューを作成します。したがって、更新、挿入、削除のたびに実行する必要がある余分なデータ処理を削除する

CREATE VIEW MoviesVW AS
SELECT M.Movie_ID, COUNT(R.*) AS Num_Rental
FROM Movies M
LEFT JOIN customer_rentals R ON
R.movies_id = M.movies_ID
GROUP BY
M.Movie_ID