473,549 Members | 2,734 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

Trigger failing after table structure change

Hello,

I have created the following trigger:

CREATE TRIGGER tr_UDFTest ON UserDefinedFiel ds FOR INSERT, UPDATE
AS
DECLARE @foobar varchar(100)

SELECT @foobar= foobar FROM inserted
IF ( @foobar = 'foobar') INSERT INTO LogTable (LogText) values ('Found foobar')
ELSE INSERT INTO LogTable (LogText) values ('Did not find foobar')
GO
Basically, the trigger monitors the values begin put in the foobar field,
and acts accordingly based on what it finds. In practice, my needs are a
bit more complex (the trigger will be programmaticall y generated, based on
a set of rules) but the principle is much the same.

ErrorTable is defined as :

create table LogTable (LogText varchar(128))

UserDefinedFiel ds is a table whose definition may change depending on the
user's needs, but for now assume it contains a varchar column called
foobar.

My problem is that if the user's needs change, and they remove the field
foobar, the trigger causes all subsequent inserts/updates to fail with an
error indicating the column foobar doesn't exist. (Which makes sense of
course!)

CREATE TRIGGER tr_UDFTest ON UserDefinedFiel ds FOR INSERT, UPDATE
AS
DECLARE @foobar varchar(100)

if not exists (select * from syscolumns sc inner join sysobjects so on sc.id = so.id
where sc.name = 'foobar'
and so.name = 'UserDefinedFie lds') BEGIN
INSERT INTO LogTable (LogText) values ('Error : Foobar column does not exist!')
RETURN
END

SELECT @foobar= foobar FROM inserted
IF ( @foobar = 'foobar') INSERT INTO LogTable (LogText) values ('Found foobar')
ELSE INSERT INTO LogTable (LogText) values ('Did not find foobar')
GO
I'd be happy with the above 'flavor' of solution (bailing, or logging an
error and bailing, when we hit unexpected problems) as long as the
inserts/updates don't fail otherwise. Perhaps I can nest a transaction, or
supress a RAISEERROR or something?

The cleanest solution would probably be to change a bunch of client
software such that it won't remove the foobar field if this field is
needed for a trigger (foreign key constraints based on the set of rules
I'm using are a nice and intuitive solution). Unfortunately, that doesn't
work well with my timeframe (done by thursday) as changing the client
software is impossible by then. Any ideas or suggestions? Platform is
Win2k, SQL 2000 Enterprise (I think enterprise, certainly 2000).

thanks,
Dave

Jul 20 '05 #1
6 3437
On Fri, 17 Oct 2003, Dave C. wrote:
My problem is that if the user's needs change, and they remove the field
foobar, the trigger causes all subsequent inserts/updates to fail with an
error indicating the column foobar doesn't exist. (Which makes sense of
course!)

CREATE TRIGGER tr_UDFTest ON UserDefinedFiel ds FOR INSERT, UPDATE
AS
DECLARE @foobar varchar(100)

if not exists (select * from syscolumns sc inner join sysobjects so on sc.id = so.id
where sc.name = 'foobar'
and so.name = 'UserDefinedFie lds') BEGIN
INSERT INTO LogTable (LogText) values ('Error : Foobar column does not exist!')
RETURN
END

SELECT @foobar= foobar FROM inserted
IF ( @foobar = 'foobar') INSERT INTO LogTable (LogText) values ('Found foobar')
ELSE INSERT INTO LogTable (LogText) values ('Did not find foobar')
GO


Oops, deleted a sentence. In case is wasn't clear, the second trigger
definition (quoted above) was a workaround that I tried, but which
was not successful, but whose 'flavor' (logging an error and otherwise
continuing with the insert/update) I'd be happy with.

Dave

Jul 20 '05 #2
Dave C. (me***@rules.sp am) writes:

CREATE TRIGGER tr_UDFTest ON UserDefinedFiel ds FOR INSERT, UPDATE
AS
DECLARE @foobar varchar(100)

