I´m using Delphi 5 with SQL Server 2000 here.
I have created an ADOQuery on top of an updatable view with an INSTEAD OF DELETE trigger.
The updatable view is basically used for controlling soft deletes. It filters out records which are marked as deleted and it hides the controlling column as well.
It all works fine when I´m issuing direct DELETE commands to the database. I delete the record on the view and the underlying table gets updated, doing the soft delete as expected.
When I try to use the ADOQuery to delete a record, it bypasses the view and deletes the record directly on the underlying table, so the instead-of-delete trigger on the view is never fired.
I´m also using referential constraints and the delete is erroring out because of them, but I don´t know if this matters. This does not happen when issuing delete commands to the view.
Would any of you guys know how to work around this annoying behaviour?
Notice that it's deleting directly from the main table instead? This is probably because it's detecting that it's a view and working with the underlying table itself. To prevent this, declare your view WITH VIEW_METADATA, see ALTER VIEW for more information.
Then the ADO library will treat the view as a table. Be aware that you could get unwanted side effects by tricking your DB library like this, such as in cases when the delete isn't actually performed or it does an update instead of a delete.
Related
I am building a database for a CMS system and I am at a point where I am no longer sure which way to go anymore, noting that all of the business logic is in the database layer (We use PostgreSQL 13 and the application is planned to be a SaaS):
1- The application has folders and documents associated with them, so if we move a folder (Or a group of folders in bulk) from its parent folder to another, then the permissions of the folder as well as the underlying documents must follow the permissions of the new location (An update to a permissions table is sent), is this better enforced via an after statement trigger, or do we need to force all of the code to call a single method to move the folder, documents and update their permissions.
2- Wouldn't make more sense to have an AFTER statement trigger rather than an AFTER row trigger in all cases since they do the same thing, but with statement triggers you can process all affected rows in bulk (Thus done more efficiently) , so if I was to enforce inserting a record in another table if an update or an insert takes place, it will have a similar performance for a a single row, but will be a lot faster if they were 1000 rows in the statement level trigger (Since I can easily do INSERT INTO .. SELECT * FORM new_table).
You need a row level trigger or a statement level trigger with transition tables, so that you know which rows were affected by the statement. To avoid repetition, the latter might be a better choice.
Rather than modifying permissions whenever you move an object, you could figure out the permissions when you query the table by recursively following the chain of containment. The question here is if you prefer to do the extra work when you modify the data or when you query the data.
I'm building a quite complex database and in order to simplify some queries I made a view that involves a lot of joined tables. I need to receive a notification whenever a row is added / modified / deleted in the view. Using postgresql 9.2 I first though about the new feature: triggers on view, introduced in pg 9.1. However this doesn't do what I need, since this feature only offers a trigger that is fired when an insert/update/delete is performed directly on the view.
Long story short: I need something (triggers or else) that, looking directly on the view, will notify me when my view is updated (I mean indirectly: when one of the tables which composes the view is modified). Is there something easy to use or I have to manually set a trigger for each table that is involved in the creation of the view?
Thanks in advance!
Feature what you want doesn't exist. You need to write your own a set of triggers on interesting tables.
If you can figure out this one you are a true SQL guru! It's one of the weirdest things I've ever seen.
I've added a trigger to a table in our database. The server is SQL 2008. The trigger doesn't do anything particularly tricky. Just changes a LastUpdated field in the table when certain fields are changed. It's a "After Update" trigger.
There is a large C++ legacy app that runs all kind of huge queries against this database. Somehow (I've got absolutely no idea how) it is deleting this trigger. It doesn't delete any other triggers and I'm certain that it's not explicitly dropping the trigger or table. The developers of this app don't even know anything about my triggers.
How is this possible??
I've tried running a trace using SQL Server Profiler and I've gone through each command that it's sending and run them using SQL Management Studio but my trigger is not affected. It only seems to happen when I run the app. WTF :(
UPDATE:
Sorry I don't want to waste your time. I just realised that if I change the name of the trigger then it doesn't get deleted. Furthermore if I modify the trigger so it doesn't do anything at all then it still gets deleted. From this I can only guess that the other devs are explicitly deleting it but I've searched the trace for the trigger name and it's not there. I'll hassle them and see what they say. Thanks for the suggestions.
UPDATE 2:
The other devs reckon that they are not deleting it explicitly. It doesn't exist in sys.objects or sys.triggers so it's not a glitch with SSMS. So confused :( Guess I'll just rename it and hope for the best? Can't think of anything else to try. A few comments below have asked if the trigger is being deleted or just disabled or not working. As I stated, it's being deleted completely. Also, the problem is not related to the actual contents of the trigger. As I stated, it I remove the contents and replace with some extremely simple code that doesn't do anything then it is still deleted.
Cheers
Mark
Thoughts:
To delete a trigger requires ALTER permission = shouldn't be used by an app
Triggers can be disabled with ALTER TABLE
Triggers can be confused by testing for ##ROWCOUNT at the beginning to trap dummy updates etc
Is the trigger coded for single rows only and appears not to run
Does the trigger exists in sys.objects/sys.triggers: don't rely on Object Explorer in SSMS
A trigger can be deleted if the table is dropped and re-created
A trigger won't fire for TRUNCATE TABLE
I had an identical issue which I tracked down to a creation script missing a final GO statement.
Script 1
IF EXISTS (....)
DROP PROC MyProc
GO
CREATE PROC MyProc
.....
/* GO statement is missing */
Script 2
IF EXISTS (....)
DROP TRIGGER MyDisappearingTrigger
GO
CREATE TRIGGER MyDisappearingTrigger
.....
GO
When I inspected MyProc in the object explorer it looked like this:
CREATE PROC MyProc
AS
...
IF EXISTS (....)
DROP TRIGGER MyDisappearingTrigger
GO
So this meant that every time the stored proc was called the trigger was also deleted.
check with MERGE command in table it will cause triggers get error
Pretty general question regarding triggers in SQL server 2005.
In what situations are table triggers fired and what situations aren't they?
Any code examples to demonstrate would be great.
I'm writing a audit based databases and just want to be aware of any situations that might not fire off the triggers that I have set up for update, delete and insert on my tables.
A example of what I mean,
UPDATE MyTable SET name = 'test rows' WHERE id in (1, 2, 3);
The following statement only fires the update trigger once.
When do you want them to fire?
CREATE TRIGGER AFTER ACTION
That runs after the action (insert update delete) being committed. INSTEAD OF fires the trigger in place of the action.
One of the biggest gotchas with triggers is that they fire whenever an action is performed, even if no rows are affected. This is not a bug, and it's something that can burn you pretty quickly if you aren't careful.
Also, with triggers, you'll be using the inserted and deleted tables. Updated rows are listed in both. This throws a lot of folks off, because they aren't used to thinking about an update as a delete then insert.
The MSDN documentation actually has a pretty in-depth discussion about when triggers fire and what effect they have here.
On 2008 you can use built in Change Data Capture
Also There are quite a few situations when triggers do not fire, such as:
· A table is dropped.
· A table is truncated.
· Settings for nested and/or recursive triggers prevent a trigger from firing.
· Data is bulk loaded, bypassing triggers.
The following statement only fires the update trigger once.
Any action type statement only fires the trigger once no matter how many rows are affected, triggers must be written to handle multiple row inserts/updates/deletes.
If your trigger depends on only one row at a time being in the inserted or deleted pseudotables, it will fail. And worse it will not fail with an error, it will simply not affect all the rows you want affected by whatever the trigger does. Do not fix this through a loop or a cursor in a trigger, change to set-based logic. A cursor in a trigger can bring your entire app to a screeching halt while a transaction of 500,000 records processes and locks up the table for hours.
Bulk inserts by pass triggers unless you specify to use them. Be aware of this because if you let them by pass the trigger you will need code to make sure whatever happens in the trigger also happens after the bulk insert. Or you need to call the bulk inserts with the FIRE_TRIGGERS option.
I thought I'd highlight from the link Eric posted a situation in which a trigger would not fire:
Although a TRUNCATE TABLE statement is in effect a DELETE, it cannot activate a trigger because the operation does not log individual row deletions. However, only those with permissions on a table to execute a TRUNCATE TABLE need be concerned about inadvertently circumventing a DELETE trigger with a TRUNCATE TABLE statement.
Update: My problem doesn't seem to be with the SQL server. I executed an update statement inside the database manually against the view and I was able to update the Bar table. I'll close this and research the OleDbDataAdapters more since I think the problem lies with them.
This question applies to MS SQL Server 2000. How do I determine which table of the multitable view can be modified?
I have the following view:
CREATE VIEW dbo.MyView
AS
SELECT dbo.Foo.Id, dbo.Bar.Id, dbo.Foo.column1, dbo.Foo.column2,
dbo.Foo.column3, dbo.Bar.column1, dbo.Bar.column2,
dbo.Bar.column3
FROM dbo.Bar INNER JOIN
dbo.Foo ON dbo.Bar.Id = dbo.Foo.ForeignId
When I update this view, (using VB.NET OleDbDataAdapters), I can update columns of Foo, but not columns of Bar. My investigation into this tells me that in a multitable view like this that MS SQL server only allows you to update one of the tables. So my question is, how does SQL server determine which table can be updated?
I tried a test where I edit the fields of a particular row from the view. Afterwards, I used the OleDbDataAdapter to update the view. Only the edits to the Foo table were accepted. The edits to the Bar table were ignored (no exception thrown).
Is there a way to predict which of the tables can be updated or a way to control which one? What if I wanted Bar to be the updateable table instead of Foo?
Update: I found this on google, MS SQL Server 2000 Unleased:
http://books.google.com/books?id=G2YqBS9CQ0AC&pg=RA1-PA713&lpg=RA1-PA713&dq=ms+sql+server+"multitable+view"++updated&source=bl&ots=ZuQXIlEPbO&sig=JbgdDe5yU73aSkxh-SLDdtMYZDs&hl=en&ei=b-0SSq-aHZOitgPB38zgDQ&sa=X&oi=book_result&ct=result&resnum=1#PRA1-PA713,M1
(For some reason the URL I'm trying to paste doesn't work with this site, sorry that you have to copy&paste.)
Which says:
An update through a multitable view cannot affect more than one underlying base table.
A delete cannot be executed against multitable views.
But, I don't yet see an answer to my question.
Again, my question is:
How do I determine which table of the multitable view can be modified?
I realize I can write two update statements one for each table. My concern is different. I need to audit code that uses views like the one above and does updates on the views. I was hoping to find a way to determine which parts of the updates will be silently ignored.
Example:
I edit Bar.Column1 and then call the Update() method of the OleDbDataAdapter. This results in the Bar table not being modified nor is an exception thrown. If I edit Foo.Column2 then call Update() the Foo table does get modified.
You can update any table in the view, but only fields that are all in the same table in that statement. If you need to update fields from two tables in a view, then you must write two update statements.
Personally I prefer not to update or delete from views at all. I use the base tables for that.
There are also rules concerning whether view is updateble. See Books online. Search for this:
views-SQL Server, modifying data
You need to be able to uniquely identify the row in the table by returning the primary key. Try returning dbo.Bar.Id in the view, and you should be able to edit columns in table Bar.