I'm trying to add a simple trigger to a table- the 1st issue i came accross was that this table has text columns - so the for delete, insert, update triggers aren't going to float. 'instead of' does though.
I am now up against the fact that the table has cascades set on it. Do you know if there's a way to get around that little gem or am I basically fubared?
Create a new table, which everyone uses instead of the cascading table. Then build your "instead of" trigger onto the new table, and update the old table within the trigger.
The old table will cascade as normal, but your new table doesn't have any cascades.
UPDATE:
You could try adding a view rather that creating another table. You could even exclude those text columns from the view.
I don't know what version of SQL Server you are on but text columns are deprecated - they will NOT be in the next version of SQL Server. If you are on any version higher than 2000, I would suggest you make it an immediate prioroity to fix those by making them nvarchar(max) (You will also need to change code that uses CONTAINS, WRITETEXT and other text type code).
That said, I always got the value of text column in a trigger by joining inserted to the actual table itself on the primary key.
I'm not sure what to do about your cascade question as we do not allow cascade delete or update for performance reasons. As far as I can tell triggers will still fire (and should definitely be written to handle multiple record inserts, updates or deletes, but I strongly feel all triggers should be written this way). What problem exactly are you running into with the cascades?
Related
I would like to mark a record as deleted instead of actually deleting a record.
My intention is to use an instead of trigger, but I am getting an SQLException that neither I nor Google know how to solve this.
My code:
CREATE TRIGGER IF NOT EXISTS <Trigger>
INSTEAD OF DELETE ON <Table>
FOR EACH ROW
BEGIN
UPDATE <Table>
SET Status = 'D'
WHERE ID = old.ID;
END
My Error:
java.sql.SQLException: cannot create INSTEAD OF trigger on table: main.<Table>
at org.sqlite.NativeDB.throwex(NativeDB.java:210)
at org.sqlite.NativeDB._exec(Native Method)
at org.sqlite.Stmt.executeUpdate(Stmt.java:152)
Assist me, please?
EDIT:
What I really wanted was to activate foreign key enforcement.
Refer here: How do you enforce foreign key constraints in SQLite through Java?
You cannot use INSTEAD OF triggers on tables, and when RAISE-ing an error in BEFORE/AFTER triggers, any updates done in the trigger would also be rolled back.
You could rename your table, create a view for that table, and create lots of INSTEAD OF triggers to implement all the INSERT/UPDATE/DELETE operations.
However, it would be much easier to change your program to just execute the UPDATE when it wants to mark some record.
Instead of triggers are intended for use with views so that you can specify the underlying tables that an action should be carried out on when an insert, update our delete is issued on the view itself.
One thing you could try is to do a before delete trigger then raise an exception. The only thing is I'm not sure if this would also interfere with the update. Maybe worth a try though:
SELECT RAISE(ABORT, 'Prevent delete');
I'm using triggers on my sql database to capture change information for a table, it seems to be having a problem with nhibernate though.
The table has a few columns and primary keys and triggers on it. The triggers look like this
CREATE TRIGGER [dbo].[tr_Instrument_update] ON [dbo].[Instrument] FOR UPDATE AS
BEGIN
INSERT [MyAudit].[audit].[Instrument]
SELECT 'Updated', i.*
FROM inserted
INNER JOIN [MyAudit].[dbo].[Instrument] i ON inserted.[InstrumentID] = i.[InstrumentID]
END
Basically on every change we copy the row into the audit table. I have tested and if I modify the data directly through sql management studio triggers function correctly and I get data written to the audit table, however if i update through my app I get the following:
NHibernate.StaleObjectStateException
was unhandled by user code
Message=Row was updated or deleted by
another transaction (or unsaved-value
mapping was incorrect)
I assume this is because the trigger updates another table in another database, is there anyway to make nhibernate ignore this as the change will not affect any of its data, in our mappings we have no reference to this audit data.
Figured out that the trigger was causing Nhibernate to do two identical update calls for some reason. The solution was to SET NOCOUNT ON inside the trigger. Still not sure though why nhibernate makes two updates!
If you create a new trigger in MS SQL Management Studio by using the GUI, it gives you this template:
--====================================
-- Create database trigger template
--====================================
USE <database_name, sysname, AdventureWorks>
GO
IF EXISTS(
SELECT *
FROM sys.triggers
WHERE name = N'<trigger_name, sysname, table_alter_drop_safety>'
AND parent_class_desc = N'DATABASE'
)
DROP TRIGGER <trigger_name, sysname, table_alter_drop_safety> ON DATABASE
GO
CREATE TRIGGER <trigger_name, sysname, table_alter_drop_safety> ON DATABASE
FOR <data_definition_statements, , DROP_TABLE, ALTER_TABLE>
AS
IF IS_MEMBER ('db_owner') = 0
BEGIN
PRINT 'You must ask your DBA to drop or alter tables!'
ROLLBACK TRANSACTION
END
GO
Should I use this template?
I dont know anything about triggers, but I think I need to use them. The purpose in this case is that on an insert to the table, I need to update one of the fields.
Please help me get started!
OK to begin with that is the wrong template if you want an ordinary trigger that one is a trigger on making structural changes to the table itself.
If you decide to do a trigger that affects data (as opposed to structure), there are several things you need to know. First and by far the most critical, triggers operate on sets of data not one row at time. You must write any trigger to handle multiple row inserts.updates or deletes. If you end up with any code setting the value in inserted or deleted to a variable, there is a 99% chance it will not work properly if multiple records are involved.
What is inserted or deleted you ask? That is the next thing you need to know about triggers, there are two pseudotables (inserted and deleted) that are only available in a trigger (or an output clause) which contain the new information being inserted or the updated values (in the inserted table) and the old information being deleted or being changed by an update (in the deleted table). So an insert has values in inserted, a delete has values in deleted and an update has values in both. Use these in your trigger to pull the values you need to change.
Since you don't know anything about triggers, I would say no, don't use the template.
Read the books online page for Create Trigger and write the trigger by hand.
There is probably more in that template code than you actually need. Read the manual and keep it simple.
If you don't know anything about triggers then I would strongly suggest that you read up on them before implementing them. Get Triggers right and they can make your life a lot easier; get it wrong and Triggers will cause you a lot of trouble.
I would suggest starting off with this tutorial
http://www.sqlteam.com/article/an-introduction-to-triggers-part-i
You can use the above SQL as a template or you can simply write your own. I would suggest you write your own as you'll understand what you are doing. Obviously only do this after you have done some serious reading on triggers. Check out MSDN too
I am currently not in a location to test any of this out but would like to know if this is an option so I can start designing the solution in my head.
I would like to create an insert trigger on a table. In this insert trigger, I would like to get values from the inserted virtual table and use them to UPDATE the same table. Would this work or would we enter some kind of infinite loop (even though the trigger is not for update commands).
As an example if a row was inserted (which represents a new rate/cost for a vendor) I would like to update the same table to expire the old rate/cost for that vendor. The expiration is necessary vs updating the record that already exists so a history of rates/costs can be kept for reporting purposes (not to mention that the current reporting infrastructure expects this type of thing to happen and we are migrating current reports/data to SQL Server).
Thanks!
If you have only an INSERT trigger and no UPDATE trigger then there isn't any problem, but I assume you want to catch also UPDATEs and perhaps even DELETEs.
The INSTEAD OF triggers are guaranteed not to behave recursively:
If an INSTEAD OF trigger defined on a
table executes a statement against the
table that would ordinarily fire the
INSTEAD OF trigger again, the trigger
is not called recursively
With and INSTEAD OF trigger you must do both the original INSERT and the UPDATE you desire.
This doesn't sound like it would cause any problems to me, providing you're not doing an INSERT in another UPDATE trigger.
I want to create a table trigger for insert and update. How can I get the values of the current record that is inserted/updated?
within the trigger, you can use a table called 'inserted' to access the values of the new records and the new version of the updated records. Similarly, the table called 'deleted' allows you to access deleted records and the original versions of updated records.
using function 'update' on column ( if you wanna check the fact of update) or retrieving rows from table 'inserted'
While triggers can be used for this, I'd be very careful about deciding to implement them. They are an absolute bear to debug, and can lead to a lack of maintainability.
if you need to do cascading updates (i.e. altering table A in turn changes table B), I would either use a stored procedure (which can be tested and debugged more easily than a trigger), or if you're fortunate enough to be using an ORM (Entity framework, NHibernate, etc.) perform this function within your model or repository.