Please start any new threads on our new
site at https://forums.sqlteam.com. We've got lots of great SQL Server
experts to answer whatever question you can come up with.
| Author |
Topic |
|
steamngn
Constraint Violating Yak Guru
306 Posts |
Posted - 2005-02-18 : 22:02:17
|
I seem to come up with all the good ones:I need to set two tables so that after an entry is made into a column, it cannot be changed. i wrote the following trigger, thinking that this would be the way to go, for one of the columns:CREATE trigger DISALLOW_ENTRY_CHANGE on WARR_PARTS_RCVD after insertas set nocount on/* Declare local variables */declare @AMT T_MONEY, @CHG T_MONEY, @Msg T_ERR_REFselect @AMT = I.ACT_PARTS_AMT, @CHG=D.ACT_PARTS_AMTfrom inserted IJOIN DELETED DON I.TKT_NO=D.TKT_NO/* Make sure the entry has not changed */if @AMT <> @CHG and @AMT IS NOT NULL begin select @Msg = @AMT + ' <> ' + @CHG + ' - you may not CHANGE ENTRIES!' raiserror(@Msg, 18, 1) end Not only does this not work, but I need to do this for each column in each table, 20 columns in all. Anyone know an easier (and functioning!) way to do this?AndyThere's never enough time to type code right, but always enough time for a hotfix... |
|
|
robvolk
Most Valuable Yak
15732 Posts |
Posted - 2005-02-18 : 22:47:36
|
| How about denying UPDATE permissions on those columns? Then you don't need a trigger at all. |
 |
|
|
Kristen
Test
22859 Posts |
Posted - 2005-02-19 : 04:11:35
|
| ... or use the COLUMNS_UPDATED() function, in your trigger, which will allow you to determine if any of the relevant columns have been updated, in one strike.Kristen |
 |
|
|
rockmoose
SQL Natt Alfen
3279 Posts |
Posted - 2005-02-19 : 04:12:13
|
DENY might work, but sysadmin will be able to update anyway.DENY UPDATE ON ... TO public in your trigger:IF (COLUMNS_UPDATED() & <bitmask>)BEGINROLLBACKRAISERROR('Not updateable...',16,1)ENDrockmoose |
 |
|
|
steamngn
Constraint Violating Yak Guru
306 Posts |
Posted - 2005-02-19 : 07:03:42
|
| Hey gang,I have to admit I didn't even give DENY a thought. DUH! letting the sysadmin update is ok, this needs to block entry from an app. I've never used DENY before; If a rowset is inserted, will DENY treat NULL as an entry? That is one of my issues. A Row may be inserted that will have only partial data, and when an operator comes back to update what was missing we don't want to allow changing of previous entries. Rockmoose, if DENY will work as above, what would the syntax look like for all of the columns using your trigger text?Would it be a single entry, or one for each column?AndyThere's never enough time to type code right, but always enough time for a hotfix... |
 |
|
|
robvolk
Most Valuable Yak
15732 Posts |
Posted - 2005-02-19 : 07:44:26
|
Assuming your application uses a particular login, you can use DENY UPDATE on that user only. Then you can create a stored procedure to perform these updates you DO want. The procedure would contain the logic needed to prevent updating non-null entries. The user would be able to execute the procedure, but not update the table directly.For completeness, you can also GRANT INSERT to the user, but if you're using a stored procedure for inserting data as well you might as well be totally safe and DENY INSERT too. I'm a big fan of explicitly denying user permissions, it's a great way to indulge any megalomaniac tendencies, and as a side-effect, keeps your data safe. |
 |
|
|
steamngn
Constraint Violating Yak Guru
306 Posts |
Posted - 2005-02-19 : 08:30:48
|
| Hey Robvolk,megalomaniac tendancies; sign me up! Here's the skinny on the whole scenario:1) The app doesn't use SQL user logins (figures; why make it easy)2) For some dumb-ass reason, the app cannot be configured to call a procedure directly. It interfaces with SQL on a table level only.3) The app has a feature for non-edit, which locks the column after an entry is made. Problem is, NULL is a valid entry to the app!4) Each row is inserted and then updated once or twice before the entry is complete. Once the entry is complete, a proc will copy the data to a historical table and then delete it from the table(s) in question. I thought about a CHECK CONSTRAINT, but couldn't get that to work right either. Think I'll take a break, go refill my coffee and abuse an underling...AndyThere's never enough time to type code right, but always enough time for a hotfix... |
 |
|
|
robvolk
Most Valuable Yak
15732 Posts |
Posted - 2005-02-19 : 08:47:23
|
If you're using Windows Authentication, you can still DENY UPDATE to public. You can also find out if a Windows group contains all of the users of your app. You can add that Windows group as a login to SQL Server, add it as a user to the database, and DENY UPDATE to that group. Worst case, you can add all of the users to a database role and then DENY UPDATE to that role. Lots of DENY possibilities here! Unless you're dealing with a 3rd party app, you can always go to the developers and say "Hey, because of Sarbanes-Oxley, we can no longer allow direct access to database tables" or something like that. And you might not have to make anything up; if your company needs to comply with SOX you'd better check with your legal department about that. Even if you are dealing with a 3rd party app, you might be able to require them to change it for that reason.If none of these will work, then I suppose you'll have to figure it out in the trigger, and as you know it's gonna be a dog to write no matter what.If it makes you feel better, go strangle a random someone at work, or if possible, the people who wrote the program. |
 |
