다음을 통해 공유


INSTEAD OF 트리거의 식과 계산 열

뷰의 SELECT 목록에는 열 이름만으로 구성되는 단순 식이 아닌 다른 식이 포함됩니다. 뷰의 INSTEAD OF 트리거에는 INSERT 및 UPDATE에 지정된 값 중에서 기본 테이블 열에 설정해야 하는 값을 제대로 판단하는 논리가 있어야 합니다. 그러한 식의 예를 들면 다음과 같습니다.

  • 상수 또는 몇몇 유형의 함수와 같이 테이블의 어떠한 열로도 매핑되지 않는 뷰 식

  • 여러 열의 문자열을 연결하여 구성하는 복잡한 식과 같이 여러 열로 매핑되는 뷰 식

  • 함수의 열을 참조하는 것과 같이 하나의 기본 테이블 열에 있는 값을 변환하는 뷰 식

이 문제는 뷰 열이 기본 테이블의 계산 열을 참조하는 단순 식인 경우에도 적용됩니다. 계산 열을 정의하는 식은 뷰 SELECT 목록의 더 복잡한 식과 같은 형식을 갖습니다.

뷰의 SELECT 목록에는 기본 테이블의 어떤 열에도 매핑되지 않는 식을 포함할 수 있습니다. 다음 예를 참조하십시오.

CREATE VIEW dbo.ExpressionView
AS
SELECT BusinessEntityID, JobTitle, GETDATE() AS TodaysDate
FROM AdventureWorks2008R2.HumanResources.Employee;

TodaysDate 열은 테이블 열에 매핑되지 않지만 SQL Server에서는 ExpressionView에 정의된 INSTEAD OF 트리거로 전달하는 inserted 테이블에 TodaysDate 열을 작성해야 합니다. 그러나 inserted.TodaysDate 열은 Null을 허용하므로 ExpressionView를 참조하는 INSERT 문에서 이 열에 값을 제공하지 않아도 됩니다. 식은 테이블의 열로 매핑되지 않기 때문에 트리거가 INSERT 문에서 열에 제공한 값을 무시할 수 있습니다.

다른 열에 종속되지 않는 결과를 작성하는 기본 테이블의 계산 열을 참조하는 단순한 뷰 식인 경우에도 마찬가지입니다. 다음 예를 참조하십시오.

CREATE TABLE dbo.ComputedExample
   (
    PrimaryKey    int PRIMARY KEY,
    ComputedCol   AS SUSER_NAME()
   );

일부 복잡한 식은 여러 열로 매핑됩니다. 다음 예를 참조하십시오.

CREATE TABLE dbo.SampleTable
     (
      PriKey    int,
      FirstName nvarchar(20),
      LastName  nvarchar(30)
     );
GO
CREATE VIEW dbo.ConcatView
AS
SELECT PriKey, FirstName + ' ' + LastName AS CombinedName
FROM SampleTable;

ConcatView의 CombinedName 식에는 FirstName 및 LastName 값의 연결 값이 있습니다. INSTEAD OF INSERT 트리거를 ConcatView에 정의한 경우에는 INSERT 문에서 CombinedName 열에 값을 제공하는 방법에 대한 규칙이 있어야 합니다. 이 규칙은 트리거가 문자열 중 어느 부분을 FirstName 열에 지정하고 어느 부분을 LastName 열에 지정할 것인지 결정할 수 있도록 합니다. 'first_name;last_name' 규칙을 사용하여 INSERT 문에서 CombinedName의 값을 지정하는 규칙을 선택하면 트리거에서 INSERT를 성공적으로 처리할 수 있습니다.

CREATE TRIGGER InsteadSample on dbo.ConcatView
INSTEAD OF INSERT
AS
BEGIN

   INSERT INTO dbo.SampleTable
      SELECT PriKey,
         -- Pull out the first name string.
         SUBSTRING(
            CombinedName,
            1,
            (CHARINDEX(';', CombinedName) - 1)
            ),
         -- Pull out the last name string.
         SUBSTRING(
            CombinedName,
            (CHARINDEX(';', CombinedName) + 1),
            DATALENGTH(CombinedName) - (CHARINDEX(';', CombinedName) + 1)
            )
      FROM inserted
END;

복잡한 식이 포함된 계산 열을 참조하는 단순 식인 뷰 열을 처리할 때도 비슷한 논리가 필요합니다.

일부 뷰 식은 수학적 연산을 수행하거나 열을 함수의 매개 변수로 사용함으로써 기본 테이블 열의 값을 변환할 수 있습니다. 이런 경우 INSTEAD OF INSERT 트리거의 논리에서 다음과 같은 두 가지 방식을 사용할 수 있습니다.

  • 모든 INSERT 문에서 기본 테이블에 지정할 행 값을 제공하고 트리거 논리에서 inserted 테이블의 값을 기본 테이블로 이동하는 규칙을 사용합니다.

  • 뷰의 SELECT에서 반환할 것으로 예상되는 값을 모든 INSERT 문에서 제공하는 규칙을 사용합니다. 이런 경우에는 논리에서 작업을 반대로 실행해야 합니다. 예를 들면 다음과 같습니다.

    CREATE TABLE dbo.BaseTable
      (
       PrimaryKey   int PRIMARY KEY,
       ColumnB      int,
       ColumnC      decimal(19,3)
      );
    
    CREATE VIEW dbo.SquareView AS
    SELECT PrimaryKey, ColumnB,
           -- Square the value of ColumnC
           SQUARE(ColumnC) AS SquareC
    FROM BaseTable;
    
    CREATE TRIGGER SquareTrigger ON dbo.SquareView
    INSTEAD OF INSERT
    AS
    BEGIN
      INSERT INTO dbo.BaseTable
         SELECT PrimaryKey, ColumnB,
                 -- Perform logical inverse of function in view.
                 SQRT(SquareC)
         FROM inserted
    END;
    

더하기 및 빼기와 같은 수학적 연산을 사용하는 복잡한 식과 같은 몇몇 식에서는 트리거에서 대상 기본 테이블 열에 대한 값을 확실하게 작성하는 데 사용할 수 있는 값을 제공하지 못할 수도 있습니다. 예를 들어 뷰 SELECT 목록에 IntColA + IntColB AS AddedColumns 식이 있을 경우 inserted.AddedColumns에 있는 값 10은 무엇을 의미하는지 생각해 봅시다. 10이 3 + 7, 2 + 8 또는 5 + 5 연산의 결과입니까? inserted.AddedColumns 값만으로는 IntColA 및 IntColB에 어떠한 값이 있는지 알 수 없습니다.

이런 경우 다른 정보 원본을 사용하도록 트리거의 코드를 작성하면 기본 테이블 열에 설정된 값을 알아낼 수 있습니다. 뷰에 INSTEAD OF 트리거가 있을 경우 뷰 SELECT 목록에는 트리거가 수정한 기본 테이블에서 Null이 아닌 모든 열에 대해 값을 작성할 수 있도록 충분한 정보가 포함되어야 합니다. 모든 데이터를 inserted 테이블에서 직접 가져오는 것은 아닙니다. inserted 테이블에 있는 값이 트리거가 다른 기본 테이블의 관련 데이터를 검색하는 데 사용하는 키 값이 되는 경우도 있습니다.

참고 항목

개념