Share via


INSTEAD OF 트리거의 식과 계산 열

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

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

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

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

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

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

CREATE VIEW ExpressionView
AS
SELECT *, GETDATE() AS TodaysDate
FROM AdventureWorks.HumanResources.Employee

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

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

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

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

CREATE TABLE SampleTable
     (
      PriKey    int,
      FirstName nvarchar(20),
      LastName  nvarchar(30)
     )
GO
CREATE VIEW 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 ConcatView
INSTEAD OF INSERT
AS
BEGIN

   INSERT INTO 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 BaseTable
      (
       PrimaryKey   int PRIMARY KEY,
       ColumnB      int,
       ColumnC      decimal(19,3)
      )
    
    CREATE VIEW SquareView AS
    SELECT PrimaryKey, ColumnB,
           -- Square the value of ColumnC
           SQUARE(ColumnC) AS SquareC
    FROM BaseTable
    
    CREATE TRIGGER SquareTrigger ON SquareView
    INSTEAD OF INSERT
    AS
    BEGIN
      INSERT INTO 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 값만으로는 IntColAIntColB에 어떠한 값이 있는지 알 수 없습니다.

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

참고 항목

개념