Microsoft SQL Server Database Triggers

I had a requirement where I had to populate a SQL data warehouse for a third party business intelligence tool and part of the requirement was that the data warehouse needs to be in real time. I did some research and found that SQL Triggers is the way to go. I've created a SQL Trigger on all the SQL Tables I needed to get the data from to populate my data warehouse. You can create a SQL Trigger using the following syntax:


IF EXISTS(SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[tr_Main]')  AND Type IN (N'TR'))
BEGIN
 DROP TRIGGER [dbo].[tr_Main]
END
GO

CREATE TRIGGER [dbo].[tr_Main]
   ON  [dbo].[Main]
   AFTER INSERT,DELETE,UPDATE
AS
BEGIN
 IF EXISTS(SELECT * FROM inserted) AND EXISTS(SELECT * FROM deleted)
 BEGIN
   --Action = 'UPDATE'
 END
 ELSE IF EXISTS(SELECT * FROM inserted) AND NOT EXISTS(SELECT * FROM deleted)
 BEGIN
   --Action = 'INSERT'
 END
 ELSE IF NOT EXISTS(SELECT * FROM inserted) AND EXISTS(SELECT * FROM deleted)
 BEGIN
  --Action = 'DELETE'
 END
END

As for the body of my Triggers, Database tables changes (add new columns) because of new software requirements, I wanted to make it as simple and easy as possible so that minimal work or non at all is required on the SQL Triggers should the SQL Table change. What I did was, I've created a SQL Stored Procedure that will handle all my data checks and data warehouse updates. On the Triggers, I've converted the records on the inserts/updates and deleted results into a XML format and send the value to the Stored Procedure. You can convert the results to XML by using the following syntax:

--Action = 'UPDATE'
SELECT @Xml = (SELECT (SELECT * FROM deleted FOR XML PATH(''),TYPE, ELEMENTS) AS DELETED,
              (SELECT * FROM inserted FOR XML PATH(''),TYPE, ELEMENTS) AS INSERTED
              FROM Main AS MAIN
              WHERE ID = @ID FOR XML AUTO, ELEMENTS)

I've also send through a status variable so that the SQL Stored Procedure knows if it was an INSERT, UPDATE or DELETE. The Stored Procedure also required the SQL Database Table name, Primary Key column name and the Primary Key value. That combination will be used on the SQL Stored Procedure to determine which data checks and data warehouse updates to do. Below is an example of my SQL Trigger:

IF EXISTS(SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[tr_Main]')  AND Type IN (N'TR'))
BEGIN
 DROP TRIGGER [dbo].[tr_Main]
END
GO

CREATE TRIGGER [dbo].[tr_Main]
   ON  [dbo].[Main]
   AFTER INSERT,DELETE,UPDATE
AS
BEGIN
 DECLARE @temp_InsertedOrDelete AS TABLE (ID INT)
 DECLARE @Action AS NVARCHAR(10) = ''
 DECLARE @Table AS NVARCHAR(255) = ''
 DECLARE @Column AS NVARCHAR(255) = ''
 DECLARE @ID AS INT = 0
 DECLARE @Xml AS XML
 SET @Table = 'Main'
 SET @Column = 'ID'

 IF EXISTS(SELECT * FROM inserted) AND EXISTS(SELECT * FROM deleted)
 BEGIN
  SET @Action = 'UPDATE'

  INSERT INTO @temp_InsertedOrDelete (ID)
  SELECT ISNULL(ID,0) FROM inserted

  WHILE (SELECT COUNT(ID) FROM @temp_InsertedOrDelete) <> 0
  BEGIN
   SELECT TOP 1 @ID = ISNULL(ID,0) FROM @temp_InsertedOrDelete

   SELECT @Xml = (SELECT (SELECT * FROM deleted FOR XML PATH(''),TYPE, ELEMENTS) AS DELETE,
                 (SELECT * FROM inserted FOR XML PATH(''),TYPE, ELEMENTS) AS INSERT  
                 FROM Main AS MAIN
                 WHERE ID = @ID FOR XML AUTO, ELEMENTS)
   ----------------------------------
   --UPDATE THE DATAWAREHOUSE BEGIN--
   ----------------------------------

   --------------------------------
   --UPDATE THE DATAWAREHOUSE END--
   --------------------------------
   DELETE FROM @temp_InsertedOrDelete WHERE ISNULL(ID,0) = @ID
  END
 END
 ELSE IF EXISTS(SELECT * FROM inserted) AND NOT EXISTS(SELECT * FROM deleted)
 BEGIN
  SET @Action = 'INSERT'

  INSERT INTO @temp_InsertedOrDelete (ID)
  SELECT ISNULL(ID,0) FROM inserted

  WHILE (SELECT COUNT(ID) FROM @temp_InsertedOrDelete) <> 0
  BEGIN
   SELECT TOP 1 @ID = ISNULL(ID,0) FROM @temp_InsertedOrDelete

   SELECT @Xml = (SELECT (SELECT * FROM inserted FOR XML PATH(''),TYPE, ELEMENTS) AS INSERT
                  FROM Main AS MAIN
                  WHERE ID = @ID FOR XML AUTO, ELEMENTS)

   ---------------------------------------
   --INSERT INTO THE DATAWAREHOUSE BEGIN--
   ---------------------------------------

   -------------------------------------
   --INSERT INTO THE DATAWAREHOUSE END--
   -------------------------------------
   DELETE FROM @temp_InsertedOrDelete WHERE ISNULL(ID,0) = @ID
  END
 END
 ELSE IF NOT EXISTS(SELECT * FROM inserted) AND EXISTS(SELECT * FROM deleted)
 BEGIN
  SET @Action = 'DELETE'

  INSERT INTO @temp_InsertedOrDelete (ID)
  SELECT ISNULL(ID,0) FROM deleted

  WHILE (SELECT COUNT(ID) FROM @temp_InsertedOrDelete) <> 0
  BEGIN
   SELECT TOP 1 @ID = ISNULL(ID,0) FROM @temp_InsertedOrDelete

   SELECT @Xml = (SELECT (SELECT * FROM deleted FOR XML PATH(''),TYPE, ELEMENTS) AS DELETED
                 FROM (SELECT @ID AS ID) AS MAIN
                 WHERE ID = @ID FOR XML AUTO, ELEMENTS)

   ---------------------------------------
   --DELETE FROM THE DATAWAREHOUSE BEGIN--
   ---------------------------------------

   -------------------------------------
   --DELETE FROM THE DATAWAREHOUSE END--
   -------------------------------------
   DELETE FROM @temp_InsertedOrDelete WHERE ISNULL(ID,0) = ID
  END
 END
END
GO


As part of the Stored Procedure, I've added error handling by using TRY and CATCH and then write the errors to a SQL Table to view and help me to debug.

: