觸發器和遊標的用法

 

declare @d datetime
set @d=getdate()
select [語句執行花費時間(毫秒)]=datediff(ms,@d,getdate())



查找數據庫中的存儲過程
select name from sysobjects where xtype='TR'

如何禁用、啓用觸發器

禁用:alter table 表名 disable trigger 觸發器名稱
啓用:alter table 表名 enable trigger 觸發器名稱

如果有多個觸發器,則各個觸發器名稱之間用英文逗號隔開。

如果把“觸發器名稱”換成“ALL”,則表示禁用或啓用該表的全部觸發器。

AFTER 和INSTEAD OF 兩種類型的觸發器

使用注意:以下的Product表必須設置主鍵,否則無法運行正確

AFTER 觸發器
僅在觸發SQL語句中指定的所有操作已成功才被激發。所有的引用級聯操作和約束檢查也必須在激發此觸發器之前成功完成
如果僅指定FOR關鍵字,則AFTER爲默認的


INSTEAD OF 觸發器
其優先級高於SQL語句

對於表或試圖。每個insert、update或delete語句最多定義一個INSTEAD OF觸發器
注意:該觸發器不可以用於使用了WITH CHECK OPTION 的視圖

create trigger DeleteSomeThing
on Product
instead of Delete
as
begin
 insert into tb (ID,名稱,備註) values(123,'我是刪除Product表','哈哈')
end

Create trigger UpdateThings
on Product
for UPDATE
as
if UPDATE ([客戶訂數])
BEGIN
 update tb set[名稱]='已經更改啦' where  [名稱]='我是刪除Product表'
END

create trigger tr_delete on ReaderInfo
for delete
as
begin
  if exists(select 1 from BookInfo a , deleted b where a.readerid = b.readerid)
    rollback
end


inserted、deleted
這是兩個虛擬表,inserted 保存的是 insert 或 update 之後所影響的記錄形成的表,deleted 保存的是 delete 或 update 之前所影響的記錄形成的表。例:
create trigger tbl_delete
on tbl
for delete
as
    declare @title varchar(200)
    select @title=title from deleted
    insert into Logs(logContent) values('刪除了 title 爲:' + title + '的記錄')
說明:如果向 inserted 或 deleted 虛擬表中取字段類型爲 text、image 的字段值時,所取得的值將會是 null。



觸發器回滾

我們看到許多註冊系統在註冊後都不能更改用戶名,但這多半是由應用程序決定的, 如果直接打開數據庫表進行更改,同樣可以更改其用戶名,在觸發器中利用回滾就可以巧妙地實現無法更改用戶名。

use 數據庫名
go
create trigger tr
on 表名
for update
as
    if update(userName)
        rollback tran


 遊標種類
MS SQL SERVER 支持三種類型的遊標:Transact_SQL 遊標,API 服務器遊標和客戶遊標。
(1) Transact_SQL 遊標
    Transact_SQL 遊標是由DECLARE CURSOR 語法定義、主要用在Transact_SQL 腳本、存儲過程和觸發器中。Transact_SQL 遊標主要用在服務器上,由從客戶端發送給服務器的Transact_SQL 語句或是批處理、存儲過程、觸發器中的Transact_SQL 進行管理。 Transact_SQL 遊標不支持提取數據塊或多行數據。
(2) API 遊標
    API 遊標支持在OLE DB, ODBC 以及DB_library 中使用遊標函數,主要用在服務器上。每一次客戶端應用程序調用API 遊標函數,MS SQL SEVER 的OLE DB 提供者、ODBC驅動器或DB_library 的動態鏈接庫(DLL)都會將這些客戶請求傳送給服務器以對API遊標進行處理。
