4

テーブルの 1 つに監査トリガーを実装しました。基本的には、古いレコードと新しいレコードを ..._Audit という名前のテーブルに、日付とユーザーと共にコピーします。スクリプトをさらに下に投稿します。

問題は、Access に新しいレコードを挿入してからタブを移動すると、更新されてテーブルの最初のレコードが表示されることです。この例を以下に示します - 最初の 3 つのレコードを追加してから更新し、まったく同じデータをさらに 3 つ追加しました。それらを追加した後、同じデータとインクリメントされた ID を持つレコードが表示されるはずですが、代わりに最初のレコードを取得しています。最後の 3 つのレコードのテーブルの 3 つのレコード。

 P_SubtaskID  PresetID_FK P_SubtaskName            DateDay DateMonth
 148          17          a new subtask            1       7
 149          17          a new subtask            1       7
 150          17          a new subtask            1       7
 8            5           Receive, sign and save   25      10
 9            5           Electronic lodgement     30      10
 10           1           Review                   12      7

更新を押すと、これらのレコードは本来あるべきものを示します。

 P_SubtaskID  PresetID_FK P_SubtaskName            DateDay DateMonth
 148          17          a new subtask            1       7
 149          17          a new subtask            1       7
 150          17          a new subtask            1       7
 151          17          a new subtask            25      10
 152          17          a new subtask            30      10
 153          17          a new subtask            12      7

ユーザーがレコードを追加して保存すると、まったく関係のないレコードが表示されるため、これは問題です。彼らがこの出現に変更を加えた場合、その記録に影響を与えます - これは、記録の誤った更新/削除などに簡単につながります。良くありません!

したがって、監査テーブルとそれに関連するトリガーを作成するスクリプトは次のとおりです。

USE [ClientDatabase]
 GO

 SET ANSI_NULLS ON
 GO
 SET QUOTED_IDENTIFIER ON
 GO

 DROP TABLE [dbo].[AutoTaskPresets_Subtasks_Audit]
 GO

 CREATE TABLE [dbo].[AutoTaskPresets_Subtasks_Audit](
    SessionID int identity(1,1) not null,
    [P_SubtaskID] [int] NULL,
    [PresetID_FK] [int] NULL,
    [P_SubtaskName] [nvarchar](255) NULL,
    [DateDay] [int] NULL,
    [DateMonth] [int] NULL,
    [DatePeriod] [int] NULL,
    [StaffName_FK] [nvarchar](255) NOT NULL,
    Action nchar(10) null,
    RowType nchar(10) null,
    ChangedDate datetime not null default getdate(),
    ChangedBy sysname not null default user_name()
 )
 GO

 CREATE Trigger [dbo].[DeleteAutoTaskPresets_Subtasks] ON [dbo].
     [AutoTaskPresets_Subtasks] FOR DELETE AS  

 BEGIN  
     SET NOCOUNT ON
     INSERT dbo.AutoTaskPresets_Subtasks_Audit(
        [P_SubtaskID],
        [PresetID_FK],
        [P_SubtaskName],
        [DateDay],
        [DateMonth],
        [DatePeriod],
        [StaffName_FK],
        Action,
        RowType)
     SELECT
        [P_SubtaskID],
        [PresetID_FK],
        [P_SubtaskName],
        [DateDay],
        [DateMonth],
        [DatePeriod],
        [StaffName_FK],
        'Deleted',
        'Old'
    FROM Deleted
 END
 GO

 CREATE Trigger [dbo].[InsertAutoTaskPresets_Subtasks]
    ON [dbo].[AutoTaskPresets_Subtasks] FOR INSERT AS  
 BEGIN  
     SET NOCOUNT ON
     INSERT dbo.AutoTaskPresets_Subtasks_Audit(
        [P_SubtaskID],
        [PresetID_FK],
        [P_SubtaskName],
    [DateDay],
        [DateMonth],
        [DatePeriod],
        [StaffName_FK],
        Action,
        RowType)
     SELECT
        [P_SubtaskID],
        [PresetID_FK],
        [P_SubtaskName],
        [DateDay],
        [DateMonth],
        [DatePeriod],
        [StaffName_FK],
        'Inserted',
        'New'
    FROM Inserted

 END
 GO

 CREATE Trigger [dbo].[UpdateAutoTaskPresets_Subtasks]
