在MS SQL中创建“更新日期”列?

时间:2010-08-27 14:46:01

标签: sql-server datetime

有没有简单的方法在MS SQL中创建一个跟踪上次更新记录的列?

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

我的选择是:

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

还有其他选择吗?

3 个答案:

答案 0 :(得分:5)

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

答案 1 :(得分:1)

选项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

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

我不确定我是否解决了所有语法错误 - 我从之前完成此操作的代码中修改了它并且实际上没有测试它。我相信你能搞清楚。

答案 2 :(得分:0)

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

我已经完成了,但是很多以前没有示例代码向您展示,抱歉。

否则触发是通常的方式,无论是在之前还是之后。