0

(SQL Server 2014 速成版)

你好,

我参考这篇文章:http: //msdn.microsoft.com/en-gb/magazine/cc164047.aspx

我有这个 AFTER INSERT、UPDATE、DELETE 触发器来设置或更新几个表中的 DateCreated、DateModified 和 WhoUpdatedID 列(稍后添加删除处理):

CREATE TRIGGER [dbo].[TR_dim_TypeOfClaim_Audit]
    ON [dbo].[dim_TypeOfClaim]
    AFTER INSERT, UPDATE, DELETE
AS
    SET NOCOUNT ON
    DECLARE @event_type [char]

    --Get Event Type
    IF EXISTS(SELECT * FROM inserted)
    IF EXISTS(SELECT * FROM deleted)
        SELECT @event_type = 'U'
    ELSE
        SELECT @event_type = 'I'
    ELSE
    IF EXISTS(SELECT * FROM deleted)
        SELECT @event_type = 'D'
    ELSE
    --no rows affected - cannot determine event
        SELECT @event_type = 'K'

    IF @event_type = 'I' BEGIN
        --Date Created
        UPDATE t
            SET DateCreated = GETDATE()
            FROM INSERTED e
            JOIN [dbo].[dim_TypeOfClaim] t ON e.[TypeOfClaimID] = t.[TypeOfClaimID]
      ;
      SELECT @event_type = 'U' --also do UPDATE processing
    END

    IF @event_type = 'U' BEGIN
        --Date Modified
        UPDATE t
            SET DateModified = GETDATE()
            FROM INSERTED e
            JOIN [dbo].[dim_TypeOfClaim] t ON e.[TypeOfClaimID] = t.[TypeOfClaimID]

        --WhoModifiedID
        UPDATE t
            SET WhoModifiedID = u.UserID
            FROM INSERTED e
            JOIN [dbo].[dim_TypeOfClaim] t ON e.[TypeOfClaimID] = t.[TypeOfClaimID]
            JOIN [dbo].[dim_Users] u ON u.[Username] = dbo.udfUserName()
    END

    IF @event_type = 'D' BEGIN
        no_op:  --Nothing for now
    END
GO

DateCreated、DateModified 和 WhoUpdatedID 的完整性规则不为 NULL。这在技术上是正确的,但最终用户永远不会输入。这会在添加新记录时导致错误。

我应该将这些列更改为允许的 NULL,还是将触发器更改为 INSTEAD?我不确定这里的最佳做法。

如果这很重要,我打算稍后通过触发器或更改跟踪对所有数据更改进行全面审核(我需要阅读更改跟踪以查看它是否满足我的需求)。

谢谢您的帮助...

更新:

@Bogdan:对不起,我的评论不清楚。根据到目前为止每个人的反馈,这是我目前拥有的:

1) 我将 DateCreated、DateModified 和 WhoModifiedID 保留为 NOT NULL

2) 我分别创建了默认值 getdate()、getdate() 和 0。所有值都只是为了通过新记录的 NOT NULL 约束。我想有人可能会争辩说,使用触发器,NOT NULL 约束是多余的——触发器将确保这些值无论如何都不是 NULL。在这方面我有点不清楚什么是最佳实践。但我不希望这些列永远为 NULL,并且约束使这一点显而易见。

3)我现在的触发器是:

ALTER TRIGGER [dbo].[TR_dim_InjuryType_Audit]
    ON [dbo].[dim_InjuryType]
    AFTER INSERT, UPDATE
AS
    SET NOCOUNT ON

    DECLARE @CurrentUserID INT;
    SELECT  @CurrentUserID = u.UserID 
    FROM    [dbo].[dim_Users] U
    WHERE   u.[Username] = dbo.udfUserName()

    UPDATE  T
    SET     DateModified = GETDATE(),
          WhoModifiedID = @CurrentUserID
  FROM    INSERTED E
    JOIN    [dbo].[dim_InjuryType] T ON e.[InjuryTypeID] = t.[InjuryTypeID]

4)顺便说一句, dbo.udfUserName() 仅仅是:

-- =============================================
-- Author:      Scott Bass
-- Create date: 04JUL2014
-- Description: Return userid without the domain
-- =============================================
ALTER FUNCTION [dbo].[udfUserName]
(
)
RETURNS varchar(20)
AS
BEGIN
    -- Declare the return variable here
    DECLARE @UserName varchar(20)

    -- Add the T-SQL statements to compute the return value here
    SELECT @UserName = substring(suser_sname(),charindex('\',suser_sname())+1,99)

    -- Return the result of the function
    RETURN @UserName
END  

5)感谢提示:不在 SSMS 中使用 EDIT TOP 200 ROWS

这是我想要的。对改进/最佳实践的进一步评论非常受欢迎,另外将帮助那些以后找到这个线程的人。

我的 Access 前端很烦人,这可能与触发器有关,但实际上是单独帖子的单独主题。但是,为了完整性,我包含此链接,以防有人感兴趣: http ://www.utteraccess.com/forum/User-Edited-Record-Sav-t2019558.html

4

2 回答 2

1

我会使用/我使用过以下解决方案(1)2.1)):

1)DateCreated是强制性的:NOT NULL加上一个默认约束使用GETDATE()

ALTER TABLE [dbo].[dim_TypeOfClaim]
ADD CONSTRAINT DF_dim_TypeOfClaim_DateCreated DEFAULT (GETDATE()) FOR DateCreated

DateCreatedusing设置GETDATE()为默认值(就性能而言)比使用AFTER INSERT带有UPDATE ... SET DateCreated = GETDATE() ....

2.1)DateModified并且WhoModifiedID应该NULL能够并且如果您使用[仅]存储过程到UPDATE行,[dbo].[dim_TypeOfClaim]那么我将更改这些过程以更新DateModified以及和WhoModifiedID列。这样,您可以删除此AFTER UPDATE触发器。这种方法的缺点是,如果有人运行一个临时脚本,UPDATEdim_TypeOfClaim 行很容易忘记更新 ,alsoDateModifiedWhoModifiedID列。

或者

2.2)DateModified并且WhoModifiedID应该NULL能够加上一个AFTER UPDATE触发器:

-- tr = trigger, U = INSERT only trigger
ALTER TRIGGER [dbo].[trU_dim_TypeOfClaim_Audit] 
    ON [dbo].[dim_TypeOfClaim]
    -- This trigger should be activated only by UPDATE statements (or MERGE ... UPDATE SET ...)
    -- This trigger shouldn't be activated by INSERT or DELETE statements
    AFTER UPDATE 
AS
BEGIN
    DECLARE @CurrentUserID INT;
    SELECT @CurrentUserID = u.UserID 
    FROM   [dbo].[dim_Users] u 
    WHERE  u.[Username] = @CurrentUserName;

    UPDATE  t
    SET     DateModified = GETDATE(),
            WhoModifiedID = @CurrentUserID
    FROM    INSERTED e
    JOIN    [dbo].[dim_TypeOfClaim] t ON e.[TypeOfClaimID] = t.[TypeOfClaimID]

END
于 2014-07-05T14:28:44.237 回答
0

(对我来说)将DateModifedandWhoUpdatedID作为 NOT NULL 是没有意义的,因为在插入记录时它们将始终为 NULL。

在我看来,onlyDateCreated应该是 NOT NULL,它应该由数据库设置,无论是触发器还是存储过程。

于 2014-07-05T09:15:09.193 回答