标签:
原文: T-SQL开发——ID处理篇
一般序号的产生,对于一般程序员而言,都是使用T-SQL命令来实现。先读取表中的最大需要,然后累加一,再插回数据库,这样做是相当危险的。因为如果事务机制没有处理好,就会出现同时间内取得同一序号。结果可想而知。为了避免这种情况,SQLServer在内部已经提供了一定的机制来协助处理。
use tempdb go --创建测试用的数据表 create table Employee ( en int not null identity, --自增ID ename varchar(50), --员工名称 keyDT datetime --创建日期 ); --插入数据,不指定列名 insert into Employee values(‘Lewis‘,‘2012/6/23‘); --插入数据,指定列名,但不指定自增列 insert into Employee(ename,keyDT) values(‘Ada‘,‘2012/6/24‘) go select * from Employee
use tempdb go --创建测试用的数据表 CREATE TABLE T1 ( XID INT NOT NULL IDENTITY, XNAME VARCHAR(10) ); GO CREATE TABLE T2 ( YID INT NOT NULL IDENTITY, YNAME VARCHAR(10) ); GO --插入3条数据到T2表中 INSERT INTO T2(YNAME) VALUES(‘name1‘),(‘name2‘),(‘name3‘); GO --建立T1的INSERT触发器,用于将T1的数据自动新增到T2的数据表中 CREATE TRIGGER tri_t1 ON t1 after insert as insert into t2(YNAME) select xname from inserted GO --编写存储过程将数据新增到t1数据表自动返回scope_identity()和@@Identity的值 create PROC uspTest ( @name varchar(10) ) as insert into t1 values(@name) select @@IDENTITY ‘@@identity‘,SCOPE_IDENTITY() ‘scope_identity‘,‘In Proc‘as ‘scope‘ go --使用存储过程测试:当scope_identity()是1时,@@identity是4 EXEC uspTest ‘Ada‘
use tempdb go --创建南方员工的数据表 CREATE TABLE Employee_S ( en timestamp not null,--自增二进制ID ename varchar(50),--员工名 keyDT datetime --创建时间 ) --创建中部员工的数据表 CREATE TABLE Employee_C ( en timestamp not null,--自增二进制ID ename varchar(50),--员工名 keyDT datetime --创建时间 ) --创建北方员工的数据表 CREATE TABLE Employee_N ( en timestamp not null,--自增二进制ID ename varchar(50),--员工名 keyDT datetime --创建时间 ) --插入数据: insert into Employee_S(ename,keyDT) values(‘Sname‘,GETDATE()) insert into Employee_C(ename,keyDT) values(‘Cname‘,GETDATE()) insert into Employee_N(ename,keyDT) values(‘Nname‘,GETDATE()) --显示数据 select ‘南方‘,* from Employee_S union all select ‘中部‘,* from Employee_C union all select ‘北方‘,* from Employee_N
use tempdb go --创建南方员工的数据表 CREATE TABLE Employee_GUID ( en uniqueidentifier not null,--自增二进制ID ename varchar(50)--员工名 ) --插入数据: insert into Employee_GUID(en,ename) values(newid(),‘Sname‘),(newid(),‘Cname‘),(newid(),‘Nname‘) --显示数据,为了证明不唯一,可以使用GROUP BY来检验: --源数据 select * from Employee_GUID --检验数据 select count(1) ‘Total‘,en from Employee_GUID group by en having count(1)>1
use tempdb go --产生NEWID()和NEWSEQUENTIALID(): SET NOCOUNT ON DECLARE @T TABLE (newSN uniqueidentifier,seqSN uniqueidentifier default (NEWSEQUENTIALID())) DECLARE @I INT SET @I=1 WHILE @I<=10 BEGIN INSERT INTO @T VALUES(NEWID(),DEFAULT) SET @I=@I+1 END SELECT * FROM @T SET NOCOUNT OFF执行后可以看到下图:注意每台机器值会不一样
use tempdb go --创建当天序号表 create table tabSN(sn int,sndt datetime) go --创建历史序号表 create table tabSNHist(sn INT,sndt datetime) go -- create proc uspSN ( @sn char(14) output ) as --开始事务 set xact_abort on begin transaction --判断序号表是否有数据,若没有则新增一条数据 if (select count(1) from tabSN)=0 begin insert into tabSN values(000000,GETDATE()) end --取出序号表中的日期 DECLARE @sndt datetime set @sndt=(select sndt from tabSN); --判断是否发生跨天情况,,若是则移动到历史表 if CONVERT(char(10),@sndt,111)<>CONVERT(char(10),getdate(),111) begin insert into tabSNHist select * from tabSN; truncate table tabSN; insert into tabSN values(000000,getdate()) end --将号码累加1,作为最后操作时间 update tabsn set sn=sn+1 ,sndt=GETDATE() --出去序号,转换成YYYYMMDDNNNNNN SELECT @sn=CONVERT(VARCHAR(10),SNDT,112)+RIGHT(‘000000‘+CONVERT(VARCHAR(6),SN),6) FROM tabSN; COMMIT TRANSACTION GO --使用存储过程产生序号 DECLARE @SN CHAR(14) EXEC uspSN @SN OUTPUT SELECT @SN ‘SN‘
--压力测试 --创建表存放测试结果 create table test ( sn char(14), sdt datetime , scomm varchar(100)--谁执行了存储过程 )
declare @cnt int set @cnt=1 while @cnt<=100 begin --执行存储过程 declare @sn char(14) exec uspsn @sn output --将结果新增到测试数据表 insert into test select @sn,GETDATE(),‘SPID‘+convert(varchar(5),@@spid) set @cnt=@cnt+1 waitfor delay ‘00:00:01‘ end go
select count(1), sn from test group by sn having count(1)>1
--检查是否发生跳号: SET NOCOUNT ON DECLARE @T TABLE (TID INT) DECLARE @MAX INT ,@MIN INT SET @MIN=(SELECT CONVERT(INT,RIGHT(MIN(SN),6)) FROM TEST) SET @MAX=(SELECT CONVERT(INT,RIGHT(MAX(SN),6)) FROM TEST) WHILE @MIN<=@MAX BEGIN INSERT INTO @T VALUES(@MIN) SET @MIN=@MIN+1 END SELECT TID ‘不连续号码‘ FROM @T EXCEPT SELECT CONVERT(INT,RIGHT(SN,6)) FROM TEST SET NOCOUNT OFF
select * from test order by sn
USE TEMPDB GO --创建订单表,订单号是主索引键不可以重复 --创建时间使用GETDATE()值 CREATE TABLE FruitOrderList ( orderID varchar(20) not null primary key, prodID int, qty int, region varchar(10), keyinDT datetime default (getdate()) ); GO --创建INSTEAD OF触发器 CREATE TRIGGER Tri_Int_FruitOrderList ON FruitOrderList INSTEAD OF INSERT AS SET NOCOUNT ON declare @oSN varchar(20) --产生新序号规则=日期+(总笔数+1) SELECT @oSN=CONVERT(VARCHAR(10),GETDATE(),112)+‘.‘+RIGHT(‘000000‘+CONVERT(VARCHAR(6),COUNT(1)+1),6) FROM FruitOrderList WHERE CONVERT(char(10),keyinDT,111)=CONVERT(CHAR(10),GETDATE(),111) --重新进行数据新增操作 INSERT INTO FruitOrderList SELECT @oSN,prodID,qty,region,keyinDT FROM inserted SET NOCOUNT OFF GO
--测试操作: --新增数据,注意订单编号是自动产生: INSERT INTO FruitOrderList VALUES(NULL,3,30,‘A‘,GETDATE()) INSERT INTO FruitOrderList VALUES(NULL,6,10,‘B‘,GETDATE()) INSERT INTO FruitOrderList VALUES(NULL,9,20,‘C‘,GETDATE()) INSERT INTO FruitOrderList VALUES(NULL,12,40,‘D‘,GETDATE()) SELECT * FROM FruitOrderList GO
USE AdventureWorks GO --使用FirstName进行序号的输出排序 SELECT ROW_NUMBER() OVER(ORDER BY FirstName),FirstName,JobTitle,EmailAddress FROM HumanResources.vEmployee WHERE JobTitle LIKE ‘%Engineer%‘ GO
标签:
原文地址:http://www.cnblogs.com/lonelyxmas/p/4317604.html