Author |
Topic |
ferrethouse
Constraint Violating Yak Guru
352 Posts |
Posted - 2012-01-10 : 16:47:20
|
Is there an efficient way to code this? I have a "students" table that has a field called "lastloggedin". There is a trigger on this table that I want to fire if any field other than "lastloggedin" changes. There are 50 columns in this table so I'd prefer not to do the whole...if inserted.lastloggedin <> lastloggedin andinserted.col1 = col1 and inserted.col2 = col2 etc. etc. etc. |
|
Bustaz Kool
Master Smack Fu Yak Hacker
1834 Posts |
Posted - 2012-01-10 : 19:19:35
|
There are a couple of trigger specific functions that might be of use to you. They are UPDATE() and COLUMNS_UPDATED(). The first takes a column name returns true if the column actually changed value. The second returns a bit map of the columns which have changed. Some find this a bit hard to work with. You can find details on each in BOL.If neither of these strike your fancy, you can join and inspect the values in the inserted and deleted pseudo tables. I wouldn't recommend it but you could.=================================================Men shout to avoid listening to one another. -Miguel de Unamuno |
 |
|
visakh16
Very Important crosS Applying yaK Herder
52326 Posts |
Posted - 2012-01-11 : 01:26:47
|
quote: Originally posted by Bustaz Kool There are a couple of trigger specific functions that might be of use to you. They are UPDATE() and COLUMNS_UPDATED(). The first takes a column name returns true if the column actually changed value. The second returns a bit map of the columns which have changed. Some find this a bit hard to work with. You can find details on each in BOL.If neither of these strike your fancy, you can join and inspect the values in the inserted and deleted pseudo tables. I wouldn't recommend it but you could.=================================================Men shout to avoid listening to one another. -Miguel de Unamuno
Not fully correctIt will return true even if column didnt actually change its value but still was a part of update. If just returns the status whether column was a part of update operation without actually looking into before and after values------------------------------------------------------------------------------------------------------SQL Server MVPhttp://visakhm.blogspot.com/ |
 |
|
visakh16
Very Important crosS Applying yaK Herder
52326 Posts |
Posted - 2012-01-11 : 01:28:18
|
quote: Originally posted by ferrethouse Is there an efficient way to code this? I have a "students" table that has a field called "lastloggedin". There is a trigger on this table that I want to fire if any field other than "lastloggedin" changes. There are 50 columns in this table so I'd prefer not to do the whole...if inserted.lastloggedin <> lastloggedin andinserted.col1 = col1 and inserted.col2 = col2 etc. etc. etc.
you cant avoid trigger firing like thatTrigger will fire regardless ofthe conditionBut inside trigger you can code checking logic and do processing only if any other field changes.it will be likeIF EXISTS( SELECT 1 FROM DELETED d INNER JOIN INSERTED i ON i.PK = d.PK AND i.Field1 <> d.Field1 AND i.Field2 <> d.Field2 AND i.Field3 <> d.Field3 AND... )your actual code PK will your actual primary key and all fields except lastloggedinhas to to included in where in same format------------------------------------------------------------------------------------------------------SQL Server MVPhttp://visakhm.blogspot.com/ |
 |
|
Kristen
Test
22859 Posts |
Posted - 2012-01-11 : 04:05:30
|
quote:
IF EXISTS( SELECT 1 FROM DELETED d INNER JOIN INSERTED i ON i.PK = d.PK AND i.Field1 <> d.Field1 AND i.Field2 <> d.Field2 AND i.Field3 <> d.Field3 AND... )
I don't think, in this sort of scenario, doing a test ahead of the actual code helps because there may be individual rows within the updated rows that satisfy the conditions, and other rows that don't, so I think you need to do it on the actual code (e.g. an INSERT or UPDATE), or if the code is more complex I would pre-select the PKs of the relevant rows into a @TableVar / #TempTable and JOIN that to other tables in the code.Also, sadly, the test for "different" needs to be more complicated: ON i.PK = d.PK AND ( (i.Field1 <> d.Field1 COLLATE Latin1_General_BIN OR (i.Field1 IS NULL AND d.Field1 IS NOT NULL) OR (i.Field1 IS NOT NULL AND d.Field1 IS NULL)) OR i.Field2 <> d.Field2 ... ) leave off the COLLATE for any non-Char columns. You can leave the PK columns out of the tests (but including them, for completeness and future-proofing against maintenance-bugs will do no harm - they are, after all, going to match)These WHERE clauses are a bit tedious to make so I generate them mechanically |
 |