|
|
rockmoose
SQL Natt Alfen
3279 Posts |
Posted - 2005-02-19 : 09:02:25
|
| If we are talking lots of tables with many columns and the pattern of the triggers are the same.Then write a SQL script that generates(writes) the triggers for you. Should be more fun anyway.rockmoose |
 |
|
|
steamngn
Constraint Violating Yak Guru
306 Posts |
Posted - 2005-02-19 : 09:12:37
|
Ok, slapped the face off some nameless intern, I feel better now. There are only two tables involved here, one that has 14 columns and one that has 7 columns. We've been down the whole SOX thing, and (of course) the programmers aren't accountable (you're right, shoulda slapped one of them instead). Anyway, it is looking more and more like this trigger is gonna haunt me; Naturally the whole damned company is using this portion of the app, so I would need to create an entire company group....(sigh) I will plod along with the trigger for now, any help would be greatly appreciated. In the meantime I will check into building a group for the whole company, but I can see some issues looming with that already. I think my blood pressure is climbing, gotta go smack another intern...Andy There's never enough time to type code right, but always enough time for a hotfix... |
 |
|
|
Kristen
Test
22859 Posts |
Posted - 2005-02-19 : 10:48:02
|
Ah you saying that if the column is NULL then it can be updated, but once it is NOT NULL then it can't?If so you could do a trigger along the lines ofCREATE TRIGGER ......AS...UPDATE USET MyCol1 = COALESCE(D.MyCol1, U.MyCol1), MyCol2 = COALESCE(D.MyCol2, U.MyCol2),...FROM MyTable U JOIN deleted D ON D.MyPK = U.MyPK This will, in effect, PUT BACK the value (from DELETED) that was originally there, but ONLY if that value was NOT NULL; otherwise it will allow the column's own value.Kristen |
 |
|
|
steamngn
Constraint Violating Yak Guru
306 Posts |
Posted - 2005-02-19 : 10:58:53
|
Ok Gang,here is a single-column trigger that works:CREATE trigger DISALLOW_ENTRY_CHANGE on WARR_PARTS_RCVDfor updateas set nocount on/* Declare local variables */declare @AMT T_MONEY, @CHG T_MONEY, @Msg T_ERR_REFselect @AMT = I.ACT_PARTS_AMT, @CHG=D.ACT_PARTS_AMTfrom inserted IJOIN DELETED DON I.TKT_NO=D.TKT_NO/* Make sure the entry has not changed */if @AMT <> @CHG beginrollback raiserror('you may not CHANGE ENTRIES!', 18, 1) endThis works for one. Now, do I add the other columns to this (how?) or do I write separate triggers for each?Hmmmm...There's never enough time to type code right, but always enough time for a hotfix... |
 |
|
|
steamngn
Constraint Violating Yak Guru
306 Posts |
Posted - 2005-02-19 : 11:15:24
|
Ok,here we go:CREATE trigger DISALLOW_ENTRY_CHANGE on WARR_PARTS_RCVD FOR UPDATEas set nocount on/* Declare local variables */declare @AMT T_MONEY, @CHG T_MONEY, @AMT2 T_MONEY, @CHG2 T_MONEY, @DT T_DAT, @DTC T_DAT, @DT2 T_DAT, @DTC2 T_DAT, @V T_VEND_NO, @VC T_VEND_NO, @V2 T_VEND_NO, @VC2 T_VEND_NO, @R T_FLG, @RC T_FLG, @R2 T_FLG, @RC2 T_FLG, @Msg T_ERR_REFselect @AMT=i.ACT_PARTS_AMT,@AMT2=i.ACT_PARTS_AMT2,@DT=i.DATE_PARTS_RCVD,@DT2=i.DATE_PARTS_RCVD2,@V=i.ACT_PARTS_VEND,@V2=i.ACT_PARTS_VEND2,@R=i.PARTS_RCV_TYP,@R2=i.PARTS_RCV_TYP2, @CHG=D.ACT_PARTS_AMT,@CHG2=D.ACT_PARTS_AMT2,@DTC=D.DATE_PARTS_RCVD,@DTC2=D.DATE_PARTS_RCVD2,@VC=D.ACT_PARTS_VEND,@VC2=D.ACT_PARTS_VEND2,@RC=D.PARTS_RCV_TYP,@RC2=D.PARTS_RCV_TYP2from inserted iJOIN DELETED DON i.TKT_NO=D.TKT_NO/* Be sure user is the user logged in */if (@AMT<>@CHG) OR (@AMT2<>@CHG2)OR(@DT<>@DTC)OR(@DT2<>@DTC2) OR(@V<>@VC)OR(@V2<>@VC2) OR(@R<>@RC)OR(@R2<>@RC2) BEGINROLLBACK raiserror( ' !CHANGE ENTRY NOT ALLOWED!', 18, 1) end this seems to do the trick. Anyone see any problems with this that I may be overlooking? There's never enough time to type code right, but always enough time for a hotfix... |
 |
|
|
Kristen
Test
22859 Posts |
Posted - 2005-02-20 : 07:40:14
|
| This will onyl work for one row updates won't it?What about if you doUPDATE WARR_PARTS_RCVDSET ACT_PARTS_AMT = 0-- i.e. change ALL rows in tableIf the LAST ROW encountered happens to have ACT_PARTS_AMT = 0 then your test will not show an error (for that column) whereas all the other rows will (lets say) have been changed.Kristen |
 |
|
|
|
|
|
|
|