0

2 つのテーブルを作成しました。1 つ目は magzine のテーブルです。

CREATE TABLE [dbo].[Magzine](
[ID] [int] IDENTITY(1,1) NOT NULL,
[Name] [nvarchar](350) NULL,
[MagzineType] [int] NOT NULL,
[TotalPages] [int] NOT NULL,
[DateCreated] [datetime] NOT NULL,
[Active] [bit] NOT NULL, CONSTRAINT [PK_tblMagzine] PRIMARY KEY CLUSTERED (
[ID] ASC)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]) ON [PRIMARY] GO

マガジン内の総ページ数を保持する列名 TotalPages を持っています

ここに MagzinePage テーブルがあります。

CREATE TABLE [dbo].[MagzinePage](
[ID] [int] IDENTITY(1,1) NOT NULL,
[MagzineID] [int] NOT NULL,
[Title] [nvarchar](255) NULL,
[SubTitle] [nvarchar](255) NULL,
[Photo] [nvarchar](255) NULL,
[Description] [nvarchar](2000) NULL,
[DateCreated] [datetime] NOT NULL,
[CreatedBy] [nvarchar](25) NOT NULL,
[Active] [bit] NOT NULL,
[IsMapped] [bit] NULL, CONSTRAINT [PK_tblPage] PRIMARY KEY CLUSTERED (
[ID] ASC)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]) ON [PRIMARY] GO

magzinePage テーブルにデータを挿入するトリガーを作成しました。これは、テーブルに挿入されたレコードの総数を ID に対して処理できるトリガーです。

Alter TRIGGER trgAfterInsert ON [dbo].[MagzinePage] 
    FOR INSERT

    AS
    Declare @MagzineID int;
    Declare @TotalPages int;
    Set @MagzineID= (Select Top 1 MagzineID From MagzinePage Order By ID Desc)
    Set @TotalPages =  (Select Count(MagzineID) from MagzinePage Where MagzineID=@MagzineID Group By MagzinePage.MagzineID) 

        Update Magzine Set TotalPages=@TotalPages Where ID= @MagzineID

        PRINT 'AFTER INSERT trigger fired.'
    GO  

ここで、magzinePage テーブルのレコードが削除されるたびに、Magzine テーブルの合計ページ数を減らすのに役立つトリガーを作成したいと考えています。

そのための方法を見つけてください。ありがとう。

4

2 に答える 2

2

常に最新のカウントを維持するインデックス付きビューを作成できます。

create view dbo.vwMagzinePageCount 
with schemabinding
as
select [MagzineID], count_big(*) as TotalPages
from dbo.[MagzinePage]
group by [MagzineID];
go

create unique clustered index cdxMagzinePageCount 
    on dbo.vwMagzinePageCount (MagzineID);
go

「Magzine」のつづりをそのままにしておきました。これは、多くの観点 (正確性、パフォーマンスなど) からトリガーよりもはるかに優れています。エンジンは、すべての操作でこのカウントを最新の状態に維持します。Magzine テーブルから TotalPages 列を削除します。

于 2012-06-28T10:40:48.053 に答える
2

なんらかの理由でカウントを保存する必要がある場合、SQL Server に作業を任せることを考えたことはありますか? 最初のテーブルから削除TotalPagesし、このビューを定義すると:

CREATE VIEW dbo.MagzineWithPages
WITH SCHEMABINDING
AS
    select m.ID,Name,MagzineType,COUNT_BIG(*) as TotalPages,m.DateCreated,m.Active
    from
        dbo.Magzine m
            inner join
        dbo.MagzinePage mp
            on
                m.ID = mp.MagzineID
    group by
        m.ID,Name,MagzineType,m.DateCreated,m.Active
GO
CREATE UNIQUE CLUSTERED INDEX IX_MagzineWithPages on MagzineWithPages (ID)

その後、COUNT()ページ行が追加および削除されると、 が自動的に更新されます。Activeこれには、たとえばが 0 のページを無視するなど、この定義を更新したいという利点もあります。


トリガー壊れている理由 - 次のように INSERT を実行します。

INSERT INTO [dbo].[MagzinePage]([MagzineID],[DateCreated],[CreatedBy],[Active]) VALUES
(1,CURRENT_TIMESTAMP,'Me',1),
(2,CURRENT_TIMESTAMP,'Me also',1)

そのTOP 1 MagzineIDテーブルの は、 または のいずれ1かになります2。それらの 1 つの更新を実行し、他の 1 つを逃します。


本当に元のテーブルに保持したい場合(あなたがしつこい場合は、それを強くお勧めします):

CREATE TRIGGER T_MagzinePage on dbo.MagzinePage
AFTER INSERT,UPDATE,DELETE
AS

SET NOCOUNT ON

;with Deltas as (
    select MagzineID,COUNT(*) as Cnt,0 as Del from inserted group by MagzineID
    union all
    select MagzineID,COUNT(*),1 from deleted group by MagzineID
), Merged as (
    select MagzineID,SUM(CASE WHEN Del=0 then Cnt ELSE -Cnt END) as Net
)
update m set TotalPages = TotalPages + Net
from Magzine m
inner join
Merged mm
on
    m.MagzineID = mm.MagzineID

単一のトリガーとして実行し(既存のトリガーを破棄)、挿入内の複数の行、更新の変更MagzineID、およびその他の多くの問題に適切に対処する必要があります。

于 2012-06-28T10:42:10.787 に答える