ON [dbo].[AutoTaskPresets_Subtasks] FOR UPDATE AS  
 BEGIN  
     SET NOCOUNT ON
     INSERT dbo.AutoTaskPresets_Subtasks_Audit(
        [P_SubtaskID],
    [PresetID_FK],
    [P_SubtaskName],
    [DateDay],
    [DateMonth],
    [DatePeriod],
    [StaffName_FK],
    [Action],
    RowType)
     SELECT
    [P_SubtaskID],
    [PresetID_FK],
    [P_SubtaskName],
    [DateDay],
    [DateMonth],
    [DatePeriod],
    [StaffName_FK],
    'Updated',
    'Old'
 FROM Deleted

     INSERT dbo.AutoTAskPresets_Subtasks_Audit(
    [P_SubtaskID],
    [PresetID_FK],
    [P_SubtaskName],
    [DateDay],
    [DateMonth],
    [DatePeriod],
    [StaffName_FK],
    [Action],
    RowType)
     SELECT
    [P_SubtaskID],
    [PresetID_FK],
    [P_SubtaskName],
    [DateDay],
    [DateMonth],
    [DatePeriod],
    [StaffName_FK],
    'Updated',
    'New'
FROM Inserted

 END
 GO

なぜこれが起こっているのか、私はかなり困惑しています。私が考えることができるのは、おそらくタイミングの問題だけですが、現在、トリガーは、私が好むアクションの後に実行されます。

それらを削除すると正常に機能するので、それが私のトリガーであると確信しています。私のデータベースも、このようなエラーを示したことはありません。

MS Access 2007 クライアントへの ODBC 接続で SQL Server 2005 を使用しています。

4

1 に答える 1

4

Nikola が説明したように、この問題は @@identity の使用に関連しています。これは最後のレコード エントリの ID 値を取得するため、挿入を行うと、トリガーは別のテーブルへの挿入を行います。これは、MS Access が誤って依存しているように見える @@identity の異なる値につながります。これを修正するには、トリガーを実行する前に @@identity 値を保存してから、元に戻す必要がありました。Insert トリガーの場合は次のようになります。

 CREATE Trigger [dbo].[InsertAutoTaskPresets_Subtasks]
    ON [dbo].[AutoTaskPresets_Subtasks] FOR INSERT AS  
 BEGIN  
     SET NOCOUNT ON

     declare @id int
     set @id = @@identity

     INSERT dbo.AutoTaskPresets_Subtasks_Audit(
        [P_SubtaskID],
        [PresetID_FK],
        [P_SubtaskName],
    [DateDay],
        [DateMonth],
        [DatePeriod],
        [StaffName_FK],
        Action,
        RowType)
     SELECT
        [P_SubtaskID],
        [PresetID_FK],
        [P_SubtaskName],
        [DateDay],
        [DateMonth],
        [DatePeriod],
        [StaffName_FK],
        'Inserted',
        'New'
    FROM Inserted

DECLARE @SQL varchar(8000)
SET @sql = 'SELECT IDENTITY(INT, ' + CAST(@id as varchar) + ', 1)
         AS ident INTO #Tmp'
EXEC(@sql)

 END
 GO

Access が 100% 正確ではないものに依存して、このように構築されているように見えるのは残念です。

最終的に、他のトリガーは挿入操作を使用しますが、これを挿入トリガーにのみ実装しました。いくつかの簡単なテストの後、これは問題ないように見えました。一般ユーザーが編集できるすべてのテーブルにこのスクリプトを展開したので、これが問題を引き起こしているかどうかはすぐにわかります。

于 2013-01-17T02:05:58.707 に答える