【发布时间】:2011-08-16 18:02:25
【问题描述】:
我有一个请求表,一旦它们被批准/拒绝,就需要为它们分配一个自定义顺序 ID,例如:
MYCODE-11-0001
MYCODE-11-0002
MYCODE-11-0003
其中MYCODE 不变,但11 是当前年份,0001 是按顺序生成的为年份分配的编号。所以每年都会从 0001 开始。
我从未在 SQL Sever 中处理过触发器或存储过程,因此我想到了通过 VB.net 中的 Linq-to-SQL 在代码中执行此操作,并且我在 SQL Server 中有另一个表来跟踪 @ 987654325@
ID NAME NextID
1 Request2011 102
2 Request2012 1
3 Request2013 1
如果他们更改了网站上的状态,应用程序会根据当前年份选择名称并获取NextID 并生成RequestID。如果NextID 在获取值、加一并尝试保存该新值后发生了变化,LINQ 甚至会捕捉到。
很确定这会起作用,但我对此并不完全满意,因为它假定一切都来自我的应用程序。如果它是在数据库级别完成的,我会感觉好多了,如果它不依赖我拥有的这个 NextID 表,我会感觉更好。
有没有什么触发器和存储过程不会太疯狂,可以让我生成这些自定义 ID?我有一个模糊的想法,当StatusID 更新以运行存储过程来执行一些繁重的工作时我可以运行触发器(如果尚未设置,则生成RequestID),但如果我仍然必须依赖NextID 表,那么我必须担心锁定/解锁表是否正确?
只是希望从比我更了解 SQL Server 的人那里得到一些建议。
注意:自定义 ID 仅在批准/拒绝请求时分配,而不是在将请求插入数据库时分配。每个请求都有自己唯一的自动生成身份 PK。
更新:我可能不得不坚持使用代码解决方案,因为它为我提供了所有的手,就并发而言,但我确实写了一个触发器,以便我可以学习。
/* --------------------
SETUP
--------------------*/
CREATE TABLE [dbo].[TestData](
[ID] [int] IDENTITY(1,1) NOT NULL,
[data] [varchar](100) NULL,
[RequestID] [varchar](25) NULL,
[StatusID] [int] NULL
)
INSERT INTO TestData
([data],[StatusID])
VALUES
('test',1)
GO
CREATE TABLE [dbo].[NextID](
[ID] [int] IDENTITY(1,1) NOT NULL,
[Name] [varchar](75) NULL,
[NextID] [int] NULL,
[DateModified] [date] NULL,
[ModifiedBy] [varchar](75) NULL
)
INSERT INTO NextID
([Name],[NextID])
VALUES('RequestID2011',1)
GO
/* --------------------
TRIGGER
--------------------*/
IF EXISTS (SELECT name FROM sys.objects
WHERE name = 'UpdateStatusID' AND type = 'TR')
DROP TRIGGER dbo.UpdateStatusID;
GO
CREATE TRIGGER UpdateStatusID
ON dbo.TestData
AFTER UPDATE
AS
IF ( UPDATE (StatusID))
BEGIN
DECLARE @nextId int
DECLARE @nextIdName varchar(50)
/* -- Get NextID based on year's count IE: RequestID2011 */
SET @nextIdName = 'RequestID' + CONVERT(VARCHAR, YEAR(GetDate()), 50)
SET @nextid = (Select NextID from dbo.NextID where Name = @nextIdName)
/* -- Increment NextID */
UPDATE dbo.NextID set NextID = @nextid + 1 WHERE Name=@nextIdName
/* -- Set New RequestID */
UPDATE dbo.TestData
SET RequestID = 'MYCODE-' + RIGHT(@nextIdName,2) + '-' + CONVERT(VARCHAR, REPLICATE('0', (4- LEN(@nextid))) + @nextid, 50)
FROM inserted i INNER JOIN dbo.TestData t
ON i.id = t.id
END;
GO
/* --------------------
TEST
--------------------*/
UPDATE dbo.TestData
SET StatusID = 3
WHERE ID = 1;
GO
这不能防止有人多次更改 StatusID(他们可以这样做,但我只需要生成一次 ID)或防止有人同时抓取 NextID 并拥有比赛条件问题。
这还需要我在数据库中有几条“RequestIDXXXX”的记录,以备将来使用。
警告:这不处理并发,只是我理解触发器和 SQL Server 的过程中的一项工作。
【问题讨论】:
-
您是否也在表中存储了日期时间值?每年不超过 9999 行?
-
我在 RequestID 的同时设置了一个审核日期。永远不要说永远,但每年的请求不应超过 2000 个。
-
您的触发器仅适用于插入的一条记录。如果您一次插入多条记录,它们都会以相同的序列 ID 结束。此外,您应该在更新您的数据表之前增加您的计数器。
-
如果发生两次更新,这不会导致两个触发器运行并且它们都将 ID 与插入的表匹配吗?更新了增量位置,但这个触发器没有很多其他问题,这就是为什么我不使用它并且确实提到这根本不处理并发。也许这可以帮助一些人在未来如何开始。
标签: .net sql sql-server-2008 linq-to-sql triggers