将INSERT或UPDATE另一个表的SQL Server TRIGGER

时间:2014-01-30 19:11:35

标签: sql-server database tsql sql-server-2005 triggers

我有一个名为Prices的SQL Server表,其中包含数万行数据。遗留应用程序大量使用此表,遗憾的是无法修改此表(无法添加,删除或修改列)。

我的要求是跟踪表的修改时间(INSERT, UPDATE, or DELETE)。但是,Prices表没有LastUpdated列,我无法添加此列。此外,我的触发器必须与SQL Server 2005兼容。

但我可以创建一个额外的表格PricesHistory,该表格会存储PriceIDUpdateTypeLastUpdated列。

我想将SQL TRIGGER附加到Prices表格中,INSERTUPDATE表格中的PricesHistorySELECT一行将跟踪当价格最后一次更新以及哪些操作触发了它。

这是我到目前为止所做的,它将检测哪个操作导致触发器触发。但是,我很难从inserteddeleted表格中INSERT/UPDATE进行操作,并对PricesHistory表做了正确的PriceID

基本上,所有操作都应检查PriceHistory表中是否已存在UPDATEUpdateTypeLastUpdated列中是否PriceID。如果INSERT尚不存在,则应UpdateType以及LastUpdatedinserted值。

编辑:一位同事提醒我注意deletedIF EXISTS ... UPDATE ELSE INSERT INTO项是行而不是表。这意味着我可以做一个简单的CREATE TRIGGER PricesUpdateTrigger ON Prices AFTER INSERT, UPDATE, DELETE AS DECLARE @UpdateType nvarchar(1) DECLARE @UpdatedDT datetime SELECT @UpdatedDT = CURRENT_TIMESTAMP IF EXISTS (SELECT * FROM inserted) IF EXISTS (SELECT * FROM deleted) SELECT @UpdateType = 'U' -- Update Trigger ELSE SELECT @UpdateType = 'I' -- Insert Trigger ELSE IF EXISTS (SELECT * FROM deleted) SELECT @UpdateType = 'D' -- Delete Trigger ELSE SELECT @UpdateType = NULL; -- Unknown Operation IF @UpdateType = 'I' BEGIN -- Log an insertion record END IF @UpdateType = 'U' BEGIN -- Log an update record END IF @UpdateType = 'D' BEGIN -- Log a deletion record END GO 子句。这是真的?我的印象是它将是行的表,而不是单独的行。

{{1}}

2 个答案:

答案 0 :(得分:6)

为什么不是通用审计表?请参阅我的演讲“如何预防和审核变更?”

http://craftydba.com/?page_id=880

这是一个保存要更改的数据的表。

-- 
-- 7 - Auditing data changes (table for DML trigger)
-- 


-- Delete existing table
IF OBJECT_ID('[AUDIT].[LOG_TABLE_CHANGES]') IS NOT NULL 
  DROP TABLE [AUDIT].[LOG_TABLE_CHANGES]
GO


-- Add the table
CREATE TABLE [AUDIT].[LOG_TABLE_CHANGES]
(
  [CHG_ID] [numeric](18, 0) IDENTITY(1,1) NOT NULL,
  [CHG_DATE] [datetime] NOT NULL,
  [CHG_TYPE] [varchar](20) NOT NULL,
  [CHG_BY] [nvarchar](256) NOT NULL,
  [APP_NAME] [nvarchar](128) NOT NULL,
  [HOST_NAME] [nvarchar](128) NOT NULL,
  [SCHEMA_NAME] [sysname] NOT NULL,
  [OBJECT_NAME] [sysname] NOT NULL,
  [XML_RECSET] [xml] NULL,
 CONSTRAINT [PK_LTC_CHG_ID] PRIMARY KEY CLUSTERED ([CHG_ID] ASC)
) ON [PRIMARY]
GO

-- Add defaults for key information
ALTER TABLE [AUDIT].[LOG_TABLE_CHANGES] ADD CONSTRAINT [DF_LTC_CHG_DATE] DEFAULT (getdate()) FOR [CHG_DATE];
ALTER TABLE [AUDIT].[LOG_TABLE_CHANGES] ADD CONSTRAINT [DF_LTC_CHG_TYPE] DEFAULT ('') FOR [CHG_TYPE];
ALTER TABLE [AUDIT].[LOG_TABLE_CHANGES] ADD CONSTRAINT [DF_LTC_CHG_BY] DEFAULT (coalesce(suser_sname(),'?')) FOR [CHG_BY];
ALTER TABLE [AUDIT].[LOG_TABLE_CHANGES] ADD CONSTRAINT [DF_LTC_APP_NAME] DEFAULT (coalesce(app_name(),'?')) FOR [APP_NAME];
ALTER TABLE [AUDIT].[LOG_TABLE_CHANGES] ADD CONSTRAINT [DF_LTC_HOST_NAME] DEFAULT (coalesce(host_name(),'?')) FOR [HOST_NAME];
GO

这是捕获INS,UPD,DEL语句的触发器。

--
--  8 - Make DML trigger to capture changes
--


