Here is a solution based on FULL JOIN. The purpose of the subqueries with INTERSECT is to compare the columns.
EXISTS(A INSERSECT B)
is the same as A = B, but it also works when any of A and B are NULL.
; WITH CTE AS ( SELECT id = isnull(trg.id, src.id), action = CASE WHEN trg.id IS NULL THEN 'Insert' WHEN src.id IS NULL THEN 'Delete' ELSE 'Update' END, details = CASE WHEN trg.id IS NOT NULL AND src.id IS NOT NULL THEN CASE WHEN NOT EXISTS (SELECT trg.description INTERSECT SELECT src.description) THEN 'Description ' ELSE '' END + CASE WHEN NOT EXISTS (SELECT trg.name INTERSECT SELECT src.name) THEN 'Name' ELSE '' END + CASE WHEN NOT EXISTS (SELECT trg.IsActive INTERSECT SELECT src.IsActive) THEN 'IsActive ' ELSE '' END END FROM sourcetbl src FULL JOIN targettbl trg ON src.id = trg.id ) SELECT id, action, details FROM CTE WHERE action IN ('insert', 'delete') OR len(details) > 0
PS Had you posted CREATE TABLE + INSERT with sample data, I would have tested my solution.