sql server - UPDATE modified date trigger only if modified date is not supplied -


i have tables have "created" , "modified" dates on them. i'd able update latter if modified date not supplied application layer. need have application layer able set modified date specific value in event offline transaction (such device no internet connection syncs @ later date) occurs, can't ensure ever application developer remember set modified date in application code.

given following table:

create table [dbo].[tests](     [testid] [int] identity(1,1) not null,     [name] [nvarchar](50) not null,     [createddate] [datetime2](7) not null,     [modifieddate] [datetime2](7) not null,  constraint [pk_tests] primary key clustered  (     [testid] asc )with (pad_index = off, statistics_norecompute = off, ignore_dup_key = off, allow_row_locks = on, allow_page_locks = on) on [primary] ) on [primary]  go  alter table [dbo].[tests] add  constraint [df_tests_createddate]  default (getutcdate()) [createddate] go  alter table [dbo].[tests] add  constraint [df_tests_modifieddate]  default (getutcdate()) [modifieddate] go 

it seem when no "modified date" supplied in update, instead of either updating or throwing exception, stays same.

example test cases:

generated linq-to-entities code:

exec sp_executesql n'update [dbo].[tests] set [name] = @0 ([testid] = @1) ',n'@0 nvarchar(50),@1 int',@0=n'test_635267931494843908',@1=3 

should update modified date getutcdate()

sql code:

update tests set name = 'test' + convert(nvarchar(255), newid())  testid =3 

should update modified date getutcdate()

sql code modified date:

update tests set name = 'test' + convert(nvarchar(255), newid()), modifieddate = '2014-01-31 19:10:48' testid =3 

should update modified date '2014-01-31 19:10:48'

i have tried following:

create trigger      [dbo].[modifieddateupdatetrigger] on      [dbo].[tests] after update  begin      update dbo.tests      set modifieddate = getutcdate()     dbo.tests t     inner join inserted on i.testid = t.testid     inner join deleted d on d.testid = t.testid     t.modifieddate <> i.modifieddate         , d.modifieddate <> i.modifieddate end 

and

create trigger      [dbo].[modifieddateupdatetrigger] on      [dbo].[tests] update  begin     declare @m datetime2(7) = (select modifieddate inserted)     print @m     if (select modifieddate inserted)   null     begin         return     end      update dbo.tests      set modifieddate = getutcdate()     inserted     i.testid = tests.testid end 

and finally:

create trigger      [dbo].[modifieddateupdatetrigger] on      [dbo].[tests] update  begin     declare @m datetime2(7) = (select modifieddate inserted)     print @m     if (select modifieddate inserted) <> (select i.modifieddate tests t inner join inserted on t.testid = i.testid)     begin         return     end      update dbo.tests      set modifieddate = getutcdate()     inserted     i.testid = tests.testid end 

none of these work desire test case.

you can't use of these methods pretend inserted ever contain 1 row (what if update more 1 test in single statement?). instead, need perform join-based update, , can use coalesce() determine whether different value supplied column (when hasn't, replace getutcdate()). here approach prefer:

create trigger  [dbo].[modifieddateupdatetrigger] on [dbo].[tests] update  begin   set nocount on;    update t     set modifieddate = coalesce(nullif(i.modifieddate,d.modifieddate), getutcdate())     dbo.tests t     inner join inserted      on t.testid = i.testid     inner join deleted d      on t.testid = d.testid; end go 

the reason complication this. consider simple table:

create table dbo.tests(testid int, modifieddate datetime, x varchar(1)); 

now, 2 rows:

insert dbo.tests(testid) select 1,getdate() union select 2,getdate(); 

we want update modifieddate column in scenario:

update dbo.tests set x = 'y'; 

but in scenario:

update dbo.tests set x = 'y', modifieddate = case   when testid = 1 '19000101' else modifieddate end   testid in (1,2); 

both of these handled adequately multi-row updates trigger, latter might handled incorrectly if assume value supplied in inserted new one. need compare deleted ensure has changed. thing makes hard do? set value explicitly null (well, without disabling trigger). :-) in case replace null passed getutcdate(). not you'd ever want that, didn't want leave unsaid.


update

in comments mentioned 1 case want prevent modifieddate getting "bumped" if hard-coded same modifieddate value in subsequent update statements. couldn't find way of differentiating in after trigger (since table has been changed, , @ point it's impossible tell if current update or previous one), did find way differentiate in instead of trigger. if can change instead of trigger, can - additional complication have account other columns might not mentioned explicitly in update statement or want handle differently depending on before/after values. here trigger:

create trigger  [dbo].[modifieddateupdatetrigger] on [dbo].[tests] instead of update  begin   set nocount on;    update src      set src.name = i.name, /* other columns might updated */       src.modifieddate = case          when i.modifieddate <> src.modifieddate case            when update(modifieddate) i.modifieddate else getutcdate() end         when i.modifieddate = src.modifieddate case            when not update(modifieddate) getutcdate() else src.modifieddate end         else getutcdate()        end     dbo.tests src     inner join inserted     on i.testid = src.testid     inner join deleted d     on i.testid = d.testid; end go 

and here demo: http://sqlfiddle.com/#!3/4a00b5/1

i'm not 100% confident else condition required, exhausted time invest in testing today.


Comments

Popular posts from this blog

php - regexp cyrillic filename not matches -

c# - OpenXML hanging while writing elements -

sql - Select Query has unexpected multiple records (MS Access) -