需要MS SQL中的datetime字段,该字段在修改记录时自动更新

Jes*_*num 20 t-sql sql-server timestamp

我需要在MS-SQL中创建一个新的DATETIME字段,它始终包含创建记录的日期,然后每当修改记录时都需要自动更新.我听说有人说我需要一个触发器,这很好,但我不知道如何写它.有人可以帮助触发器的语法来实现这一目标吗?

在MySQL术语中,它应该与此MySQL语句完全相同:

ADD `modstamp` timestamp NULL DEFAULT CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP
Run Code Online (Sandbox Code Playgroud)

以下是一些要求:

  • 我无法更改我的UPDATE语句以在修改行时设置字段,因为我不控制写入记录的应用程序逻辑.
  • 理想情况下,我不需要知道表中任何其他列的名称(例如主键)
  • 它应该简短而有效,因为它会经常发生.

rka*_*ano 29

实际上,MSSQL没有办法为UPDATE定义默认值.

因此,您需要添加一个具有默认值的列以进行插入:

ADD modstamp DATETIME2 NULL DEFAULT GETDATE()
Run Code Online (Sandbox Code Playgroud)

并在表格上添加一个Trigger:

CREATE TRIGGER tgr_modstamp
ON **TABLENAME**
AFTER UPDATE AS
  UPDATE **TABLENAME**
  SET ModStamp = GETDATE()
  WHERE **ID** IN (SELECT DISTINCT **ID** FROM Inserted)
Run Code Online (Sandbox Code Playgroud)

是的,您需要为每个触发器指定一个标识列.

注意:在不知道应用程序代码的表上插入列时要小心.如果您的应用程序具有INSERT VALUES命令而没有字段定义,则即使在新列上使用默认值,也会引发错误.

  • 在子选择中你不需要`distinct`有两个原因:第一:`in`操作符将正确处理它,第二:`id`必须是主键才能使你的触发器工作,因此`distinct`永远不会删除任何值,因为`id`的所有值都是唯一的定义. (3认同)
  • 不会在触发器内部更新,再触发触发器,创建无限循环? (2认同)
  • @alfoks:默认情况下,没有。触发器不会递归调用同一个触发器。但是,如果启用了 db 设置 RECURSIVE_TRIGGERS,那么此特定触发器将导致无限循环并超过 32 个嵌套触发器的限制,并且将回滚完整批次。 (2认同)

CRA*_*DBA 12

好吧,我总是喜欢不仅记录发生的事情,而且还记得谁做到了!

让我们在名为[dwarfs]的[tempdb]中创建一个测试表.在以前的工作,金融机构,我们跟踪插入(创建)日期和更新(修改)日期.

-- just playing
use tempdb;
go

-- drop table
if object_id('dwarfs') > 0
drop table dwarfs
go

-- create table
create table dwarfs
(
asigned_id int identity(1,1),
full_name varchar(16),
ins_date datetime,
ins_name sysname,
upd_date datetime,
upd_name sysname,
);
go

-- insert/update dates
alter table dwarfs
    add constraint [df_ins_date] default (getdate()) for ins_date;
alter table dwarfs
    add constraint [df_upd_date] default (getdate()) for upd_date;

-- insert/update names
alter table dwarfs
    add constraint [df_ins_name] default (coalesce(suser_sname(),'?')) for ins_name;

alter table dwarfs
    add constraint [df_upd_name] default (coalesce(suser_sname(),'?')) for upd_name;
go
Run Code Online (Sandbox Code Playgroud)

对于更新,但存在已插入和已删除的表.我选择加入插入更新.

-- create the update trigger
create trigger trg_changed_info on dbo.dwarfs
for update
as
begin

    -- nothing to do?
    if (@@rowcount = 0)
      return;

    update d
    set 
       upd_date = getdate(),
       upd_name = (coalesce(suser_sname(),'?'))
    from
       dwarfs d join inserted i 
    on 
       d.asigned_id = i.asigned_id;

end
go
Run Code Online (Sandbox Code Playgroud)

最后但并非最不重要的是,让我们测试代码.任何人都可以输入未经测试的TSQL语句.但是,我总是强调我的团队测试!

-- remove data
truncate table dwarfs;
go

-- add data
insert into dwarfs (full_name) values
('bilbo baggins'),
('gandalf the grey');
go

-- show the data
select * from dwarfs;

-- update data
update dwarfs 
set full_name = 'gandalf'
where asigned_id = 2;

-- show the data
select * from dwarfs;
Run Code Online (Sandbox Code Playgroud)

输出.我只在插入和删除之间等了10秒.好的是,谁和何时都被捕获.

在此输入图像描述


M.A*_*Ali 7

Create trigger tr_somename 
On table_name
For update
As 
Begin
    Set nocount on; 
       Update t
        Set t.field_name = getdate()
        From table_name t inner join inserted I 
        On t.pk_column = I.pk_column
End
Run Code Online (Sandbox Code Playgroud)

  • ROFLOL - 阿里我必须通过你的手机给你积分.我希望你在回答帖子时不开车! (3认同)

Mar*_*ith 6

这可以从SQL Server 2016开始使用PERIOD FOR SYSTEM_TIME.

这是为时态表引入的内容,但您不必使用时态表来使用它.

一个例子如下

CREATE TABLE dbo.YourTable
(  
    FooId INT PRIMARY KEY CLUSTERED,   
    FooName VARCHAR(50) NOT NULL,
    modstamp DATETIME2 GENERATED ALWAYS AS ROW START NOT NULL,   
    MaxDateTime2 DATETIME2 GENERATED ALWAYS AS ROW END HIDDEN NOT NULL,     
    PERIOD FOR SYSTEM_TIME (modstamp,MaxDateTime2)    
)  

INSERT INTO dbo.YourTable (FooId, FooName)
VALUES      (1,'abc');

SELECT *
FROM   dbo.YourTable;

WAITFOR DELAY '00:00:05'

UPDATE dbo.YourTable
SET    FooName = 'xyz'
WHERE  FooId = 1;

SELECT *
FROM   dbo.YourTable;

DROP TABLE dbo.YourTable; 
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

它有一些局限性.

  • 存储的时间将由系统更新,并始终为UTC.
  • 需要声明第二列(MaxDateTime2上面),这对于这个用例是完全多余的.但它可以被标记为隐藏,使其更容易被忽略.

  • @SethFlowers - 您最终处于与此处相同的状态[当您设置 SYSTEM_VERSIONING = OFF 并且不删除 SYSTEM_TIME 周期时,系统将继续更新每个插入和更新操作的周期列。](https:// learn.microsoft.com/en-us/sql/relational-databases/tables/stopping-system-versioning-on-a-system-versioned-temporal-table?view=sql-server-ver16#important-remarks) (3认同)
  • 有趣的方法。所有文档[此处](https://docs.microsoft.com/zh-cn/sql/t-sql/statements/create-table-transact-sql)都将“ PERIOD FOR SYSTEM TIME”与时态表结合使用( SYSTEM_VERSIONING = ON`)。我也找不到其他关于它独立的东西。在没有系统版本控制的情况下可以正常工作是a幸吗?我担心会使用它,然后发现它是一个未记录的功能,将来他们会“纠正”,将其从我下面拉出来。 (2认同)