2012-04-09 3 views
10

MS SQL Server 2008 R2에서 실행중인 삽입/업데이트를 무언가를 검사하고 허용 또는 롤백 (raiserror 통해)하는 사전 삽입 및 사전 업데이트 트리거가 필요합니다.트리거에서 롤백 트랜잭션

질문 : INSTEAD OF에서 트리거합니다. 실제로 삽입 또는 업데이트를 명시 적으로 작성해야합니까? 기본 삽입 또는 업데이트를 수행하고 "사전 검사"만 수행하기를 원하기 때문입니다.

+0

은 "PreCheck를"의 본질은 무엇인가? 트리거에는'inserted' /'deleted' 테이블을 관리하는 오버 헤드가 있습니다. 그것은 다른 방식으로 집행 될 수있는 것입니까? –

+0

우리가 필요로하는 것은 하나의 열에서 빈 문자열을 무시하는 트리플 (3 개 열)에 대한 고유 한 제한 조건입니다. – Cartesius00

+0

튜플'(a, b, c)'의 경우'c'가 빈 문자열 값을 가지면 고유 한 제약 조건을 위해 해당 튜플을 완전히 무시하고 싶습니까? –

답변

9

예.

INSERT 또는 UPDATE을 명시 적으로 써야합니다.

트리거는 INSTEAD OF DML 작업을 실행합니다. 트리거를 비워두면 INSERTED/DELETED 테이블이 생성되어 tempdb에 채워진 것 외에는 아무런 작업도 수행되지 않습니다.

의견에서 논의했지만 트리거를 전혀 사용하지 않지만 고유 한 필터링 된 인덱스 CREATE UNIQUE INDEX ix ON T(a,b,c) WHERE c <> ''을 사용합니다. 이것은 동시성을 다룰 때 잠재적 인 논리 문제를 피하고 성능이 더 좋아질 수 있습니다.

+0

감사합니다. DML 작업에서 삽입되고 업데이트 된 행의 별칭은 무엇입니까? – Cartesius00

+0

@James -'INSERTED'와'DELETED'하지만 이것들은 테이블이 아닙니다. 트리거는 명령문 당 한 번 실행됩니다. 그래서 INSERT INTO YourTable SELECT * FROM INSERTED는 전형적인'INSERT' 트리거가 될 것입니다. –

+0

그리고'YourTable'에 ID 열과 많은 다른 많은 열이 포함되어 있다면? 'SELECT *'는 문제입니다. 그렇죠? – Cartesius00

3

실제 삽입 또는 업데이트를 바꾸지 않으려면 INSTEAD OF 트리거를 원하지 않을 것입니다. 귀하의 경우 대신 FOR INSERT, UPDATE 트리거가 필요합니다.

이 예제 트리거는 누군가가 titles 테이블에 데이터를 추가하거나 변경하려고 시도 할 때 클라이언트에 메시지를 인쇄합니다.

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 

또한 IF EXISTS 또는 COLUMNS_UPDATED뿐만 아니라 같은 것들을 사용할 수 있습니다.

여기서 롤백을 사용하는 또 다른 예입니다. 당신이 거래를하거나하지 않을 경우

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 

는 잘 모르겠지만, 귀하의 경우 다음과 같이 할 것입니다 :

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