|
visakh16
Very Important crosS Applying yaK Herder
52326 Posts |
Posted - 2012-01-11 : 04:12:09
|
quote: Originally posted by Kristen
quote:
IF EXISTS( SELECT 1 FROM DELETED d INNER JOIN INSERTED i ON i.PK = d.PK AND i.Field1 <> d.Field1 AND i.Field2 <> d.Field2 AND i.Field3 <> d.Field3 AND... )
I don't think, in this sort of scenario, doing a test ahead of the actual code helps because there may be individual rows within the updated rows that satisfy the conditions, and other rows that don't, so I think you need to do it on the actual code (e.g. an INSERT or UPDATE), or if the code is more complex I would pre-select the PKs of the relevant rows into a @TableVar / #TempTable and JOIN that to other tables in the code.Also, sadly, the test for "different" needs to be more complicated: ON i.PK = d.PK AND ( (i.Field1 <> d.Field1 COLLATE Latin1_General_BIN OR (i.Field1 IS NULL AND d.Field1 IS NOT NULL) OR (i.Field1 IS NOT NULL AND d.Field1 IS NULL)) OR i.Field2 <> d.Field2 ... ) leave off the COLLATE for any non-Char columns. You can leave the PK columns out of the tests (but including them, for completeness and future-proofing against maintenance-bugs will do no harm - they are, after all, going to match)These WHERE clauses are a bit tedious to make so I generate them mechanically
It will help to identify if at all there are some rows which satisfies the criteria ops interested in though if you want to do some processing over each of them, you need to do in inline code just like in the above suggestion------------------------------------------------------------------------------------------------------SQL Server MVPhttp://visakhm.blogspot.com/ |
 |
|
Bustaz Kool
Master Smack Fu Yak Hacker
1834 Posts |
Posted - 2012-01-11 : 11:45:17
|
If I am correct im assuming that you want to avoid the condition where the only column that changed is a single specific "administrative" column then I'd use the COLUMNS_UPDATED() function. You'll need to figure out the correct mapping of your special column to the bit map but the test becomes does the bit map equal a specific value(s).Visakh16, thanks for the elaboration on the UPDATE() function.=================================================Men shout to avoid listening to one another. -Miguel de Unamuno |
 |
|
visakh16
Very Important crosS Applying yaK Herder
52326 Posts |
Posted - 2012-01-11 : 11:49:13
|
quote: Originally posted by Bustaz Kool If I am correct im assuming that you want to avoid the condition where the only column that changed is a single specific "administrative" column then I'd use the COLUMNS_UPDATED() function. You'll need to figure out the correct mapping of your special column to the bit map but the test becomes does the bit map equal a specific value(s).Visakh16, thanks for the elaboration on the UPDATE() function.=================================================Men shout to avoid listening to one another. -Miguel de Unamuno
no probsyou're welcome ------------------------------------------------------------------------------------------------------SQL Server MVPhttp://visakhm.blogspot.com/ |
 |
|
X002548
Not Just a Number
15586 Posts |
|
ferrethouse
Constraint Violating Yak Guru
352 Posts |
Posted - 2012-01-23 : 11:32:32
|
quote: Originally posted by X002548 ummmm, what does your TRIGGER DO?Do you only allow stored procedures to access or modify your data?
Students get automatically enrolled into courses based on their profile data. So if a student is a "Manager" then they may get assigned some management courses. Therefore, when a student's profile changes we need to check against the thousands of rules that may exist. But tens of thousands of students simply login to our application every day and this causes the "lastloggedin" date to change which causes all of these rules to be evaluated. It is unnecessary burden on the server. |
 |
|
ferrethouse
Constraint Violating Yak Guru
352 Posts |
Posted - 2012-01-23 : 15:53:27
|
Found this which seems to do the job...declare @bit int , @field int , @doCode bit, @char int select @field = 0 set @doCode = 0 while @field < (select max(colid) from syscolumns where id = (select id from sysobjects where name = 'students')) begin select @field = @field + 1 select @bit = (@field - 1 )% 8 + 1 select @bit = power(2,@bit - 1) select @char = ((@field - 1) / 8) + 1 --select @char, @field, @bit if substring(COLUMNS_UPDATED(),@char, 1) & @bit > 0 BEGIN if (select name from syscolumns where colid = @field and id = (select id from sysobjects where name = 'students')) <> 'LastLoggedIn' set @doCode = 1 else set @doCode = 0 END END |
 |
|
Kristen
Test
22859 Posts |
Posted - 2012-01-23 : 16:00:37
|
As already stated "COLUMNS_UPDATED" is NOT an indication that a column has changed - assuming that is important to you?I would also be extremely concerned about using a LOOP in this way, particularly in a TRIGGER which is a time-critical piece of code.Why can't you just compare all (relevant) columns between INSERTED and DELETED to see if any of the column(s) [you are concerned about] has changed? That's a set based operation and will be much more efficient. |
 |
|
LoztInSpace
Aged Yak Warrior
940 Posts |
Posted - 2012-01-24 : 01:18:51
|
Can you remove "lastloggedin" from the table and put it in a new table or somewhere else that already exists with a one/one on the students table?You can create a view that joins the original table to the "somewhere else.lastloggedin" if you find you're using it a lot.If you're not prepared to do the above then I'd say you just have to suck it up and type it in. Kristen's suggestion to mechanically generate the check code for you seems reasonable - you can just put the list of columns into Excel or something, work some magic then copy & paste into your trigger. Should't take more than 10 mins, but very ugly.This is a classic example of why I hate triggers! |
 |
|
|