(3) 客戶遊標
    客戶遊標主要是當在客戶機上緩存結果集時才使用。在客戶遊標中,有一個缺省的結果集被用來在客戶機上緩存整個結果集。客戶遊標僅支持靜態遊標而非動態遊標。由於服務器遊標並不支持所有的Transact-SQL 語句或批處理,所以客戶遊標常常僅被用作服務器遊標的輔助。因爲在一般情況下,服務器遊標能支持絕大多數的遊標操作。
    由於API 遊標和Transact-SQL 遊標使用在服務器端,所以被稱爲服務器遊標,也被稱爲後臺遊標,而客戶端遊標被稱爲前臺遊標


STR ( float_expression [ , length [ , decimal ] ] )
 float_expression
    帶小數點的近似數字 (float) 數據類型的表達式。
length
    總長度。它包括小數點、符號、數字以及空格。默認值爲 10。
decimal
    小數點後的位數。decimal 必須小於或等於 16。如果 decimal 大於 16,則會截斷結果,使其保持爲小數點後具有十六位。


truncate table tb

declare @i int
set @i=1
while @i<100
begin
insert into tb (ID,名稱,備註) values(@i,REPLACE('名稱'+str(@i,2,0),'   ','')  ,REPLACE('備註'+str(@i,2,0),'   ','') )
set @i=@i+1
end

遊標的例子:

  --聲明一個遊標
     Declare curStudentFee Cursor
       for
       Select StudentFeeID From StudentFee      

     --聲明兩個費用變量
     Declare @mBorrowBookAllFee Money  --總費用
     Declare @iStudentFeeID     Int    --借書結算號

     --初始化  
     Set @mBorrowBookAllFee=0
     Set @iStudentFeeID=0

     --打開遊標
     Open curStudentFee  

     --循環並提取記錄
     Fetch Next From curStudentFee Into @iStudentFeeID     
     While ( @@Fetch_Status=0 )    
     begin

       --從借書記錄中計算某一學生的借書總記錄的總費用
       Select @mBorrowBookAllFee=Sum(BorrowBookAllFee)
         From BorrowRecord
         Where StudentFeeID=@iStudentFeeID     

       --更新到彙總表。
       Update StudentFee Set BorrowBookAllFee=@mBorrowBookAllFee
         Where StudentFeeID=@iStudnetFeeID           

       Fetch Next From curStudentFee Into @mFee
     end

     --關閉遊標    
     Close curStudentFee

     --釋放遊標
     Deallocate curStudentFee

關注遊標的要點:1、聲明、打開、關閉、釋放 ; 2、@@Fetch_Status 遊標提取狀態標誌,0表示正確

