트리거 만들기
트리거는 데이터베이스에서 특정 이벤트가 발생할 때 자동으로 실행되는 특수 저장 프로시저입니다. 애플리케이션 수준 코드를 요구하지 않고 데이터 무결성을 유지하고, 비즈니스 규칙을 적용하고, 데이터베이스 작업을 자동화하는 트리거를 정의합니다.
트리거 기본 사항 이해
트리거는 데이터베이스의 데이터 수정 또는 스키마 변경에 응답합니다. 트리거를 만들 때 트리거를 활성화하는 이벤트와 트리거가 수행하는 작업을 지정합니다.
트리거는 자동으로 실행됩니다. 명시적으로 호출하는 저장 프로시저와 달리, 트리거는 INSERT, UPDATE, DELETE 또는 DDL 문에 대한 응답으로 실행됩니다. 이 자동 실행은 모든 데이터 수정에 일관되게 적용해야 하는 규칙을 적용하는 데 강력한 기능을 제공합니다.
SQL Server는 두 가지 주요 트리거 범주인 DML(데이터 조작 언어) 트리거와 DDL(데이터 정의 언어) 트리거를 지원합니다. DML 트리거는 테이블 데이터의 변경 사항에 응답하며, DDL 트리거는 CREATE, ALTER, DROP와 같은 스키마 변경문에 응답합니다.
데이터 수정을 위한 DML 트리거 만들기
DML 트리거는 테이블 또는 뷰의 데이터 변경 내용을 모니터링하고 응답합니다. AFTER 트리거 또는 INSTEAD OF 트리거로 정의합니다.
AFTER 트리거는 트리거 문이 완료된 후 실행됩니다. 데이터베이스는 먼저 데이터 수정을 수행한 다음 트리거 코드를 실행합니다. AFTER 트리거를 사용하여 변경 내용의 유효성을 검사하거나, 관련 테이블을 업데이트하거나, 수정 내용을 기록합니다.
CREATE TRIGGER tr_UpdateInventory
ON Sales.OrderDetails
AFTER INSERT
AS
BEGIN
UPDATE Inventory.Products
SET QuantityInStock = QuantityInStock - i.Quantity
FROM Inventory.Products p
INNER JOIN inserted i ON p.ProductID = i.ProductID;
END;
INSTEAD OF 트리거는 원래 데이터 수정 문을 대체합니다. 트리거 코드는 INSERT, UPDATE, 또는 DELETE 작업 대신 실행됩니다. INSTEAD OF 트리거를 사용하여 일반적으로 직접 수정을 허용하지 않는 보기를 수정하거나 복잡한 비즈니스 논리를 구현합니다.
CREATE TRIGGER tr_UpdateOrderView
ON Sales.OrderSummaryView
INSTEAD OF UPDATE
AS
BEGIN
UPDATE Sales.Orders
SET OrderStatus = i.OrderStatus,
ModifiedDate = GETDATE()
FROM Sales.Orders o
INNER JOIN inserted i ON o.OrderID = i.OrderID;
END;
DML 트리거에서는 삽입됨 및 삭제됨 의사 테이블에 접근할 수 있습니다. 이러한 임시 테이블은 영향을 받는 행의 복사본을 저장합니다.
INSERT
작업은 DELETE 테이블을 채우고, 작업은 UPDATE 테이블을 채우고, 작업은 삭제된 이전 값과 삽입된 새 값으로 두 테이블을 채웁니다.
특정 이벤트에 대한 트리거 구현
트리거를 활성화하는 데이터 수정 이벤트를 지정합니다. 단일 트리거는 트리거 정의에서 INSERT, UPDATE, 및 DELETE를 결합하여 여러 이벤트에 응답할 수 있습니다.
정확한 제어를 위해 각 작업에 대해 별도의 트리거를 만듭니다. 이 방법을 사용하면 코드가 간소화되고 트리거를 더 쉽게 유지 관리할 수 있습니다.
CREATE TRIGGER tr_LogPriceChanges
ON Products.Catalog
AFTER UPDATE
AS
BEGIN
IF UPDATE(Price)
BEGIN
INSERT INTO Audit.PriceHistory (ProductID, OldPrice, NewPrice, ChangeDate)
SELECT d.ProductID, d.Price, i.Price, GETDATE()
FROM deleted d
INNER JOIN inserted i ON d.ProductID = i.ProductID
WHERE d.Price <> i.Price;
END;
END;
동시에 동일한 논리가 여러 작업에 적용되는 경우 이벤트를 결합할 수 있습니다. 예를 들어 다음과 같이 응답하는 단일 감사 트리거를 INSERTUPDATE만들 수 있습니다DELETE.
CREATE TRIGGER tr_AuditEmployeeChanges
ON HR.Employees
AFTER INSERT, UPDATE, DELETE
AS
BEGIN
DECLARE @Operation NVARCHAR(10);
IF EXISTS (SELECT * FROM inserted) AND NOT EXISTS (SELECT * FROM deleted)
SET @Operation = 'INSERT';
ELSE IF EXISTS (SELECT * FROM inserted) AND EXISTS (SELECT * FROM deleted)
SET @Operation = 'UPDATE';
ELSE
SET @Operation = 'DELETE';
INSERT INTO Audit.EmployeeLog (EmployeeID, Operation, ChangeDate)
SELECT COALESCE(i.EmployeeID, d.EmployeeID), @Operation, GETDATE()
FROM inserted i
FULL OUTER JOIN deleted d ON i.EmployeeID = d.EmployeeID;
END;
이 함수는 UPDATE() 변경된 열을 결정하는 데 도움이 됩니다. 특정 필드만 비즈니스 논리에 중요한 경우 불필요한 처리를 방지하기 위해 특정 열을 확인합니다.
트리거 모범 사례 적용
트리거는 모든 정규화 작업으로 실행되므로 데이터베이스 성능에 영향을 줍니다. 트랜잭션 처리량에 미치는 영향을 최소화하기 위해 효율적인 트리거 코드를 작성합니다.
트리거 논리를 집중적이고 최소한으로 유지합니다. 트리거 본문 내에서 필수 작업만 실행합니다. 복잡하거나 시간이 많이 걸리는 작업의 경우 이벤트 세부 정보를 로깅하고 별도의 작업을 통해 비동기적으로 처리하는 것이 좋습니다.
CREATE TRIGGER tr_QueueLargeOrders
ON Sales.Orders
AFTER INSERT
AS
BEGIN
INSERT INTO Processing.OrderQueue (OrderID, TotalAmount, QueuedDate)
SELECT OrderID, TotalAmount, GETDATE()
FROM inserted
WHERE TotalAmount > 10000;
END;
트리거 수정을 통해 동일한 트리거가 다시 작동하는 재귀적 작용을 방지합니다.
RECURSIVE_TRIGGERS 데이터베이스 옵션을 적절하게 설정하고 무한 루프를 방지하도록 트리거를 디자인합니다.
트리거 내에서 오류를 적절하게 처리합니다. 트랜잭션 동작은 오류 처리에 따라 달라집니다. 트리거에 오류가 발생하여 처리하지 않는 경우 SQL Server는 트리거와 원래 문을 모두 롤백합니다.
CREATE TRIGGER tr_ValidateOrderDate
ON Sales.Orders
AFTER INSERT, UPDATE
AS
BEGIN
IF EXISTS (SELECT * FROM inserted WHERE OrderDate > GETDATE())
BEGIN
THROW 50001, 'Order date cannot be in the future', 1;
END;
END;
트리거를 철저히 문서화합니다. 다른 개발자는 일반적인 데이터베이스 작업 중에 보이지 않게 실행되므로 트리거가 존재하는 이유와 트리거가 수행하는 작업을 이해해야 합니다.
이제 트리거를 만들고 구현하는 방법을 이해했으므로 다른 프로그래밍 기능 개체와 통합하여 포괄적인 데이터베이스 솔루션을 빌드하는 방법을 살펴볼 준비가 되었습니다.