Click here to Skip to main content
15,889,116 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
Hi,

i wanted to write a SQL trigger on update and when parent table is updated all child tables through fk/pk-key-constraint having field name isLocked (data type bit - true or false).

table structures like below:


--- table 1 (has field isLocked)
     --- table 1a (has field isLocked)
            --- table 1ax (has field isLocked)
            --- table 1ay
            --- table 1az (has field isLocked)
     --- table 1b
     --- table 1c (has field isLocked)
            --- table 1cxy
--- table 2 (has field isLocked)
     --- table 2a



In above example I wanted to write a trigger on table 1 on update and find all child tables of table 1 having field isLocked and update field isLocked = true.

Any help on this issue will be highly appreciated.

Thanks in advance.

regards

[Tshencho]
Bhutan
Posted
Updated 24-Apr-13 21:54pm
v5

1 solution

Here's one way of doing it ...
SQL
IF OBJECT_ID('Update_table_1','TR') is not null
	DROP TRIGGER Update_table_1
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TRIGGER Update_table_1
	ON  [table 1] AFTER UPDATE  
AS 
BEGIN
	SET NOCOUNT ON;
	
	-- identify child tables of this table ([table 1]) that have a column isLocked
	-- NB we know the name of the parent table as that's the one we're putting the trigger on :-)
	-- Alternatively you could maintain a table with these relationships defined and just query that
	select C.name 
	into #children 
	from sysforeignkeys A
	join syscolumns B on A.fkeyid=B.id and A.fkey=B.colid
	join sysobjects C on A.fkeyid=C.id
	where rkeyid = (select id from sysobjects where name = 'table 1')
	and fkeyid in (select id from syscolumns where  name = 'id')

	declare @tname varchar(50)	-- table name
	declare @sql varchar(1024)	-- dynamic sql statement
	declare @id int			-- id of a row changed on [table 1]
	
	-- step through all of the child tables building up the sql to update them
	declare cur1 cursor for
		SELECT name from #children
	open cur1
	fetch next from cur1 into @tname
	while @@FETCH_STATUS = 0
	begin
			-- step through the keys of the changed rows
			declare curkeys cursor for
				select id from inserted	-- inserted table contains all the rows affected by the update
				-- replace "id" with the pk column name on table 1
			open curkeys
			fetch next curkeys into @id
			while @@FETCH_STATUS = 0
			begin
				-- replace "id" here with the fk column name on child tables
				set @sql = 'update ' + @tname + ' set isLocked = 1 where id = ' + @id
				exec(@sql)
				fetch next from curkeys into @id
			end
			close curkeys
			deallocate curkeys
		fetch next from cur1 into @tname
	end
	drop table #children
	close cur1
	deallocate cur1
END


If the child tables have different column names as the foreign keys "pointing" back to the parent then you can find out what those column names are with something similar to this ...
SQL
DECLARE @ForId varchar(200)
SET @ForId = (select COLUMN_NAME from INFORMATION_SCHEMA.KEY_COLUMN_USAGE
    WHERE CONSTRAINT_NAME LIKE 'FK%' AND TABLE_NAME = @tname)
PRINT @ForId

and then change the dynamic sql to something like
SQL
@sql = 'update ' + @tname + ' set isLocked = 1 where ' + @ForId + ' = ' + @id

I didn't amend the sql above as it was easier just to show you how you can get this info.
Note that this will only work if you have a single-column primary key on your tables - now that you know the name of the sql view Google can provide more complex examples if you need them.
Also note that information_schema is a better approach than using sysobjects (or sys.objects for later versions) as it is less likely to change.
 
Share this answer
 
v2
Comments
CringTee 23-May-13 4:56am    
Thanks CHill60. There is 1 problem in the solution in the where clause of@sql clause ('where id =' @id). Here i got with different name in each table for id field. so how can i get field id dynamically and use @pkID instead of 'id' in where clause. Thanks in advance.
CHill60 23-May-13 10:09am    
I've added some more info to the end of my solution that should point you in the right direction - warning - it's untested as I can't get to a sql instance at the moment
CringTee 27-May-13 3:14am    
Still then thanks for the information.
CringTee 27-May-13 4:48am    
Hi CHill60,
it almost solved 1 of my problem and i tested with your query
select COLUMN_NAME from INFORMATION_SCHEMA.KEY_COLUMN_USAGE
WHERE CONSTRAINT_NAME LIKE 'FK%' AND TABLE_NAME = @tname
and it returns all the fk fields not the fk of parent table it is giving error, i understood the error but dont know how to select the fk field of its parent table only not all fks.
thanks in advance....
CHill60 28-May-13 6:10am    
Sorry @tname should have read [table 1] i.e. the name of the table that you are putting the trigger on

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900