【问题标题】:Creating a "date updated" column in MS SQL?在 MS SQL 中创建“更新日期”列?
【发布时间】:2010-08-27 14:46:00
【问题描述】:

是否有任何简单的方法可以在 MS SQL 中创建一个列来跟踪记录的上次更新时间?

我想要两个字段。用于跟踪记录的创建时间。那个很简单。创建一个日期时间字段并将其默认设置为 getdate()。然而,第二个字段接缝有点棘手。我希望它具有修改记录的最新日期(和时间)。

我的选择是:

  • 在每个更新语句中包含 getdate() - 这不是一个选项,这些表将通过 MS Access 访问
  • 只允许通过 SP 进行更新。 - 不是一个选项,这些表将通过 MS Access 访问
  • 为每个表创建触发器 - 数据库在许多机器上重新创建,我担心它会发生冲突、被遗忘或不同步。

还有其他选择吗?

【问题讨论】:

    标签: sql-server datetime


    【解决方案1】:

    触发器几乎是您在这里的唯一选择。什么是阻止任何人使用 SSMS 更新表,在这种情况下,这些更新不会更新更新日期列

    【讨论】:

      【解决方案2】:

      选项 4:

      创建一个自动为数据库中所有表创建触发器的存储过程。在 SQL 2005 中,可以选择在任何时候创建任何表时运行此触发器(使用 DDL 触发器)。

      CREATE PROC UpdateTriggersCreate
      AS
      DECLARE
         @TableSchema sysname,
         @TableName sysname,
         @PrimaryKeys nvarchar(4000),
         @ObjectName nvarchar(4000)
         @TriggerName nvarchar(4000),
         @SQL nvarchar(4000);
      SET @TableName = '';
      SET @TableSchema = '';
      WHILE 1 = 1 BEGIN
         SELECT TOP 1
            @TableSchema = TABLE_SCHEMA,
            @TableName = TABLE_NAME
         FROM INFORMATION_SCHEMA.COLUMNS
         WHERE
            COLUMN_NAME = 'LastUpdatedDate'
            AND (
               TABLE_SCHEMA > @TableSchema
               OR (
                  TABLE_SCHEMA = @TableSchema
                  AND TABLE_NAME > @TableName
               )
            )
         ORDER BY TABLE_SCHEMA, TABLE_NAME;
         IF @@RowCount = 0 BREAK;
      
         IF NOT EXISTS (
            SELECT *
            FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS C
            WHERE
               C.CONSTRAINT_TYPE = 'PRIMARY KEY'
               AND C.TABLE_SCHEMA = @TableSchema
               AND C.TABLE_NAME = @TableName
         ) BEGIN
             PRINT '-- Not processing table ''' + @TableSchema + '.' + @TableName + ''' because automatic last updated triggers cannot be used on tables with no primary key.';
             CONTINUE;
         END;
      
         SET @PrimaryKeys = NULL;
         SELECT @PrimaryKeys = Coalesce(@PrimaryKeys + ' AND T.', 'T.') + QuoteName(Y.COLUMN_NAME) + ' = I.' + QuoteName(Y.COLUMN_NAME)
         FROM
            INFORMATION_SCHEMA.TABLE_CONSTRAINTS T
            INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE Y
               ON T.CONSTRAINT_CATALOG = Y.CONSTRAINT_CATALOG
               AND T.CONSTRAINT_SCHEMA = Y.CONSTRAINT_SCHEMA
               AND T.CONSTRAINT_NAME = Y.CONSTRAINT_NAME
         WHERE
            T.CONSTRAINT_TYPE = 'PRIMARY KEY'
            AND T.TABLE_SCHEMA = @TableSchema
            AND T.TABLE_NAME = @TableName;
         -- order is not important which is good because ORDER BY is unreliable in this case
      
         SET @ObjectName = @TableSchema + '.' + @TableName;
         SET @TriggerName = 'TR_' + Replace(@ObjectName, '.', '_') + '_U_TimeUpdated';
         SET @SQL = 'IF Object_ID(''' + @TriggerName + ''', ''TR'') IS NOT NULL DROP TRIGGER ' + @TriggerName;
         EXEC sp_executesql @SQL;
         SET @SQL = 'CREATE TRIGGER ' + @TriggerName + ' ON ' + @ObjectName + ' FOR INSERT
      AS
      SET NOCOUNT ON
      UPDATE T
      SET T.LastUpdatedDate = GetDate()
      FROM
         ' + @ObjectName + ' T
         INNER JOIN Inserted I ON ' + @PrimaryKeys;
      
         EXEC sp_executesql @SQL;
      END;
      

      一旦您有了这样的存储过程,就安排它每天运行一次,或者(在 sql 2005 及更高版本中)响应 DDL 创建表。

      更新 1

      代码现在可以正确处理架构,并查找主键。它还报告并跳过没有主键的表。

      我不确定我是否解决了所有的语法错误——我根据之前做过的代码对其进行了调整,但实际上并没有对其进行测试。我相信你能想出来。

      【讨论】:

      • B"H 是的,我想这是一个选项。我需要充实它以查找主键,并且我必须了解架构。
      • @Rabbi - 在那里,我为你充实了它。
      【解决方案3】:

      存储过程是 Access 的一个选项,但您必须在 VBA 中拦截事件并改为调用存储过程,然后是 Me.Undo

      我已经完成了,但很多个月前没有示例代码可以展示给您,抱歉。

      否则触发器是通常的方式,在触发器之前或之后。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-02-13
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-07-04
        • 1970-01-01
        相关资源
        最近更新 更多