Share via


INSTEAD OF 觸發程序中之運算式與計算資料行

檢視的選取清單可以包含任何一種運算式,但只包含一個資料行名稱的簡單運算式除外。這些檢視的 INSTEAD OF 觸發程序必須具有邏輯,以便從 INSERT 及 UPDATE 所指定的值當中,正確判斷出哪些值必須設定到基底資料表的資料行中。這類運算式的範例如下:

  • 未對應到資料表中任何資料行的檢視運算式,例如常數或某些類型的函數。

  • 對應到多個資料行的檢視運算式,例如由二或多個資料行的串連字串所組成的複雜運算式。

  • 轉換單一基底資料表資料行值的檢視運算式,例如參考函數中的一個資料行。

這些原則也適用於屬於簡單運算式、且參考基底資料表中計算資料行的檢視資料行。定義計算資料行的運算式,可與檢視選取清單中更複雜的運算式擁有相同的格式。

檢視的選取清單中,可以包含未對應到任何基底資料表資料行的運算式,例如:

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

雖然 TodaysDate 資料行不會對應到任何資料表資料行,但 SQL Server 必須在 inserted 資料表中建立一個 TodaysDate 資料行,此資料表會傳遞到為 ExpressionView 定義的 INSTEAD OF 觸發程序。不過,由於 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 值的串連值如果為 ConcatView 定義了 INSTEAD OF INSERT 觸發程序,您必須設定慣例說明 INSERT 陳述式如何為 CombinedName 資料行提供值,讓觸發程序決定應將字串的哪個部份放入 FirstName 資料行,哪個部份放入 LastName 資料行。如果您選擇讓 INSERT 陳述式利用 'first_name;last_name' 慣例來指定 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 資料表中的值移到基底資料表。

  • 本慣例是讓所有的 INSERT 陳述式提供預期檢視的 SELECT 會傳回的值,在此狀況下,觸發程序中的邏輯必須反向運算。例如:

    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;
    

某些運算式,例如使用加法與減法數學運算之複雜運算式,使用者可能無法提供值,讓觸發程序明確地用來建立目的基底資料表資料行的值。例如,如果檢視選取清單包含 IntColA + IntColB AS AddedColumns 運算式,則 inserted.AddedColumns 中的 10 這個值代表什麼意義呢?10 是否代表 3 + 7、2 + 8 或 5 + 5 的結果?光從 inserted.AddedColumns 的值,是無法瞭解應在 IntColA 及 IntColB 中放入什麼值。

在這些狀況下,可以設定觸發程序使用不同來源的資訊,以決定要放入基底資料表資料行中的值。對於具有 INSTEAD OF 觸發程序的檢視來說,檢視選取清單必須包含足夠的資訊,以便為基底資料表中由觸發程序修改的所有非 Null資料行建立值。並非所有資料都必須直接來自於 inserted 資料表。在某些情況下,inserted 資料表中的值,可能是觸發程序用來擷取其他基底資料表相關資料的索引鍵值。