帶條件的唯一標識符欄位
我有一個不在生產中的數據庫,所以主表是 CustodyDetails,這個表有一個
ID int IDENTITY(1,1) PRIMARY KEY
列,我正在尋找一種添加另一個唯一標識符的方法,該標識符在任何其他表中都沒有引用,我想通過考慮這個account 列的內容不會完全是身份密鑰。這個新的身份列有一些具體的細節,這就是我的問題開始的地方。格式如下:
XX/YY
其中XX是一個自動遞增值,每年重置/重新啟動,YY是目前年份的最後 2 位數字SELECT RIGHT(YEAR(GETDATE()), 2)
。因此,例如,假設從28/12/2015結束03/01/2016開始每天添加一條記錄,該列將如下所示:
ID ID2 DATE_ADDED 1 1/15 2015-12-28 2 2/15 2015-12-29 3 3/15 2015-12-30 4 4/15 2015-12-31 5 1/16 2016-01-01 6 2/16 2016-01-02 7 3/16 2016-01-03
我想過用前端解析複合ID(範例中為ID2)獲取最後2位數字並與目前年份的最後2位數字進行比較,然後決定是否開始新的關聯。當然,如果能夠在數據庫端完成所有這些工作,那就太好了。
**編輯1:**順便說一句,我還看到人們使用單獨的表來儲存並行標識鍵,所以一個表標識鍵成為第二個表輔助鍵,這聽起來有點狡猾,但也許這種實現就位了?
**編輯 2:**這個額外的ID 是標記每個文件/記錄的舊文件參考。我想人們可以將其視為主 ID 的特殊別名。
該數據庫每年處理的記錄數量在過去 20 年中沒有超過 100 條,而且非常(真的,非常非常高)不可能,當然,如果它確實超過 99 條,那麼該領域將能夠繼續使用額外的數字,前端/程序將能夠超過 99,所以它不會改變事情。
當然,其中一些細節我一開始沒有提到,因為它們只會縮小解決方案的可能性以適應我的特定需求,試圖讓問題範圍更廣。
您可以使用鍵表來儲存第二個 ID 列的遞增部分。該解決方案不依賴任何客戶端程式碼,並且自動感知多年;當
@DateAdded
參數傳入以前未使用的年份時,它將ID2
根據該年份自動開始為該列使用一組新值。如果 proc 因此用於插入前幾年的行,則這些行將插入“正確”的增量值。proc 旨在優雅地處理可能的GetNextID()
死鎖,只有在嘗試更新tblIDs
表時發生 5 個連續死鎖時才會將錯誤傳遞給呼叫者。創建一個表來儲存每年包含目前使用的 ID 值的一行,以及一個儲存過程以返回要使用的新值:
CREATE TABLE [dbo].[tblIDs] ( IDName nvarchar(255) NOT NULL, LastID int NULL, CONSTRAINT [PK_tblIDs] PRIMARY KEY CLUSTERED ( [IDName] ASC ) WITH ( PAD_INDEX = OFF , STATISTICS_NORECOMPUTE = OFF , IGNORE_DUP_KEY = OFF , ALLOW_ROW_LOCKS = ON , ALLOW_PAGE_LOCKS = ON , FILLFACTOR = 100 ) ); GO CREATE PROCEDURE [dbo].[GetNextID]( @IDName nvarchar(255) ) AS BEGIN /* Description: Increments and returns the LastID value from tblIDs for a given IDName Author: Max Vernon / Mike Defehr Date: 2012-07-19 */ SET NOCOUNT ON; DECLARE @Retry int; DECLARE @EN int, @ES int, @ET int; SET @Retry = 5; DECLARE @NewID int; WHILE @Retry > 0 BEGIN SET @NewID = NULL; BEGIN TRY UPDATE dbo.tblIDs SET @NewID = LastID = LastID + 1 WHERE IDName = @IDName; IF @NewID IS NULL BEGIN SET @NewID = 1; INSERT INTO tblIDs (IDName, LastID) VALUES (@IDName, @NewID); END SET @Retry = -2; /* no need to retry since the operation completed */ END TRY BEGIN CATCH IF (ERROR_NUMBER() = 1205) /* DEADLOCK */ SET @Retry = @Retry - 1; ELSE BEGIN SET @Retry = -1; SET @EN = ERROR_NUMBER(); SET @ES = ERROR_SEVERITY(); SET @ET = ERROR_STATE() RAISERROR (@EN,@ES,@ET); END END CATCH END IF @Retry = 0 /* must have deadlock'd 5 times. */ BEGIN SET @EN = 1205; SET @ES = 13; SET @ET = 1 RAISERROR (@EN,@ES,@ET); END ELSE SELECT @NewID AS NewID; END GO
您的表,以及用於在其中插入行的 proc:
CREATE TABLE dbo.Cond ( CondID INT NOT NULL CONSTRAINT PK_Cond PRIMARY KEY CLUSTERED IDENTITY(1,1) , CondID2 VARCHAR(30) NOT NULL , Date_Added DATE NOT NULL ); GO CREATE PROCEDURE dbo.InsertCond ( @DateAdded DATE ) AS BEGIN DECLARE @NextID INT; DECLARE @Year INT; DECLARE @IDName NVARCHAR(255); SET @Year = DATEPART(YEAR, @DateAdded); DECLARE @Res TABLE ( NextID INT NOT NULL ); SET @IDName = 'Cond_' + CONVERT(VARCHAR(30), @Year, 0); INSERT INTO @Res (NextID) EXEC dbo.GetNextID @IDName; INSERT INTO dbo.Cond (CondID2, Date_Added) SELECT CONVERT(VARCHAR(30), NextID) + '/' + SUBSTRING(CONVERT(VARCHAR(30), @Year), 3, 2), @DateAdded FROM @Res; END GO
插入一些範例數據:
EXEC dbo.InsertCond @DateAdded = '2015-12-30'; EXEC dbo.InsertCond @DateAdded = '2015-12-31'; EXEC dbo.InsertCond @DateAdded = '2016-01-01'; EXEC dbo.InsertCond @DateAdded = '2016-01-02';
顯示兩個表:
SELECT * FROM dbo.Cond; SELECT * FROM dbo.tblIDs;
結果:
密鑰表和儲存過程來自這個問題。