我想基于自定义标识创建自定义标识。或者类似于一个类似于自动递增键的身份的东西。
例如,如果我有一个绘图的主键,我希望它的修订版基于图纸编号。
示例
DRAWING ID | REV | INFO ------+-------+------ 1 | 0 | "Draw1" 2 | 0 | "Draw2" 2 | 1 | "Draw2Edit" 2 | 2 | "Draw2MoreEdit" 3 | 0 | "Draw3" 4 | 0 | "Draw4"
如果我要在表格中插入更多记录,请执行以下操作:
INSERT INTO DRAWING (INFO) VALUES ("Draw5")
INSERT INTO DRAWING (ID,INFO) VALUES (3,"Draw3Edit")
我的表格想:
DRAWING ID | REV | INFO ------+-------+------ 1 | 0 | "Draw1" 2 | 0 | "Draw2" 2 | 1 | "Draw2Edit" 2 | 2 | "Draw2MoreEdit" 3 | 0 | "Draw3" 3 | 1 | "Draw3Edit" --NEW ROW 4 | 0 | "Draw4" 5 | 0 | "Draw5" --NEW ROW
T-SQL
CREATE TABLE DRAWING
(
ID INT,
REV INT,
INFO VARCHAR(50),
PRIMARY KEY (ID,REV)
);
CREATE TABLE CURRENT_DRAWING
(
ID INT IDENTITY (1,1),
DRAWING_ID INT,
DRAWING_REV INT,
PRIMARY KEY (ID),
FOREIGN KEY (DRAWING_ID,DRAWING_REV) REFERENCES DRAWING (ID,REV)
ON UPDATE CASCADE
ON DELETE CASCADE
);
我正在使用 SQL Server Management Studio 2005 并使用 SQL Server 2000 数据库。
我也会接受可能的替代方案。主要目标是ID为新图纸自动递增。 ID将保持不变,REV将在新的图纸修订中递增。
我认为我接近我想要的东西:
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
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
但是,我不断获得Violation of PRIMARY KEY constraint
。
我已经放了调试语句,我似乎不太可能违反了我的主键:
BEGIN TRIG 0 -1 END TRIG 0 -1 1 0 (1 row(s) affected) (1 row(s) affected) (1 row(s) affected) BEGIN TRIG 0 -1 END TRIG 0 -1 2 0 (2 row(s) affected) (1 row(s) affected) (1 row(s) affected) BEGIN TRIG 2 -1 EXISTS END TRIG 2 -1 2 1 (3 row(s) affected) Msg 2627, Level 14, State 1, Procedure TRIG_DRAW, Line 58 Violation of PRIMARY KEY constraint 'PK__DRAW__56D3D912'. Cannot insert duplicate key in object 'DRAW'. The statement has been terminated.
打印
ID | REV | INFO ----+--------+------------ 1 | 0 | DRAW1 2 | -1 | DRAW2EDIT1 --This row is being updated to 2 1 2 | 0 | DRAW2
就在它失败之前,第2行被更新为2 1.它不应该违反我的主键。
答案 0 :(得分:2)
您可以创建一个设置转速值
的插入触发器CREATE TRIGGER RevTrigger ON DRAWING
FOR INSERT
AS
WITH ins AS
(
SELECT ID, ROW_NUMBER() OVER (PARTITION BY ID ORDER BY {another-column}) AS sequence
FROM inserted
WHERE REV IS NULL -- only update rows where REV is not included
),
draw AS
(
SELECT ID, MAX(REV) AS REV
FROM DRAWING
GROUP BY ID
)
UPDATE DRAWING
SET REV = COALESCE(draw.REV + ins.sequence, 0)
FROM DRAWING
JOIN ins ON DRAWING.ID = ins.ID AND DRAWING.{another-column} = ins.{another-column}
JOIN draw ON DRAWING.ID = draw.ID
如果同时插入具有相同ID值的多行,则不指示如何分配REV值。换句话说,如果同时添加多个修订版,将如何分配修订版?
此解决方案假设在这种情况下还有一个额外的列将确定修订顺序(请参阅上面的{another-column})。如果您没有这样的列,请在ORDER BY {another-column}
函数中使用ORDER BY 0
更改ROW_NUMBER
。并删除以下AND DRAWING.{another-column} = ins.{another-column}
。进行此更改后,插入中具有相同ID的所有行将获得相同的REV。
修改强>
上面的脚本仅适用于SQL Server 2005及更高版本。这是一个适用于SQL Server 2000的解决方案,但没有解决一个插入中多个修订的问题。
CREATE TRIGGER RevTrigger ON DRAWING
FOR INSERT
AS
UPDATE DRAWING
SET REV = COALESCE(draw.REV + 1, 0)
FROM DRAWING
JOIN inserted ON DRAWING.ID = inserted.ID AND DRAWING.{another-column} = inserted.{another-column}
AND inserted.REV IS NULL
JOIN
(
SELECT ID, MAX(REV) AS REV
FROM DRAWING
GROUP BY ID
) AS draw ON DRAWING.ID = draw.ID
答案 1 :(得分:2)