-- Delete existing trigger
IF OBJECT_ID('[ACTIVE].[TRG_FLUID_DATA]') IS NOT NULL 
  DROP TRIGGER [ACTIVE].[TRG_FLUID_DATA]
GO

-- Add trigger to log all changes
CREATE TRIGGER [ACTIVE].[TRG_FLUID_DATA] ON [ACTIVE].[CARS_BY_COUNTRY]
  FOR INSERT, UPDATE, DELETE AS
BEGIN

  -- Detect inserts
  IF EXISTS (select * from inserted) AND NOT EXISTS (select * from deleted)
  BEGIN
    INSERT [AUDIT].[LOG_TABLE_CHANGES] ([CHG_TYPE], [SCHEMA_NAME], [OBJECT_NAME], [XML_RECSET])
    SELECT 'INSERT', '[ACTIVE]', '[CARS_BY_COUNTRY]', (SELECT * FROM inserted as Record for xml auto, elements , root('RecordSet'), type)
    RETURN;
  END

  -- Detect deletes
  IF EXISTS (select * from deleted) AND NOT EXISTS (select * from inserted)
  BEGIN
    INSERT [AUDIT].[LOG_TABLE_CHANGES] ([CHG_TYPE], [SCHEMA_NAME], [OBJECT_NAME], [XML_RECSET])
    SELECT 'DELETE', '[ACTIVE]', '[CARS_BY_COUNTRY]', (SELECT * FROM deleted as Record for xml auto, elements , root('RecordSet'), type)
    RETURN;
  END

  -- Update inserts
  IF EXISTS (select * from inserted) AND EXISTS (select * from deleted)
  BEGIN
    INSERT [AUDIT].[LOG_TABLE_CHANGES] ([CHG_TYPE], [SCHEMA_NAME], [OBJECT_NAME], [XML_RECSET])
    SELECT 'UPDATE', '[ACTIVE]', '[CARS_BY_COUNTRY]', (SELECT * FROM deleted as Record for xml auto, elements , root('RecordSet'), type)
    RETURN;
  END

END;
GO

如果您对表进行了大量更改,则可以在一个周期中清除数据,或者只是将修改后的日期记录在另一个表中,如您所述。但是,关键信息将丢失。

关于我的解决方案的好处是它告诉你何时以及谁做了改变。实际数据以XML格式保存,如果需要可以恢复。

答案 1 :(得分:1)

我从那里给出的代码你可以得到如何编写单个触发器来处理数据库插入和放大的视图。更新以及如何通过触发器执行审计跟踪。希望这有帮助。

CREATE TRIGGER TRG_HourSheet ON EditedHourSheet 
FOR INSERT, UPDATE
AS                     
   DECLARE @v_xml   XML,
   @PKValue INT,                    
   @type   CHAR(1),
   @v_slno   INT               

BEGIN                    
 SET NOCOUNT ON                    


IF EXISTS(SELECT * FROM INSERTED)
BEGIN
  IF EXISTS(SELECT * FROM DELETED)
  BEGIN
     SET @type ='U';
  END
  ELSE
  BEGIN
    SET @type ='I';
  END
END

IF @type = 'U'
BEGIN   
    DECLARE DB_CURSOR CURSOR FOR                     
    SELECT ID FROM DELETED ORDER BY ModDate DESC                     

    OPEN DB_CURSOR                      
    FETCH NEXT FROM DB_CURSOR INTO @PKValue                      
    WHILE @@FETCH_STATUS = 0                       
    BEGIN                    
    SET  @v_xml =(SELECT * FROM DELETED Where ID=@PKValue          
       FOR xml AUTO, root('Record'),elements XSINIL)                    

    SELECT @v_slno = IsNull(Max(RowID),0)+1 FROM EditedHourSheetLog  
    Where HourSheetID=@PKValue           

    INSERT INTO EditedHourSheetLog(HourSheetID,XMLData,Action,RowID)                    
    values (@PKValue,@v_xml,@type,@v_slno)                    
    FETCH NEXT FROM DB_CURSOR INTO @PKValue                      

    END                    

    CLOSE DB_CURSOR                      
    DEALLOCATE DB_CURSOR                    
    --END 
END 
ELSE IF @type = 'I'
BEGIN   
    DECLARE DB_CURSOR CURSOR FOR                     
    SELECT ID FROM INSERTED ORDER BY ModDate DESC                     

    OPEN DB_CURSOR                      
    FETCH NEXT FROM DB_CURSOR INTO @PKValue                      
    WHILE @@FETCH_STATUS = 0                       
    BEGIN                    
    SET  @v_xml =(SELECT * FROM INSERTED Where ID=@PKValue          
       FOR xml AUTO, root('Record'),elements XSINIL)                    

    SELECT @v_slno = IsNull(Max(RowID),0)+1 FROM EditedHourSheetLog  
    Where HourSheetID=@PKValue           

    INSERT INTO EditedHourSheetLog(HourSheetID,XMLData,Action,RowID)                    
    values (@PKValue,@v_xml,@type,@v_slno)                    
    FETCH NEXT FROM DB_CURSOR INTO @PKValue                      

    END                    

    CLOSE DB_CURSOR                      
    DEALLOCATE DB_CURSOR                    
    --END 
END
END