Rollback transaction from trigger

╄→гoц情女王★ 提交于 2019-12-09 02:52:59

问题


In MS SQL Server 2008 R2, we want a pre-insert and pre-update trigger which checks something and allows or rollbacks (via raiserror) the running insert/update.

Question: In INSTEAD OF trigger. Does one really has to explicitly write the insert or update? Because we want the default insert or update to be done and only do the "precheck".


回答1:


Yes.

You do need to write the explicit INSERT or UPDATE.

The trigger runs INSTEAD OF the DML operation. If you leave the trigger blank then no action will happen other than the INSERTED / DELETED tables being created and populated in tempdb.

Although from discussion in the comments I would not use a trigger for this at all but use a unique filtered index CREATE UNIQUE INDEX ix ON T(a,b,c) WHERE c <> ''. This is likely to be more performant and avoid potential logic issues when dealing with concurrency.




回答2:


You probably do not want an INSTEAD OF trigger unless you want to replace the actual insert or update. In your case, you want a FOR INSERT, UPDATE trigger instead.

This example trigger prints a message to the client when anyone tries to add or change data in the titles table.

USE pubs
IF EXISTS (SELECT name FROM sysobjects
      WHERE name = 'reminder' AND type = 'TR')
   DROP TRIGGER reminder
GO
CREATE TRIGGER reminder
ON titles
FOR INSERT, UPDATE 
AS RAISERROR ('inserts and updates to the titles table is not allowed', 16, 1)
GO

You could also use things like IF EXISTS or COLUMNS_UPDATED as well.

Here another example that uses rollback.

USE pubs
IF EXISTS (SELECT name FROM sysobjects
      WHERE name = 'employee_insupd' AND type = 'TR')
   DROP TRIGGER employee_insupd
GO
CREATE TRIGGER employee_insupd
ON employee
FOR INSERT, UPDATE
AS
/* Get the range of level for this job type from the jobs table. */
DECLARE @min_lvl tinyint,
   @max_lvl tinyint,
   @emp_lvl tinyint,
   @job_id smallint
SELECT @min_lvl = min_lvl, 
   @max_lvl = max_lvl, 
   @emp_lvl = i.job_lvl,
   @job_id = i.job_id
FROM employee e INNER JOIN inserted i ON e.emp_id = i.emp_id 
   JOIN jobs j ON j.job_id = i.job_id
IF (@job_id = 1) and (@emp_lvl <> 10) 
BEGIN
   RAISERROR ('Job id 1 expects the default level of 10.', 16, 1)
   ROLLBACK TRANSACTION
END
ELSE
IF NOT (@emp_lvl BETWEEN @min_lvl AND @max_lvl)
BEGIN
   RAISERROR ('The level for job_id:%d should be between %d and %d.',
      16, 1, @job_id, @min_lvl, @max_lvl)
   ROLLBACK TRANSACTION
END

I'm not sure if you have a transaction or not, but in your case you would want something like the following:

USE myDatabase

    IF EXISTS (SELECT name FROM sysobjects
          WHERE name = 'myTable' AND type = 'TR')
       DROP TRIGGER tr_myTrigger
    GO
    CREATE TRIGGER tr_myTrigger
    ON myTable
    FOR INSERT, UPDATE
    AS

if(exists(select * from inserted where rtrim(c) <> ''))
begin
  -- check to make sure the insert(s) are unique

    if(exists(
      select * from inserted i
      join dbo.myTable t on i.a = t.a and i.b = t.b and i.c = t.c)

    begin
      raiserror('Duplicate(s) found', 16, 1)
      rollback transaction
    end
end


来源:https://stackoverflow.com/questions/10072627/rollback-transaction-from-trigger

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!