Search code examples
sqldatabasesql-server-2008triggersinsert-into

Forbid insert into table on certain conditions


I have a SQL Server 2008 database. There are three terminals connected to it (A, B, C). There is a table SampleTable in the database, which reacts to any terminal activity. Every time there is some activity on any terminal, logged on to this DB, the new row is inserted into SampleTable.

I want to redirect traffic from one (C) of the three terminals to write to table RealTable and not SampleTable, but I have to do this on DB layer since services that write terminal activity to DB are in Black Box.

I already have some triggers working on SampleTable with the redirecting logic, but the problem is that rows are still being inserted into SampleTable.

What is the cleanest solution for this. I am certain that deleting rows in an inserting trigger is bad, bad, bad.

Please help.

Edit:

Our current logic is something like this (this is pseudo code):

ALTER TRIGGER DiffByTerminal
 ON SampleTable
AFTER INSERT
AS
DECLARE @ActionCode VARCHAR(3), 
    @ActionTime DATETIME,
    @TerminalId INT

  SELECT @ActionCode = ins.ActionCode, 
     @ActionTime = ins.ActionTime, 
     @TerminalId = ins.TerminalId
  FROM inserted ins

IF(@TerminalId = 'C')
BEGIN

    INSERT INTO RealTable 
    (   
         ...
    )
    VALUES
    (
         @ActionCode, 
         @ActionTime, 
         @TerminalId
    )
END

Solution

  • In order to "intercept" something before a row gets inserted into a table, you need an INSTEAD OF trigger, not an AFTER trigger. So you can drop your existing trigger (which also included flawed logic that assumed all inserts would be single-row) and create this INSTEAD OF trigger instead:

    DROP TRIGGER DiffByTerminal;
    GO
    
    CREATE TRIGGER dbo.DiffByTerminal
     ON dbo.SampleTable
    INSTEAD OF INSERT
    AS
    BEGIN
      SET NOCOUNT ON;
    
      INSERT dbo.RealTable(...) SELECT ActionCode, ActionTime, TerminalID
        FROM inserted
        WHERE TerminalID = 'C';
    
      INSERT dbo.SampleTable(...) SELECT ActionCode, ActionTime, TerminalID
        FROM inserted
        WHERE TerminalID <> 'C';
    END
    GO
    

    This will handle single-row inserts and multi-row inserts consisting of (a) only C (b) only non-C and (c) a mix.