SELECT @foobar= foobar FROM inserted
IF ( @foobar = 'foobar') INSERT INTO LogTable (LogText) values
('Found foobar')
ELSE INSERT INTO LogTable (LogText) values ('Did not find foobar')
GO
There is a problem with this trigger. If more than one row is inserted
or updated in the same statement, you are only logging one of these
rows, since a trigger fires once per statement.
My problem is that if the user's needs change, and they remove the field
foobar, the trigger causes all subsequent inserts/updates to fail with an
error indicating the column foobar doesn't exist. (Which makes sense of
course!)
And the entire transaction is rolled back, so there is no risk that
any data is updated without be audited.
The cleanest solution would probably be to change a bunch of client
software such that it won't remove the foobar field if this field is
needed for a trigger (foreign key constraints based on the set of rules
I'm using are a nice and intuitive solution). Unfortunately, that doesn't
work well with my timeframe (done by thursday) as changing the client
software is impossible by then. Any ideas or suggestions? Platform is
Win2k, SQL 2000 Enterprise (I think enterprise, certainly 2000).


If I understand this you have some tables that the user can change on
the fly. That sounds like a bad design to me. When you change a table,
for instance drop a column, any codes that refer to that column needs
to be revised. Seems like you should consider regenerate that trigger
in some automatic fashion.

You should also investigate third party tools. The best tools for auditing
are probably SQL Audit (www.redmatrix.com) and Entegra (www.lumigent.com).
SQL Audit works with triggers, whereas Entegra works from the transaction
log.
--
Erland Sommarskog, SQL Server MVP, so****@algonet. se

Books Online for SQL Server SP3 at
http://www.microsoft.com/sql/techinf...2000/books.asp
Jul 20 '05 #3
On Sun, 19 Oct 2003, Erland Sommarskog wrote:
There is a problem with this trigger. If more than one row is inserted
or updated in the same statement, you are only logging one of these
rows, since a trigger fires once per statement.
Yes, I know. I was trying to get the simple case of a single row
update/insert working first, then it would be a relatively simple step to
extend it to the multiple case. Thanks, though.

My problem is that if the user's needs change, and they remove the field
foobar, the trigger causes all subsequent inserts/updates to fail with an
error indicating the column foobar doesn't exist. (Which makes sense of
course!)


And the entire transaction is rolled back, so there is no risk that
any data is updated without be audited.


In this case, rolling back the transaction would cause undesirable
behavior in an end user GUI app, which I want to avoid. This entire issue
is part of a short term customization for a single customer, and it's more
important for me to keep the standard software working as expected than
audit the data (the decision being made here is of relatively minor
importance).

If I understand this you have some tables that the user can change on
the fly. That sounds like a bad design to me. When you change a table,
for instance drop a column, any codes that refer to that column needs
to be revised. Seems like you should consider regenerate that trigger
in some automatic fashion.
You are absolutely right on all counts. Problems are that I didn't write
the original software, just this customization, and that this
customization needs to be in place by thursday. Regenerating the trigger
at the right time would involve changes to the standard software release,
rather than just this cusomtization, and there's not way I could put that
change into effect by then (it's not under my control!). If this isn't
done by thursday, we don't get paid, etc etc etc. As much as I agree with
you ideally, I can't implement the correct solution as you suggest. So
basically I was looking for a way to not have the trigger completely roll
back the transaction, and runtime checking of the existence of the column,
like the following, wasn't working as I had hoped:
if not exists (select * from syscolumns sc inner join sysobjects so on sc.id = so.id
where sc.name = 'foobar'
and so.name = 'UserDefinedFie lds') BEGIN
INSERT INTO LogTable (LogText) values ('Error : Foobar column does not exist!')
RETURN
END


I suspect it was because the trigger is compiled ahead of time, but I am
not sure.

Dave

Jul 20 '05 #4
Dave C. (me***@rules.sp am) writes:
In this case, rolling back the transaction would cause undesirable
behavior in an end user GUI app, which I want to avoid. This entire issue
is part of a short term customization for a single customer, and it's more
important for me to keep the standard software working as expected than
audit the data (the decision being made here is of relatively minor
importance).


One alternative would be set up replication and do the auditing in the
data in the replicated database. That is the triggers would be over
there and not in the source database. If you try to an audit a column
that does not exist, I would guess holds up replication, but you are
not disrupting the GUI. Since you would have to stop and restart
replication, you would lose auditing.

Now, replication is nothing to take lightly, and you may not get it
working smoothly by Thursday. And there will be issue for future
changes to the database.

The only other alternative is to use dynamic SQL, but this too requires
carefulness:

IF col_length('tbl ', 'col') IS NOT NULL
BEGIN
INSERT LogTable (LogText)
EXEC ('IF EXISTS (SELECT * FROM #tbl_inserted
WHERE fobar = ''fobar'')
SELECT ''Found "fobar"''
ELSE
SELECT ''Did not find "fobar"''')
END

#tbl_inserted is here created in the beginning of the trigger with

SELECT * INTO #tbl_inserted FROM inserted

Make sure that the name of the temp table is unique for each trigger,
in case triggers cascade.

col_length() is a trick to avoid direct refernces to the system tables.

If you have never used dynamic SQL before, there are a couple of things
you need to know before you start hacking. I have an article on my web
site on this topic: http://www.algonet.se/~sommar/dynamic_sql.html.
--
Erland Sommarskog, SQL Server MVP, so****@algonet. se

Books Online for SQL Server SP3 at
http://www.microsoft.com/sql/techinf...2000/books.asp
Jul 20 '05 #5
On Mon, 20 Oct 2003, Erland Sommarskog wrote:
One alternative would be set up replication and do the auditing in the
data in the replicated database. That is the triggers would be over
there and not in the source database. If you try to an audit a column
that does not exist, I would guess holds up replication, but you are
not disrupting the GUI. Since you would have to stop and restart
replication, you would lose auditing.

Now, replication is nothing to take lightly, and you may not get it
working smoothly by Thursday. And there will be issue for future
changes to the database.
I can see how that would work. I've actually done a great deal of work
wit replication, and in this case I feel it would make the problem *much*
more complex than it needs to be.

The only other alternative is to use dynamic SQL, but this too requires
carefulness:
I like this idea, actually.

IF col_length('tbl ', 'col') IS NOT NULL
BEGIN
INSERT LogTable (LogText)
EXEC ('IF EXISTS (SELECT * FROM #tbl_inserted
WHERE fobar = ''fobar'')
SELECT ''Found "fobar"''
ELSE
SELECT ''Did not find "fobar"''')
END

#tbl_inserted is here created in the beginning of the trigger with

SELECT * INTO #tbl_inserted FROM inserted

Make sure that the name of the temp table is unique for each trigger,
in case triggers cascade.
Wow! I really should have thought of trying 'Select Into' on my own. I
believe this is exactly what I was looking for, since the dynamic SQL
should allow me to analyze table structures at run time and act
accordingly. Thanks a great deal for your help.

col_length() is a trick to avoid direct refernces to the system tables.
Thanks again, this is a useful tip I'm sure I'll use again.
If you have never used dynamic SQL before, there are a couple of things
you need to know before you start hacking. I have an article on my web
site on this topic: http://www.algonet.se/~sommar/dynamic_sql.html.


The article is is good one. Luckily for me, I do not expect performance or
any of the other considerations you list to be a problem in this
particular case.

Dave

Jul 20 '05 #6
Dave C. (me***@rules.sp am) writes:
The article is is good one. Luckily for me, I do not expect performance or
any of the other considerations you list to be a problem in this
particular case.


Be very careful with complex code in a trigger, because in a trigger you
are always in the context of a transaction, which means that you are holding
locks. Of course, if this is an application where the users only
occasionally makes some updates, this is not much of an issue. But in a
busy system with data arriving in real-time, you could get contention
issues.
--
Erland Sommarskog, SQL Server MVP, so****@algonet. se

Books Online for SQL Server SP3 at
http://www.microsoft.com/sql/techinf...2000/books.asp
Jul 20 '05 #7

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

