<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12
      Dev Guide: js | css | HTML(DOM) WEBCAST .NET4 Lib Web.config-WCF MVC3-EF4.1 T-SQL-(2012)

      Transact-SQL 示例 - 觸發器的基礎及應用

      閱讀提示:本篇文章內所使用到的數據庫為AdventureWorks OLTP

      I:觸發器介紹

      1.在開始介紹觸發器之前我們先回顧一下T-SQL的專業詞匯DDL, DML

      詞匯 中文解釋 英文
      DDL 數據定義語言 data definition language
      DML 數據操作語言 data manipulation language

      DDL:定義數據庫,表,視圖及其他對象的命令語句如:create database, create table, create view, create xxx, alter xxx, drop xxx等

      DML:對數據庫內的表或視圖進行添加,修改,刪除操作的命令語句如:insert, update, delete.在這里注意一點,select是屬于DQL(Data Query Language, 數據查詢語言)而非DML.

      備注:以上知識點均參照百度百科的介紹.DML DDL

      2.什么是觸發器?它的用途是什么?

      觸發器主要用于幫助SQL Server實現數據完整性約束.當用戶對現有數據庫的架構(schema)及表數據(包括視圖數據)進行相關操作的時候,你可以通過添加觸發器去約束用戶的操作行為.如果約束驗證成功,那么用戶的操作將會提交到數據庫當中.如果約束驗證失敗,你可以選擇回滾,并將失敗的原因告知給用戶,然后還可以把本次操作失敗的原因記錄到日志系統里面,以便為日后的分析提供一個參考依據!

      在這里列舉一個AdventureWorks數據庫的一個禁止刪除[HumanResources].[Employee]表數據的例子:

      CREATE TRIGGER [HumanResources].[dEmployee] 
         ON [HumanResources].[Employee] 
         INSTEAD OF DELETE --優先于DML觸發器執行
         NOT FOR REPLICATION --在復制代理執行插入、更新或刪除操作時,不進行觸發器約束
      AS 
      BEGIN
         DECLARE @Count int;
         SET @Count = @@ROWCOUNT;
         IF @Count = 0 
            RETURN;
         SET NOCOUNT ON;
         BEGIN
            RAISERROR(
               N'Employees cannot be deleted. They can only be marked as not current.', -- Message
               10, -- Severity.
               1 -- State.
            ); 
            IF @@TRANCOUNT > 0
            BEGIN
               ROLLBACK TRANSACTION;
            END
         END;
      END;

      INSTEAD OF DELETE觸發器運行效果:
      image
      解釋一下ROLLBACK TRANSACTION的作用,如果我把
      BEGIN
         ROLLBACK TRANSACTION;
      END
      注視掉的話.~會出現以下的情況
      image

      可以看到.~雖然顯示了DELETE受影響的行數,但是我后面的一個SELECT COUNT(*)顯示數據表內的記錄仍然存在,并沒有被刪除.所以加上這三行制造一個偽錯誤提示給客戶端是一個正確的決定.

      II.如何使用觸發器

      1.觸發器的定義
      CREATE TRIGGER [ schema_name . ]trigger_name
          ON { table | view }
      [ WITH <dml_trigger_option> [ ,...n ] ]
      { FOR | AFTER | INSTEAD OF }
      { [ INSERT ] [ , ] [ UPDATE ] [ , ] [ DELETE ] }
      [ WITH APPEND ]
      [ NOT FOR REPLICATION ]
      AS { sql_statement  [ ; ] [ ,...n ] | EXTERNAL NAME <method specifier [ ; ] > }


      <dml_trigger_option> ::=
          [ ENCRYPTION ]
          [ EXECUTE AS Clause ]

      <method_specifier> ::=
          assembly_name.class_name.method_name

      注意:如果同時定義了INSTEAD OF { [ INSERT ] [ , ] [ UPDATE ] [ , ] [ DELETE ] } 和 FOR | AFTER { [ INSERT ] [ , ] [ UPDATE ] [ , ] [ DELETE ] }的話你必須要在INSTEAD OF內使用DML語句才會使FOR|AFTER觸發器生效

      觸發器內可以已INSERTED, DELETED這兩個表名去訪問將要插入,或被刪除的數據信息

      另外:不能為 DDL 或登錄觸發器指定 INSTEAD OF。對于表或視圖,每個 INSERT、UPDATE 或 DELETE 語句最多可定義一個 INSTEAD OF 觸發器

      更多詳細資料可以參閱: Technet

      2.觸發器的種類
      A:DML觸發器

      功能:可以對insert, update, delete語句進行觸發檢查按照一定條件執行回滾操作,避免不符合業務要求的數據進入到數據表當中,使用INSERTED, DELETED去訪問將要被添加,刪除的數據.

      例2.1-禁止刪除DatabaseLog表中的記錄

      CREATE TRIGGER dDatabaseLog
         ON DatabaseLog
         FOR DELETE
      AS
      BEGIN
         RAISERROR('不允許刪除DatabaseLog表內的數據', 11, 1)
         ROLLBACK
      END
      

      執行效果
      image
      B:DDL觸發器

      功能:可以對任何DDL語句進行觸發檢測并按照設定好的規則進行回滾操作.

      例2.2-禁止當前數據庫執行DROP TABLE, ALTER TABLE:

      CREATE TRIGGER [safety]
      ON DATABASE 
      FOR DROP_TABLE, ALTER_TABLE 
      AS
      BEGIN
         RAISERROR('目前數據庫已禁止刪除,修改表', 11, 1)
         ROLLBACK;
      END

      最終效果
      image

      3.INSTEAD OF 與 FOR|AFTER觸發器

      INSTEAD OF 與 FOR|AFTER觸發器同屬DML觸發器,在本章的第一小節 [觸發器的定義] 當中我們已經得知,只能為INSERT|UPDATE|DELETE添加一個INSTEAD OF觸發器,而FOR|AFTER觸發器則是可以定義多個.下面我將會用一個小示例去演示INSTEAD OF觸發器優于FOR|AFTER觸發器的證明.及兩者的區別.

      例3-1:

      先定義一個不允許刪除DatabaseLog.DatabaseLogID < 1500的INSTEAD OF DELETE觸發器,然后在定義一個不允許刪除DatabaseLog.DatabaseLogID < 1700的FOR DELETE觸發器然后看他們被觸發的情況.請注意 [DELETED] 的位置

      注意:先把之前定義的FOR DELETE觸發器dDatabaseLog刪掉. DROP TRIGGER dDatabaseLog

      CREATE TRIGGER [dbo].[dDatabaseLog_1]
         ON [dbo].[DatabaseLog]
         INSTEAD OF DELETE
      AS
      BEGIN
         IF EXISTS(
               SELECT * FROM DELETED WHERE DatabaseLogID < 1500
            )
         BEGIN
            --這里并不會調用FOR DELETE觸發器,因為這個觸發器是INSTEAD OF
            RAISERROR('INSTEAD OF觸發器禁止刪除DatabaseLogID < 1500的記錄', 11, 1)
            IF @@TRANCOUNT > 0
            BEGIN
               ROLLBACK TRANSACTION;
            END
         END
         ELSE
         BEGIN
            --這里開始才調用FOR DELETE觸發器
            DELETE FROM DatabaseLog WHERE DatabaseLogID IN (
               SELECT DatabaseLogID FROM DELETED
            )
         END
      END
      


      CREATE TRIGGER [dbo].[dDatabaseLog_2]
         ON [dbo].[DatabaseLog]
         FOR DELETE
      AS
      BEGIN
         --如果進入到這里的話,已證明INSTEAD OF DELETE觸發器已通過約束檢測
         IF EXISTS(
               SELECT * FROM DELETED WHERE DatabaseLogID < 1700
            )
         BEGIN 
            RAISERROR(
               'FOR觸發器禁止刪除DatabaseLogID < 1700的記錄',
               11, 1
            )
            --此處的回滾操作是由FOR DELETE發出
            ROLLBACK
         END
      END
      

      從上述腳本我們可以看到在INSTEAD OF DELETE觸發器中并不需要去調用ROLLBACK去回滾操作,因為這是INSTEAD OF觸發器的一個特性.

      TechNet上介紹INSTEAD OF觸發器的定義為:INSTEAD OF 指定執行 DML 觸發器而不是觸發 SQL 語句,因此,其優先級高于觸發語句的操作.

      上述示例的運行效果

      當DatabaseLogID < 1500條件成立時,INSTEAD OF DELETE沒有調用任何DELETE FROM語句,所以FOR DELETE觸發器不會觸發.
      image

      而當我刪除DatabaseLogID > 1501的記錄時,INSTEAD OF DELETE觸發器已經通過檢測,然后去提交DELETE FROM去調用FOR DELETE觸發器.

      最終FOR DELETE因滿足約束條件DatabaseLogID < 1700而回滾了刪除操作.
      image 

      III:查詢一個數據庫內的到底定義了多少個觸發器?他們所屬的表對象是誰?

      1.下面我將會貼出一段T-SQL示例腳本,它的功能為顯示出當前數據庫內所有的觸發器信息

      --切換數據庫
      --use AdventureWorks
      
      WITH cte_AllTriggers AS (
         SELECT 
            o.name TableName,          --觸發器所屬的對象(表 | 視圖)
            o.type_desc TableType,     --描述此觸發器所屬的對象是表還是視圖
            t.name TriggerName,        --觸發器的名稱
            t.object_id,               --觸發器的object_id
            t.parent_class_desc,       --觸發器是DML觸發器還是DDL觸發器
            t.type_desc,               --觸發器是SQL觸發器還是CLR觸發器
            t.create_date,             --觸發器的創建日期
            t.modify_date,             --上次使用 ALTER 語句修改觸發器的日期
            t.is_ms_shipped,           --是否為內部 SQL Server 組件代表用戶創建的觸發器
            t.is_disabled,             --觸發器是否被禁用
            t.is_not_for_replication,  --觸發器是否作為 NOT FOR REPLICATION 創建的
            t.is_instead_of_trigger    --1 = INSTEAD OF 觸發器, 0 = AFTER 觸發器
         FROM 
            sys.triggers t INNER JOIN sys.objects o 
               ON t.parent_id = o.object_id 
         UNION ALL
         SELECT 
            NULL TableName,          
            NULL TableType,     
            t.name TriggerName,        
            t.object_id,               
            t.parent_class_desc,       
            t.type_desc,               
            t.create_date,             
            t.modify_date,             
            t.is_ms_shipped,           
            t.is_disabled,             
            t.is_not_for_replication,  
            t.is_instead_of_trigger    
         FROM 
            sys.triggers t 
         WHERE 
            t.parent_id = 0
      )
      SELECT * FROM cte_AllTriggers ORDER BY TableName, TriggerName
      

      執行效果如下:
      image
      在看到了上圖的運行后果以后,我發現AdventureWorks數據庫的觸發器定義使用了一個很不錯的命名約定

      將Insert觸發器使用以小寫字母i開頭以作識別

      將Update觸發器使用以小寫字母u開頭以做識別

      將Delete觸發器使用以小寫字母d開頭以做識別

      注意行號為1, 2的觸發器是DDL觸發器所以他們的表對象為NULL.

      OK,介紹完怎么查看某個數據庫內所有的觸發器后,接下來!我將為你介紹AdventureWorks中觸發器的用途.

      IV:DML觸發器在AdventureWorks中的應用場景

      在這里并不會把12個原有的觸發器都一一講完,僅僅挑其中2個進行講解.
      1.dEmployee:第一章第2節已經介紹
      2.iuIndividual:位于Sales架構的Individual表.這是一個帶插入兼更新為一體的觸發器.

      首先介紹一下表
      Sales.Individual --客戶的統計數據表
      {
          CustomerID, --客戶Id
          ContactID, --聯系人Id
          Demographics, --統計
          ModifiedDate --上次修改日期
      }

      Sales.Store --客戶和經銷商表
      {
          CustomerID, --客戶Id
          Name, --商店的名稱
          SalesPersonID, --Adventure Works 銷售代表的Id
          Demographics, --商店的統計信息
          rowguid, --用于合并數據庫
          ModifiedDate --上次修改日期
      }

      下面的這個觸發器大概可以理解為插入或更新的表Sales.Individual的CustomerID列存在于[Sales].[Store].[CustomerID]時回滾.

      當成功更新/插入列[CustomerID],[Demographics]時,根據設定好的條件更新[Sales].[Individual].[Demographics]列.

      ALTER TRIGGER [Sales].[iuIndividual] 
         ON [Sales].[Individual] --該觸發器是給[Sales].[Individual]定義的
         AFTER INSERT, UPDATE --是AFTER INSERT觸發器的同時,也是AFTERC觸發器
         NOT FOR REPLICATION
      AS 
      BEGIN
         DECLARE @Count int;
         SET @Count = @@ROWCOUNT;
         IF @Count = 0 
            RETURN; --如果插入刪除所影響的行為0時退出
         SET NOCOUNT ON;
         
         IF EXISTS (
               SELECT * FROM 
                  inserted INNER JOIN [Sales].[Store] 
                     ON inserted.[CustomerID] = [Sales].[Store].[CustomerID]
            ) 
         BEGIN
            IF @@TRANCOUNT > 0
            BEGIN
               --當插入[Sales].[Individual]表客戶Id已存在于[Sales].[Store]表時回滾
               ROLLBACK TRANSACTION;
            END
         END;
         
         
         IF UPDATE([CustomerID]) OR UPDATE([Demographics]) --如果CustomerID列或Demographics列更新|插入成功
         BEGIN
            --根據條件更新Demographics列
            UPDATE [Sales].[Individual] SET 
               [Sales].[Individual].[Demographics] = N'<IndividualSurvey xmlns="http://schemas.microsoft.com/sqlserver/2004/07/adventure-works/IndividualSurvey">
      <TotalPurchaseYTD>0.00</TotalPurchaseYTD>
      </IndividualSurvey>' 
            FROM inserted --連接到插入或更新的數據表
            WHERE 
               [Sales].[Individual].[CustomerID] = inserted.[CustomerID] 
               AND inserted.[Demographics] IS NULL; --將要更新或插入的Demographics為空時
      
            --根據條件插入一個XML節點
            UPDATE [Sales].[Individual] SET 
               [Demographics].modify(
                  N'declare default element namespace "http://schemas.microsoft.com/sqlserver/2004/07/adventure-works/IndividualSurvey"; 
      insert <TotalPurchaseYTD>0.00</TotalPurchaseYTD> 
      as first 
      into (/IndividualSurvey)[1]') 
            FROM inserted 
            WHERE 
               [Sales].[Individual].[CustomerID] = inserted.[CustomerID] 
               AND inserted.[Demographics] IS NOT NULL 
               AND inserted.[Demographics].exist(N'declare default element namespace 
            "http://schemas.microsoft.com/sqlserver/2004/07/adventure-works/IndividualSurvey"; 
      /IndividualSurvey/TotalPurchaseYTD') <> 1;
         END;
      END;
      

      我對AdventureWorks不太熟悉,需要學習研究的朋友們請自己上網搜索相關資料.

      3.iWorkOrder:位于[Production].[WorkOrder]表的AFTER插入觸發器

      此觸發器用于先嘗試把將要插入到表[Production].[WorkOrder]的數據先插入到[Production].[TransactionHistory]表中,如果[Production].[TransactionHistory]插入完成.那么將提交事務,否則顯示錯誤信息及回滾,并將錯誤寫入日志表內.

      ALTER TRIGGER [Production].[iWorkOrder] 
         ON [Production].[WorkOrder] 
         AFTER INSERT --AFTER插入觸發器
      AS 
      BEGIN
         DECLARE @Count int;
         SET @Count = @@ROWCOUNT;
         IF @Count = 0 
            RETURN; --插入的行為0時退出
         
         SET NOCOUNT ON;
         BEGIN TRY
            --往工作訂單表(TransactionHistory)插入生產工作訂單(WorkOrder)記錄
            INSERT INTO [Production].[TransactionHistory] (
               [ProductID]
               ,[ReferenceOrderID]
               ,[TransactionType]
               ,[TransactionDate]
               ,[Quantity]
               ,[ActualCost]
            )
            SELECT 
               inserted.[ProductID]
               ,inserted.[WorkOrderID]
               ,'W' --代表工作訂單
               ,GETDATE()
               ,inserted.[OrderQty]
               ,0
            FROM inserted;
         END TRY
         BEGIN CATCH
            --在Message窗口中輸出錯誤信息
            EXECUTE [dbo].[uspPrintError];
            IF @@TRANCOUNT > 0
            BEGIN
              ROLLBACK TRANSACTION; --事務數 > 0時回滾
            END
            
            --記錄錯誤信息進日志
            EXECUTE [dbo].[uspLogError];
         END CATCH;
      END;
      

      V:觸發器的弊端

      學習了上面4個章節的內容后,大家都可以知道了..當你往數據庫內插入,修改,刪除數據時.在原來沒有觸發器的情況下時也僅僅需要做一下外鍵主鍵的完整性約束檢查及CHECK約束檢查.而在有了觸發器的情況又會在原有的基礎上再多跑一些T-SQL語句.所以觸發器設計得是否合理對于一個數據庫系統性能極為重要.在觸發器內部需要注意鎖的問題!
      http://v.youku.com/v_show/id_XMjg5NDQ3MzUy.html (祈禱, 6++月24--)M~JCXC1J~}F8$PM4BBBN1QD

      本文到此結束!

      posted @ 2011-08-01 08:47  dotNetDR_  閱讀(3364)  評論(7)    收藏  舉報
      主站蜘蛛池模板: 国产精品小粉嫩在线观看| 俺来也俺去啦最新在线| 4hu亚洲人成人无码网www电影首页 | 亚洲成色精品一二三区| 色二av手机版在线| 亚洲高潮喷水无码AV电影| 亚洲色大成网站www在线| 亚洲av首页在线| 人妻丝袜无码专区视频网站| 国产女高清在线看免费观看| 视频一区二区三区在线视频| 久久精品国产99久久6| 狠狠色噜噜狠狠狠狠777米奇| 乱女乱妇熟女熟妇综合网| 噜噜久久噜噜久久鬼88| 另类 专区 欧美 制服| 亚洲 另类 小说 国产精品无码| 苍井空毛片精品久久久| 豆国产97在线 | 亚洲| 精品国产午夜福利在线观看| 国产精品剧情亚洲二区| 成年女人免费视频播放体验区 | 亚洲国产精品成人无码区| 尹人香蕉久久99天天拍| a在线免费| 欧美国产日产一区二区| 97久久久精品综合88久久| 99999久久久久久亚洲| 无码专区 人妻系列 在线| 国产中文字幕久久黄色片| 毛片免费观看天天干天天爽| 色老头亚洲成人免费影院| 亚洲天堂男人天堂女人天堂| 欧美日产国产精品日产| 亚洲精品成人久久av| 韩国免费a级毛片久久| 末成年娇小性色xxxxx| 国产精品亚洲一区二区在| 日本中文字幕有码在线视频| 蜜桃精品成人影片| 国产亚洲精品自在久久vr|