【问题标题】:DateCreated column in Sql Server?SQL Server 中的 DateCreated 列?
【发布时间】:2010-10-08 01:06:58
【问题描述】:

是否有一种特殊的方法可以在 MS Sql Server 表中声明 DateCreated 列,以便在创建时自动使用适当的时间戳填充它?

或者..当我进行查询时,我是否必须手动提供日期时间?

【问题讨论】:

    标签: sql sql-server sql-server-2005 linq-to-sql datecreated


    【解决方案1】:

    设置默认值是不够的,你应该添加一个触发器来防止更新:

    CREATE TRIGGER UpdateRecord ON my_table
    AFTER UPDATE AS UPDATE my_table
    SET [CreatedDate] = ((SELECT TOP 1 [CreatedDate] FROM Deleted d where d.[id]=[id]))
    

    【讨论】:

      【解决方案2】:

      默认值有两个主要缺点。

      • 如果插入语句为列指定值,则不使用默认值。
      • 该列可以随时更新。

      这意味着您不能确定这些值没有在您的控制之外被修改。

      如果您想要真正的数据完整性(以便确定行中的日期是创建日期),则需要使用触发器。

      将列设置为当前日期的插入触发器和防止更改该列(或更准确地说,将其设置为其当前值)的更新触发器是实现 DateCreated 列的方法。

      将列设置为当前日期的插入和更新触发器是实现 DateModified 列的方法。

      (来自用户 Gabriel 的编辑 - 这是我按照描述实现此功能的尝试 - 我不是 100% 确定它是正确的,但我希望 OP 对其进行审核...):

      CREATE TRIGGER [dbo].[tr_Affiliate_IU] 
         ON  [dbo].[Affiliate] 
         AFTER INSERT, UPDATE
      AS
      BEGIN
          -- SET NOCOUNT ON added to prevent extra result sets from
          -- interfering with SELECT statements.
          SET NOCOUNT ON;
      
          -- Get the current date.
          DECLARE @getDate DATETIME = GETDATE()
      
          -- Set the initial values of date_created and date_modified.
          UPDATE
              dbo.Affiliate
          SET 
               date_created = @getDate
          FROM
              dbo.Affiliate A 
              INNER JOIN INSERTED I ON A.id = I.id
              LEFT OUTER JOIN DELETED D ON I.id = D.id
          WHERE
              D.id IS NULL
      
          -- Ensure the value of date_created does never changes.
          -- Update the value of date_modified to the current date.
          UPDATE
              dbo.Affiliate
          SET
               date_created = D.date_created
              ,date_modified = @getDate
          FROM 
              dbo.Affiliate A 
              INNER JOIN INSERTED I ON A.id = I.id
              INNER JOIN DELETED D ON I.id = D.id 
      END
      

      【讨论】:

      • 如果您控制环境和应用程序,那么您就可以控制对数据层的访问。这两个问题就变得无关紧要了。
      • 真的,你不认为有人可以通过 JDBC 驱动程序连接到 DBMS 吗? n 层的主要优势之一是让每一层都对其自身的完整性负责。当数据库可以保护自己时,您永远不要假设数据库受到应用程序的保护。这是自找麻烦。
      • @Pax:不,我没有。临时连接无法连接到适当安全的环境。安全性不是 DMBS 的唯一责任(它确实提供了一个起点),因为它应该是一个合作/平台范围的策略。
      • 我从未暗示这是唯一的责任,但它主要责任。每一层都应该保护自己免受攻击。如果你其他层也保护数据库,那很好,但数据库不应该依赖它。
      • 触发器将攻击向量限制在那些(希望是少数)DBA,否则任何拥有数据库登录和表写入权限的人都可以使用“默认值”解决方案破坏您的数据。
      【解决方案3】:

      我们在 CreatedDate 上有 DEFAULT 并且不使用触发器强制执行

      有时我们想明确设置日期 - 例如如果我们从其他来源导入数据。

      应用程序错误可能会干扰 CreateDate,或者对此心存不满的 DBA(我们没有非 DBA 直接连接到我们的 DB)

      我想您可能会在 CreateDate 上设置列级权限。

      折衷办法可能是让 INSERT TRIGGER 在 1:1 表中创建一行,以便该列位于主表之外。第二个表可以具有 SELECT 权限,其中主表具有 UPDATE 权限,因此不需要 UPDATE 触发器来防止对 CreateDate 的更改 - 这会在正常更新行时移除一些“权重”。

      我想你可以在第二张表上设置一个 UPDATE/DELETE 触发器来防止更改(在正常情况下永远不会执行,所以“轻量级”)

      虽然有点痛苦,但拥有额外的表......可能有一个表用于所有 CreateDates - TableName、PK、CreateDate。不过,大多数数据库架构师会讨厌这样...

      【讨论】:

        【解决方案4】:

        当然是。

        这里有一个例子。

        Create table #TableName
        (
            ID INT IDENTITY(1,1) PRIMARY KEY,
            CreatedDate DATETIME NOT NULL DEFAULT GETDATE(),
            SomeDate VARCHAR(100)
        )
        
        INSERT INTO #TableName (SomeDate)
        SELECT 'Some data one' UNION ALL SELECT 'some data two' 
        
        SELECT * FROM #TableName 
        
        DROP TABLE #TableName 
        

        【讨论】:

        • 当一个心怀不满的员工带着“UPDATE #TABLE SET CREATEDDATE = GETDATE()”出现时会发生什么?砰,所有关于行创建时间的宝贵信息都在这里了。
        • @Pax:不会发生在我的地盘上,但万一发生了,我会简单地实施我们的 DR 程序并恢复数据。听起来你需要看看你的安全策略和员工道德:-)
        • “士气”,但也许他们的道德也应该被检查 :-) 无论如何,预防总是比恢复好。这是没有停机时间和一些停机时间之间的区别(没有比任何数量都好)。这可能更像是我工作的环境,System z 上的 DB2,我们总是偏执。
        【解决方案5】:

        您可以将列的默认值设置为“getdate()”

        【讨论】:

        • 请注意,这可能会被用户绕过,因为在插入实际值时不会考虑默认值。它也可以由用户更新。如果您可以控制运行什么 SQL(但您不能:-),这可能就足够了,但它并不安全。
        • 这实际上是一件好事,因为如果用户有一个特定的日期,他们需要把它放在那里可能应该被允许,除非你有另外的规则。
        • 不同意,@James。你没听说过萨班斯-奥克斯利法案吗? :-) 如果您有 DateCreated 列,则应将其设置为该行的创建日期。如果你想要一个用户可更改的列,它应该被称为 DateCreatedForPurposesOfFraud 或类似的东西。
        • 如果你想改变一个触发器控制的列,你提交一个由 8 个管理级别签名的表单,DBA 将数据库离线给用户,禁用触发器,更改日期,然后一切重新开始。然后你就有了审计线索。
        猜你喜欢
        • 1970-01-01
        • 2010-09-19
        • 1970-01-01
        • 1970-01-01
        • 2018-10-15
        • 2012-02-21
        • 2015-01-29
        • 2016-08-09
        相关资源
        最近更新 更多