2
4191
by: Trevor Fairchild | last post by:
I am trying to create a very minimal auditing system for a series of databases. I am in the process of writing Update triggers for 5 Tablse. I will write a trigger for each table-the trigger's function will be to INSERT a row into my MasterChanges table everytime ANY data is changed in each of the 5 tables. I have set up MasterChanges to...
1
15392
by: shottarum | last post by:
I currently have 2 tables as follows: CREATE TABLE . ( mhan8 int, mhac02 varchar(5), mhmot varchar(5), mhupmj int )
33
4740
by: coosa | last post by:
I have a table: ---------------------------------------------------- CREATE TABLE CATEGORY ( CATEGORY_ID INTEGER IDENTITY(1,1) NOT NULL, CATEGORY_NAME VARCHAR(40) NOT NULL, PARENT_CATEGORY_ID INTEGER, CATEGORY_ICON IMAGE, DEPTH INTEGER,
10
2053
by: Axel | last post by:
Hello, I would like to create a (what I believe is) simple trigger that updates a row in one table based on updates of corresponding fields of same row. Its a "week total" field that sums up values of 7 singular "day" fields. Here is what I have come up with using the TSQL documentation. CREATE TRIGGER trigger_stocksum ON tblStock FOR...
6
9219
by: JohnO | last post by:
Hi Folks, I have an update trigger that fails (it inserts an audit table record) in some circumstances. This is causing the triggering transaction to fail and roll back. Is there any way to prevent this? If the trigger fails I still want the triggering transaction to continue. Cheers, JohnO
2
4958
by: mob1012 via DBMonster.com | last post by:
Hi All, I wrote last week about a trigger problem I was having. I want a trigger to produce a unique id to be used as a primary key for my table. I used the advice I received, but the trigger is still not working correctly. Here is my code: create trigger emp_update_id BEFORE update on emp_update REFERENCING NEW AS N for each row SET...
5
5336
by: wpellett | last post by:
I can not get the SQL compiler to rewrite my SQL UPDATE statement to include columns being SET in a Stored Procedure being called from a BEFORE UPDATE trigger. Example: create table schema1.emp ( fname varchar(15) not null, lname varchar(15) not null, dob date,
2
2380
by: dean.cochrane | last post by:
I have inherited a large application. I have a table which contains a hierarchy, like this CREATE TABLE sample_table( sample_id int NOT NULL parent_sample_id int NOT NULL ....lots of other cols...) DELETEs on all tables are handled by the front end code, which just
6
4419
by: Oliver | last post by:
I'm fairly new to DB2. I have been assigned to build a delete trigger that finds the data type of each of the table's fields so that the trigger can then build a string consisting of OLD values pre-wrapped in quote marks as needed. The deleted record's field values, all strung together as a single string, would then be inserted into a...
0
7720
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers, it seems that the internal comparison operator "<=>" tries to promote arguments from unsigned to signed. This is as boiled down as I can make it. ...
0
7960
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven tapestry of website design and digital marketing. It's not merely about having a website; it's about crafting an immersive digital experience that...
1
7475
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows Update option using the Control Panel or Settings app; it automatically checks for updates and installs any it finds, whether you like it or not. For...
0
7812
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each protocol has its own unique characteristics and advantages, but as a user who is planning to build a smart home system, I am a bit confused by the...
0
6048
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing, and deployment—without human intervention. Imagine an AI that can take a project description, break it down, write the code, debug it, and then...
1
5372
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new presenter, Adolph Dupré who will be discussing some powerful techniques for using class modules. He will explain when you may want to use classes...
0
5089
by: conductexam | last post by:
I have .net C# application in which I am extracting data from word file and save it in database particularly. To store word all data as it is I am converting the whole word file firstly in HTML and then checking html paragraph one by one. At the time of converting from word file to html my equations which are in the word document file was convert...
0
3483
by: adsilva | last post by:
A Windows Forms form does not have the event Unload, like VB6. What one acts like?
1
1944
by: 6302768590 | last post by:
Hai team i want code for transfer the data from one system to another through IP address by using C# our system has to for every 5mins then we have to update the data what the data is updated we have to send another system

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.