Một phương pháp tiềm năng để làm điều này sẽ là (xem phương pháp tốt hơn, ở cuối):
USE tempdb;
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
*/
DECLARE @Retry int;
DECLARE @EN int, @ES int, @ET int;
SET @Retry = 5;
DECLARE @NewID int;
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
SET NOCOUNT ON;
WHILE @Retry > 0
BEGIN
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
CREATE TABLE dbo.HumanReadableSequence
(
HumanReadableSequence_ID VARCHAR(20) NOT NULL
CONSTRAINT PK_HumanReadableSequence
PRIMARY KEY CLUSTERED
, SomeData VARCHAR(386) NOT NULL
);
GO
CREATE PROCEDURE dbo.HumanReadableSequence_Insert
(
@SomeData VARCHAR(386)
)
AS
BEGIN
SET NOCOUNT ON;
DECLARE @NextID INT;
DECLARE @Today VARCHAR(20);
DECLARE @t TABLE
(
ID INT NOT NULL
);
SET @Today = (CONVERT(VARCHAR(20), GETDATE(), 101))
INSERT INTO @t (ID)
EXEC dbo.GetNextID @IDName = @Today;
INSERT INTO dbo.HumanReadableSequence (HumanReadableSequence_ID, SomeData)
SELECT (@Today + '_' + CONVERT(VARCHAR(20), ID, 0))
, @SomeData
FROM @t;
END
GO
EXEC dbo.HumanReadableSequence_Insert N'this is a test';
SELECT *
FROM dbo.HumanReadableSequence;
Kết quả:
Đã nói tất cả những điều đó, tôi sẽ hỏi tại sao không chỉ đơn giản duy trì hai cột riêng biệt có thể được nối trong lớp trình bày:
CREATE TABLE dbo.HumanReadableSequence
(
CreateDate DATETIME NOT NULL
CONSTRAINT DF_HumanReadableSequence_CreateDate
DEFAULT (DATEADD(DAY, 0, DATEDIFF(DAY, 0, GETDATE())))
, HumanReadableSequence_ID INT NOT NULL
, SomeData VARCHAR(386) NOT NULL
, CONSTRAINT PK_HumanReadableSequence
PRIMARY KEY CLUSTERED
(CreateDate, HumanReadableSequence_ID)
);
DECLARE @ID INT;
DECLARE @t TABLE
(
ID INT NOT NULL
);
DECLARE @Today VARCHAR(20);
SET @Today = (CONVERT(VARCHAR(20), GETDATE(), 101))
INSERT INTO @t (ID)
EXEC dbo.GetNextID @IDName = @Today;
SELECT @ID = t.ID
FROM @t t;
INSERT INTO dbo.HumanReadableSequence (SomeData, HumanReadableSequence_ID)
VALUES ('This is a test', @ID);
SELECT HumanReadableSequenceValue =
REPLACE(CONVERT(VARCHAR(20), hrs.CreateDate, 101)
+ '_'
+ CONVERT(VARCHAR(20), hrs.HumanReadableSequence_ID, 0), '/', '-')
, SomeData
FROM dbo.HumanReadableSequence hrs;
Kết quả:
Phương pháp trên có khả năng mở rộng tốt hơn nhiều và cung cấp sự linh hoạt trong việc trình bày số thứ tự có thể đọc được của con người.