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.

 All Forums
 SQL Server 2000 Forums
 SQL Server Development (2000)
 trigger to disallow change

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 insert
as
set nocount on

/* Declare local variables */
declare
@AMT T_MONEY,
@CHG T_MONEY,
@Msg T_ERR_REF

select
@AMT = I.ACT_PARTS_AMT,
@CHG=D.ACT_PARTS_AMT
from inserted I
JOIN DELETED D
ON 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?
Andy

There'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.
Go to Top of Page

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
Go to Top of Page

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>)
BEGIN
ROLLBACK
RAISERROR('Not updateable...',16,1)
END

rockmoose
Go to Top of Page

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?
Andy

There's never enough time to type code right,
but always enough time for a hotfix...
Go to Top of Page

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.
Go to Top of Page

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...
Andy

There's never enough time to type code right,
but always enough time for a hotfix...
Go to Top of Page

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.
Go to Top of Page

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
Go to Top of Page

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...
Go to Top of Page

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 of

CREATE TRIGGER ...
...
AS

...

UPDATE U
SET 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
Go to Top of Page

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_RCVD
for update
as
set nocount on

/* Declare local variables */
declare
@AMT T_MONEY,
@CHG T_MONEY,
@Msg T_ERR_REF

select
@AMT = I.ACT_PARTS_AMT,
@CHG=D.ACT_PARTS_AMT
from inserted I
JOIN DELETED D
ON I.TKT_NO=D.TKT_NO

/* Make sure the entry has not changed */
if @AMT <> @CHG
begin
rollback
raiserror('you may not CHANGE ENTRIES!', 18, 1)
end


This 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...
Go to Top of Page

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 UPDATE
as
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_REF

select
@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_TYP2
from inserted i
JOIN DELETED D
ON 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)
BEGIN
ROLLBACK
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...
Go to Top of Page

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 do

UPDATE WARR_PARTS_RCVD
SET ACT_PARTS_AMT = 0
-- i.e. change ALL rows in table

If 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
Go to Top of Page
   

- Advertisement -