I'm trying to intercept any DELETE commands against a particular table. MySQL supports triggers but it doesn't seem to support a way to raise an error yet like SQL Server and other databases.
Can I do this with just an empty Trigger definition? Something like:
create trigger trListsDelete on lists
instead of delete
as
begin
/* Do nothing */
end
In SQL Server I could add a RAISEERROR('You cannot delete lists.') statement to force it to fail and that way I know the Delete wouldn't be executed. Since MySQL doesn't support raising errors, how do I simply ignore the Delete command?
The technique is you do something that will cause an error, such as update a column that doesn't exist.
Details here: MySQL Triggers: How do you abort an INSERT, UPDATE or DELETE with a trigger?
Related
Can SQL Server triggers prevent updating records and allow inserting new records?
Thanks,
Przemek
Couldn't this be accomplished by creating a SQL Server user that has INSERT access on the destination tables but not UPDATE access? Create a new user with no permissions, then:
GRANT INSERT ON [blah] TO [user]
I admit, my knowledge of SQL Server triggers is limited, but this seems like it would work.
To expand on INSTEAD OF UPDATE, this trigger will fire for UPDATE commands. INSERT and DELETE commands work as usual; if you wanted to intercept either of those you'd use an INSTEAD OF INSERT or INSTEAD OF DELETE trigger.
The full solution goes something like this:
CREATE TRIGGER myTable_IO_Upd ON myTable INSTEAD OF UPDATE AS
BEGIN
RAISERROR('myTable does not allow UPDATE queries.', 18, 0);
END;
GO
More information on RAISERROR is here. Basically the second argument (18) is the severity, with 18 being the highest severity allowed for user-defined exceptions. The third argument (0) is the "state", which you don't normally need, hence the zero.
One more example: if you wanted to prevent UPDATE and DELETE, you'd use something like this:
CREATE TRIGGER myTable_IO_Upd ON myTable INSTEAD OF UPDATE, DELETE AS
BEGIN
RAISERROR('myTable does not allow UPDATE or DELETE queries.', 18, 0);
END;
GO
To prevent update on table, you can use "INSTEAD OF UPDATE" Trriger
you can check this note "https://msdn.microsoft.com/en-us/library/aa258254%28SQL.80%29.aspx?f=255&MSPPError=-2147217396"
All we need is to create several pre-insert/update triggers in SQL Server 2008 R2 which do some select * or select count(*) and explicitly fail if it is empty or non-empty.
Please, how to achieve that?
Create an INSTEAD OF INSERT, UPDATE trigger. Now to prevent DML you have 2 options. In the body of trigger execute RAISERROR so your application can catch the error. Another way is not to perform actual insert/update in the trigger, so no records will be inserted/updated, but the user will not know if DML succeeds.
I am in the process of creating a sql server 2008 database table for auditing users actions.
Is it possible to create a database table which can only inserted in to - no truncates, deletes or updates allowed on the data in the table. One option I know of is to use a different user with limited rights, but this isnt option for me. So looking at other options?
You need to create a TRIGGER that fires on UPDATE and DELETE and throws an error:
CREATE TRIGGER user_action_update on UserActions FOR UPDATE, DELETE AS
BEGIN
RAISERROR ('Cannot modify or delete user actions', 16, 1)
ROLLBACK TRAN
RETURN
END
GO
Source: http://msdn.microsoft.com/en-us/magazine/cc164047.aspx
Another way to do that is to Write a trigger creation script for the table and set the action to " INSTEAD OF " which will override the triggering action (unwanted action in your case ) for some other code, or null code.
INSTEAD OF Property
Specifies that the DML trigger is executed instead of the triggering SQL statement, therefore, overriding the actions of the triggering statements.
Here is a link in how to Write the SQL statement for the trigger creation:
http://technet.microsoft.com/en-us/library/ms189799.aspx
Good luck
Adrian
I thought "after delete" meant that the trigger is not fired until after the delete has already taken place, but here is my situation...
I made 3, nearly identical SQL CLR after delete triggers in C#, which worked beautifully for about a month. Suddenly, one of the three stopped working while an automated delete tool was run on it.
By stopped working, I mean, records could not be deleted from the table via client software. Disabling the trigger caused deletes to be allowed, but re-enabling it interfered with the ability to delete.
So my question is 'how can this be the case?' Is it possible the tool used on it futzed up the memory? It seems like even if the trigger threw an exception, if it is AFTER delete, shouldn't the records be gone?
All the trigger looks like is this:
ALTER TRIGGER [sysdba].[AccountTrigger] ON [sysdba].[ACCOUNT] AFTER DELETE AS
EXTERNAL NAME [SQL_IO].[SQL_IO.WriteFunctions].[AccountTrigger]
GO
The CLR trigger does one select and one insert into another database. I don't yet know if there are any errors from SQL Server Mgmt Studio, but will update the question after I find out.
UPDATE:
Well after re-executing the same trigger code above, everything works again, so I may never know what if any error SSMS would give.
Also, there is no call to rollback anywhere in the trigger's code.
after means it just fires after the event, it can still be rolled back
example
create table test(id int)
go
create trigger trDelete on test after delete
as
print 'i fired '
rollback
do an insert
insert test values (1)
now delete the data
delete test
Here is the output from the trigger
i fired
Msg 3609, Level 16, State 1, Line 1
The transaction ended in the trigger. The batch has been aborted.
now check the table, and verify that nothing was deleted
select * from test
The CLR trigger does one select and
one insert into another database. I
don't yet know if there are any errors
from SQL Server Mgmt Studio, but will
update the question after I find out.
Suddenly, one of the three stopped
working while an automated delete tool
was run on it.
triggers fire per batch/statement not per row, is it possible that your trigger wasn't coded for multi-row operations and the automated tool deleted more than 1 row in the batch? Take a look at Best Practice: Coding SQL Server triggers for multi-row operations
Here is an example that will make the trigger fail without doing an explicit rollback
alter trigger trDelete on test after delete
as
print 'i fired '
declare #id int
select #id = (select id from deleted)
GO
insert some rows
insert test values (1)
insert test values (2)
insert test values (3)
run this
delete test
i fired
Msg 512, Level 16, State 1, Procedure trDelete, Line 6
Subquery returned more than 1 value. This is not permitted when the subquery follows =, !=, <, <= , >, >= or when the subquery is used as an expression.
The statement has been terminated.
check the table
select * from test
nothing was deleted
An error in the AFTER DELETE trigger will roll-back the transaction. It is after they are deleted but before the change is committed. Is there any particular reason you are using a CLR trigger for this? It seems like something that a pure SQL trigger ought to be able to do in a possibly more lightweight manner.
Well you shouldn't be doing a select in trigger (who will see the results) and if all you are doing is an insert it shouldn't be a CLR trigger either. CLR is not generally a good thing to have in a trigger, far better to use t-SQL code in a trigger unless you need to do something that t-sql can't handle which is probably a bad idea in a trigger anyway.
Have you reverted to the last version you have in source control? Perhaps that would clear the problem if it has gotten corrupted.
I want that when I execute a query for example DELETE FROM Contact, and an error is raised during the transaction it should delete the rows that are able to be deleted raising all the relevant errors for the rows that cannot be deleted.
For SQL Server you are not going to break the atomicity of the Delete command within a single statement - even issued outside of an explicit transaction, you are going to be acting within an implicit one - e.g. all or nothing as you have seen.
Within the realms of an explicit transaction an error will by default roll back the entire transaction, but this can be altered to just try and rollback the single statement that errored within the overall transaction (of multiple statements) the setting for this is SET XACT_ABORT.
Since your delete is a single statement, the XACT_ABORT can not help you - the line will error and the delete will be rolled back.
If you know the error condition you are going to face (such as a FK constraint violation, then you could ensure you delete has a suitable where clause to not attempt to delete rows that you know will generate an error.
If you're using MySQL you can take advantage of the DELETE IGNORE syntax.
This is a feature which will depend entirely on which flavour of database you are using. Some will have it and some won't.
For instance, Oracle offers us the ability to log DML errors in bulk. The example in the documentation uses an INSERT statement but the same principle applies to any DML statement.