This is occurring because when you have both a foreign key with CASCADE
action and triggers, the actions occur in the following order. First the
update/delete on the original table and all the casading updates or deletes
are done, second, the trigger is called on the original table (even if no
rows were actually deleted or updated), and finally, the triggers are called
on the cascaded tables, but only if one or more rows were deleted or updated
in that table.
So the row in ABC is gone by the time you get to the XYZ trigger (for that
matter, so are the rows in XYZ, but in that case you have the deleted table
available to find the original values). AFAIK, there is no way to change
this. If you need this value for auditing and cannot get it in any other
way than the row in the ABC table (maybe it is enough to have the ABC
trigger audit it?), probably your best bet is to get rid of the CASCADE
option on the foreign keys and do the deletes/updates through stored
procedures that do all the deletes, updates, and auditing in the correct
order so you save the data you need and the foreign key constraints are
never violated.
Incidently, there is a common flaw in your trigger logic. Triggers are
called once per statement, not once per row. If a statement
inserts/updates/deletes multiple rows, then the inserted and/or deleted
tables will have multiple rows in them. If, for example, you deleted a row
from ABC, and that cascaded to delete 5 rows from XYZ, then the XYZ trigger
would be called only one time with 5 rows in the deleted table. But your
code would only audit one of them. It is good practice to always write
triggers so that they work if the inserted/deleted tables have multiple
rows.
Tom
[quoted text, click to view] "Sacher" <sacherdos@rediffmail.com> wrote in message
news:1159331541.881822.263040@m73g2000cwd.googlegroups.com...
> Hello all,
>
> We have a parent table (say ABC) and its child table(say XYZ). The
> sturctures are simple as shown below.
>
> ABC
> 1. abc_id
> 2. abc_name
>
> XYZ
> 1. xyz_id
> 2. xyz_name
> 3. abc_id_fk (foreign key relation with abc_id of abc table)
>
> So there is a foreign key in XYZ table. ON DELETE CASCADE is set for
> the parent. So when I delete a record in ABC table, related records
> from XYZ also is removed. This is fine.
>
> In the DELETE trigger of XYZ (child), we are trying to access the
> parent record for the record currently being deleted (this is to get
> the NAME_ABC for kind of logging). The full trigger is as follows:
>
> CREATE TRIGGER dbo.trgTest
> ON dbo.xyz
> AFTER DELETE
> AS
> BEGIN
> SET NOCOUNT ON;
> Declare @idno int
> Declare @fkid int
> Declare @sAddinfo varchar(50)
>
> Select @idno=xyz_id ,@fkid = abc_id_fk from deleted
> Select @sAddinfo=abc_name from abc where abc_id=@fkid
>
> INSERT INTO [dbo].DeleteLog
> VALUES
> (
> 'xyz',
> @idno,
> GETDATE(),
> USER_NAME(),
> @sAddInfo
> );
>
> END
> GO
> When I delete a record directly from the child XYZ table, this works
> fine. But if I delete a record from parent ABC thereby causing a
> cascade, this does not work. The " Select @sAddinfo=abc_name from abc
> where abc_id=@fkid " does not return anything and seems that this query
> fails. And subsequently, the next step of INSERT fails since there is a
> NULL value constraint in the DeleteLog table.
> The same problem occurs if we try to do the same work for a CASCADE
> UPDATE too.
>
> Anybody has an idea why such a problem occurs and how we should do this
> correctly?
>
> Any suggestion is appreciated.
>
> Regards,
> Sacher
>