本文將介紹利用 DML Trigger 及 SEQUENCE 物件,讓您在新增資料到資料表時,依據特定規則產生編號。
【情境描述】
有網友在論壇上討論到如何在新增資料時,利用 Trigger 產生具特定規則的編號或流水號,筆者依照發問者的描述嘗試實作可能的解決方案。
【實作步驟】
您可以利用 DML Trigger 在 Insert 動作發生時,由更新資料表 t 的 roadCode 資料行,其規則是 DL 加上五位的流水號,因此筆者在 Trigger 中利用 inserted 邏輯資料表取得目前該筆資料的 id,接著利用字串函數 REPLICATE 搭配 RIGHT 來取得五位數的流水號。
use tempdb
go
if object_id('t') is not nulldrop table tgo
create table t([id] int identity,[roadName] char(1),
[roadCode] nvarchar(10))go
--建立ddl trigger
create trigger tr_insert_ton t
for insert
as
update t
set roadCode = 'DL' + right(replicate('0',5) + convert(varchar(5),id),5)where id = (select id from inserted)go
insert t([roadName]) values ('a')insert t([roadName]) values ('b')insert t([roadName]) values ('c')go
select *
from t
上述的寫法其實有個問題,如果您使用資料表值建構函式來新增資料到資料表 t 時,這個 DML Trigger 的寫法就會出錯,因為使用資料表值建構函式新增資料時,Inserted 邏輯資料表會有多筆資料,導致子查詢回傳多個結果,因而發生錯誤(如下圖)。
因此 DML Trigger 應該修改為下列的樣子,才能避免上述問題。
create trigger tr_insert_ton t
for insert
as
update t
set roadCode = 'DL' + right(replicate('0',5) + convert(varchar(5),inserted.id),5)from t
join inserted
on t.id = inserted.id
go
如果不一定要使用 Trigger,利用 SQL Server 2012 新的 SEQUENCE 物件也可以達到相同的目的,在 roadCode 資料行的預設值中搭配 NEXT VALUE FOR 函數取得流水號之後再去組合您所要的編號,一樣可以輕鬆地完成任務。
use tempdb
go
--#region 建立Sequence物件if object_id ('seqRoadCode') is not nulldrop sequence seqRoadCodego
create sequence seqRoadCodeas intstart with 1minvalue 1maxvalue 99999increment by 1
go
--#endregionif object_id('t') is not nulldrop table tgo
create table t([id] int identity,[roadName] char(1),
[roadCode] nvarchar(10)default 'DL' + right(replicate('0',5) + convert(varchar(5),next value for seqRoadCode),5))go
insert t([roadName]) values ('a'),('b'),('c')go
select *
from t
【參考資料】
- CREATE TRIGGER (Transact-SQL)
- CREATE SEQUENCE (Transact-SQL)
- 序號
【補充說明】
朋友 James 根據筆者上述的文章內容指出,建議應在 Trigger 處理資料前,先加上 SET NOCOUNT ON,以避免原本異動的資料筆數被 Trigger 所更新的筆數給影響,造成其他程式邏輯判斷上的錯誤。