【发布时间】:2011-06-08 04:06:09
【问题描述】:
如何创建类似于身份的自定义触发器或计算列?
我有两个字段需要按特定顺序自动递增:ID 和 REV。
图纸 身份证 |转 |信息 ------+--------+------ 1 | 0 | “画1” 2 | 0 | “画2” 2 | 1 | “Draw2Edit” 2 | 2 | “Draw2MoreEdit” 3 | 0 | 《画3》 4 | 0 | “画4”如果我要在我的表中插入更多记录,例如:
INSERT INTO DRAWINGS (INFO) VALUES ("Draw5")
INSERT INTO DRAWINGS (ID,INFO) VALUES (3,"Draw3Edit")
我的桌子想要:
图纸 身份证 |转 |信息 ------+--------+------ 1 | 0 | “画1” 2 | 0 | “画2” 2 | 1 | “Draw2Edit” 2 | 2 | “Draw2MoreEdit” 3 | 0 | 《画3》 3 | 1 | “Draw3Edit”——新行 4 | 0 | “画4” 5 | 0 | “Draw5”——新行伪代码
-- IF ID==NULL AND REV==NULL THEN IT IS A NEW DRAWING
IF INSERTED.ID IS NULL AND INSERTED.REV IS NULL
ID = SELECT MAX(ID)+1 FROM DRAWINGS
REV = 0
--INSERT HERE STATEMENT HERE
ELSE
-- IF ID!=NULL AND REV==NULL THEN IT IS A NEW REVISION
IF INSERTED.ID IS NOT NULL AND INSERTED.REV IS NULL
-- EXTRA CHECK TO ENSURE DRAWING ACTUALLY EXISTS
IF EXISTS(INSERTED.ID)
REV = SELECT MAX(REV) + 1 FROM DRAWINGS WHERE ID = INSERTED.ID
--INSERT HERE STATEMENT HERE
ELSE
--DRAWING DOES NOT ACTUALLY EXIST
GOTO ERROR
ELSE
--REV IS NOT NULL (REVISIONS ARE A COMPUTED VALUE ERROR)
GOTO ERROR
注意:
- 我正在使用 SQL Server 2000。
- 该表仅用于插入。
我想我已经接近了我想要的:
DROP TABLE DRAW
GO
CREATE TABLE DRAW
(
ID INT DEFAULT(0),
REV INT DEFAULT(-1),
INFO VARCHAR(10),
PRIMARY KEY(ID, REV)
)
GO
CREATE TRIGGER TRIG_DRAW ON DRAW
FOR INSERT
AS
BEGIN
DECLARE @newId INT,
@newRev INT,
@insId INT,
@insRev INT
SET TRANSACTION ISOLATION LEVEL READ COMMITTED
BEGIN TRANSACTION
SELECT @insId = ID FROM inserted
SELECT @insRev = REV FROM inserted
PRINT 'BEGIN TRIG'
PRINT @insId
PRINT @insRev
PRINT @newId
PRINT @newRev
--IF ID=0 THEN IT IS A NEW ID
IF @insId <=0
BEGIN
--NEW DRAWING ID=MAX+1 AND REV=0
SELECT @newId = COALESCE(MAX(ID), 0) + 1 FROM DRAW
SELECT @newRev = 0
END
ELSE
--ELSE IT IS A NEW REV
BEGIN
--CHECK TO ENSURE ID EXISTS
IF EXISTS(SELECT * FROM DRAW WHERE ID=@insId AND REV=0)
BEGIN
PRINT 'EXISTS'
SELECT @newId = @insId
SELECT @newRev = MAX(REV) + 1 FROM DRAW WHERE ID=@insID
AND REV=-1
END
ELSE
--ID DOES NOT EXIST THEREFORE NO REVISION
BEGIN
RAISERROR 50000 'ID DOES NOT EXIST.'
ROLLBACK TRANSACTION
GOTO END_TRIG
END
END
PRINT 'END TRIG'
PRINT @insId
PRINT @insRev
PRINT @newId
PRINT @newRev
SELECT * FROM DRAW
UPDATE DRAW SET ID=@newId, REV=@newRev WHERE ID=@insId
COMMIT TRANSACTION
END_TRIG:
END
GO
INSERT INTO DRAW (INFO) VALUES ('DRAW1')
INSERT INTO DRAW (INFO) VALUES ('DRAW2')
INSERT INTO DRAW (ID,INFO) VALUES (2,'DRAW2EDIT1') --PROBLEM HERE
INSERT INTO DRAW (ID,INFO) VALUES (2,'DRAW2EDIT2')
INSERT INTO DRAW (INFO) VALUES ('DRAW3')
INSERT INTO DRAW (INFO) VALUES ('DRAW4')
GO
--SHOULD THROW
INSERT INTO DRAW (ID,INFO) VALUES (9,'DRAW9')
GO
SELECT * FROM DRAW
GO
【问题讨论】:
-
你删除过行吗?如果是这样,那会发生什么?如果删除组中的最后一个,新插入的行是否会被赋予相同的值?值是顺序的重要吗?如果是这样,这将影响并发性,因为在事务回滚时需要阻止并发插入。
-
@Martin:这是一个很好的观点。该数据库旨在仅允许插入。顺序插入最好,但这不是必需的,所以 REV 0、1、2、6、7、8(其中 3..5 插入失败并被忽略)。
-
这实际上是相当困难的。试图想出一种解决方案,避免 2 个并发事务被分配相同的数字而不会阻塞。 are a couple of approaches here 他们需要调整才能与任意数量的子组一起工作。
-
使用 'INSTEAD OF INSERT' 的触发器如何像 BEFORE INSERT 一样工作?一个问题是它不允许 NULL。我可以使用 0 作为默认值并从 1 开始我的修订和绘图。我可以修改 inserted 表吗?如:插入的.REV = 1; INSERT INTO DRAWING(选择 * FROM 已插入);
-
@snmcdonald - 我已经发布的链接中的第二个版本的效率似乎略低!
标签: sql database tsql triggers sql-server-2000