J'ai besoin de créer un nouveau champ DATETIME dans MS-SQL qui contiendra toujours la date de création de l'enregistrement, puis il doit se mettre à jour automatiquement chaque fois que l'enregistrement est modifié. J'ai entendu des gens dire que j'avais besoin d'un déclencheur, ce qui est bien, mais je ne sais pas comment l'écrire. Quelqu'un pourrait-il aider avec la syntaxe d'un déclencheur pour accomplir cela?
En termes MySQL, il devrait faire exactement la même chose que cette déclaration MySQL:
ADD `modstamp` timestamp NULL DEFAULT CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP
Voici quelques exigences:
MSSQL, en fait, n'a aucun moyen de définir une valeur par défaut pour UPDATE.
Vous devez donc ajouter une colonne avec une valeur par défaut pour l'insertion:
ADD modstamp DATETIME2 NULL DEFAULT GETDATE()
Et ajoutez un déclencheur sur la table:
CREATE TRIGGER tgr_modstamp
ON **TABLENAME**
AFTER UPDATE AS
UPDATE **TABLENAME**
SET ModStamp = GETDATE()
WHERE **ID** IN (SELECT DISTINCT **ID** FROM Inserted)
Et oui, vous devez spécifier une colonne d'identité pour chaque déclencheur.
ATTENTION: faites attention lors de l'insertion de colonnes sur des tables dont vous ne connaissez pas le code de l'application. Si votre application a la commande INSERT VALUES sans définition de champ, elle générera des erreurs même avec la valeur par défaut sur les nouvelles colonnes.
D'accord, j'aime toujours garder une trace non seulement quand quelque chose s'est passé, mais qui l'a fait!
Permet de créer une table de test dans [tempdb] nommée [nains]. Lors d'un emploi antérieur, une institution financière, nous gardons une trace de la date insérée (créer) et mise à jour (modifier).
-- 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
Pour les mises à jour, mais les tables insérées et supprimées existent. Je choisis de participer à l'inséré pour la mise à jour.
-- 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
Last but not least, permet de tester le code. Tout le monde peut taper une instruction TSQL non testée. Cependant, je soumets toujours mon équipe à des tests de stress!
-- 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;
Le résultat. J'ai seulement attendu 10 secondes entre l'insertion et la suppression. Ce qui est bien, c'est que qui et quand sont tous les deux capturés.
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
Cela est possible depuis SQL Server 2016 en utilisant PERIOD FOR SYSTEM_TIME
.
C'est quelque chose qui a été introduit pour les tables temporelles mais vous n'avez pas besoin d'utiliser des tables temporelles pour l'utiliser.
Un exemple est ci-dessous
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;
Il a certaines limites.
MaxDateTime2
ci-dessus) qui est complètement superflu pour ce cas d'utilisation. Mais il peut être marqué comme caché, ce qui le rend plus facile à ignorer.ALTER TRIGGER [trg_table_name_Modified]
ON [table_name]
AFTER UPDATE
AS
Begin
UPDATE table_name
SET modified_dt_tm = GETDATE() -- or use SYSDATETIME() for 2008 and newer
FROM Inserted i
WHERE i.ID = table_name.id
end