比較好的例子:
CREATE TRIGGER [TRGJCDNAME] ON dbo.TABLEJCD
FOR INSERT, UPDATE
AS
   DECLARE
   @CODE VARCHAR(50),
   @XS FLOAT,
   @ROWCOUNT INT
  --檢查代碼是否爲空
 
  //只支持1條操作,如果有多條操作則跳過
  IF @@ROWCOUNT>1 RETURN

  SELECT @CODE=LTRIM(ISNULL(CODE,'''')) FROM INSERTED
  IF @CODE=''''
  BEGIN
     ROLLBACK TRAN
     RAISERROR(''代碼不允許爲空或空格!'',16,1)
  END
  --檢查代碼是否有重複的
  SELECT @ROWCOUNT=COUNT(*) FROM TABLEJCD,INSERTED
  WHERE UPPER(TABLEJCD.CODE)=UPPER(INSERTED.CODE) AND (INSERTED.SYSTEMID=TABLEJCD.SYSTEMID)
  --如果有重複
  IF @ROWCOUNT>1
  BEGIN
      ROLLBACK TRAN
      RAISERROR(''代碼重複,請修改!'',16,1)
  END
  --不允許爲0或負數
  SELECT @XS=ISNULL(XS,0) FROM INSERTED
  IF @XS<=0
  BEGIN
      ROLLBACK TRAN
      RAISERROR(''不允許爲0或負數!'',16,1)
  END
2.當操作多條記錄時(及聯刪除或更新)
create trigger del_id on tablename for delete
as
  delete from tablename where id in(select id from deleted)
3.遞規觸發器
  create tablebudget
 (
  dept_name varchar(30) not null,
  part_name varchar(30) null,
  budget_amt money not null)
在上面的表,記錄之間是關聯,比如部門a,隸屬於部門b,頂級部門的父部門爲空,我們想到,子部門的預算更新時,其對應的父部門的預算,也要更新

create trigger update_budget
on budget for update as

if (@@rowcount>1)
begin
  print ''only on row can be update at a time''
  rollback tran
  return
end
if (select parent_name from inserted ) is null return
update
  set budget_amt=budget_amt+(select budget_amt from inserted)-
                     (select budget_amt from deleted)
where dept_name=(select parent_name from inserted)

更新時,其對應的父部門

RAISERROR 和@@error用法的不同點?

RAISERROR ( { msg_id | msg_str } { , severity , state }
    [ , argument [ ,...n ] ] )
    [ WITH option [ ,...n ] ]

severity 任何用戶都可以指定0到18,只有SYSADMIN固定服務器角色成員或具備alter trace 權限的
用戶纔可以指定19到25之間的嚴重級別。如果要使用19到25之間的嚴重級別,則必須選擇WITH LOG選項

state 爲1到127之間的數字

msg_str中可以用到格式參數
類型規範                         表示

d或i                              有符號整數
o                                  無符號八進制數
s                                 字符串
u                                 無符號整數
x或X                               無符號十六進制數

用例:
declare @count int
select @count=count(*) from jobs where max_lvl>1000
if @count=0
raiserror('有%d個max_lvl>1000的工作',16,1,@count)--》可自定製返回的信息
相應於vb,err.number可以取msg_id,而err.description可以取msg_str了


如果最後的 Transact-SQL 語句執行成功,則 @@ERROR 系統函數返回 0;如果此語句產生錯誤,則 @@ERROR 返回錯誤號。每一個 Transact-SQL 語句完成時,@@ERROR 的值都會改變。
@@error 是返回錯誤代碼,不是錯誤性信息

@@ROWCOUNT和@@ERROR變量的值,在執行完一條語句後總是會發生變化,所以我們將他們作爲判斷的依據的時候應該首先保存在局部變量中。他們反映的都是緊接着的上一條語句對他們的影響!

declare @sd int
set @sd=ABS(3.45)
 waitfor  delay  '00:00:10' ---》延時10秒鐘
print @sd

 

 

 

 

 

--聲明rs爲局域變量,否則第二次執行會報rs已定義的錯誤     

declare @s varchar(max); 

DECLARE rs CURSOR local FOR select OrgCode,ExchangeNum,SaleNum,LocalProductNum,OtherProductNum,SubsidyNum,[Year],[Month] from sdds

set @s='1';

OPEN rs 

declare @OrgCode float,@ExchangeNum float,@SaleNum float,@LocalProductNum float,@OtherProductNum float,@SubsidyNum float,@Year float,@Month float

 

FETCH NEXT FROM rs INTO @OrgCode,@ExchangeNum,@SaleNum,@LocalProductNum,@OtherProductNum,@SubsidyNum,@Year,@Month

WHILE @@FETCH_STATUS = 0

BEGIN

set @s='insert into T_Subsidy(OrgCode,ExchangeNum,SaleNum,LocalProductNum,OtherProductNum,SubsidyNum,Year,Month)values('+cast(@OrgCode as nvarchar)+','+cast(@ExchangeNum as varchar)+','+cast(@SaleNum as varchar)+','+cast(@LocalProductNum as varchar)+','+cast(@OtherProductNum as varchar)+','+cast(@SubsidyNum as varchar)+','+cast(@Year as varchar)+','+cast(@Month as varchar)+')';

 print @s

FETCH NEXT FROM rs INTO @OrgCode,@ExchangeNum,@SaleNum,@LocalProductNum,@OtherProductNum,@SubsidyNum,@Year,@Month

END

 

CLOSE  rs 

 

 

GO

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章