Sql-Server
SQL Server - 如何定義需要列名的預設值函式?
聲明預設列值時不允許使用列名。是否有解決方法來實現這樣的目標?
CREATE TABLE [dbo].[Tasks] ( [TaskId] INT IDENTITY(1,1) NOT NULL, [TaskName] NVARCHAR(255) NULL, [Priority] INT NOT NULL UNIQUE DEFAULT Max(Priority)+1, -- not allowed )
要求是預設情況下最新任務獲得最低優先級(最高 int 值)。在任務在表中之後,可以對其進行優先級/取消優先級,例如與表中的任何其他任務交換優先級值。
我會使用一個序列來實現它。
該序列每次呼叫時都會生成一個唯一編號,它滿足您在列
UNIQUE
上定義的約束。[Priority]
我們將使用它作為列值的預設值。USE tempdb; DROP TABLE IF EXISTS dbo.[Tasks]; DROP SEQUENCE IF EXISTS dbo.[tasks_priority_sequence] GO CREATE SEQUENCE dbo.[tasks_priority_sequence] AS int START WITH 1 INCREMENT BY 1 NO CYCLE CACHE; GO CREATE TABLE dbo.[Tasks] ( [TaskId] int NOT NULL IDENTITY(1,1) , [TaskName] nvarchar(255) NULL , [Priority] int NULL UNIQUE DEFAULT (NEXT VALUE FOR dbo.[tasks_priority_sequence]) ); GO INSERT INTO dbo.[Tasks] ([TaskName]) VALUES ('test1') , ('test2'); SELECT * FROM dbo.[Tasks];
結果:
雖然使用序列會引入間隙,但您可以向列提供任意值這一事實向我表明,您不需要在
[Priority]
列中嚴格單調遞增的值。如果間隙對您來說是個問題,您可以使用NO CACHE
pragma 重新定義序列,這將確保序列不會產生間隙。這種方法的一個警告是,如果您手動為尚未由序列生成的列分配值,則序列將導致錯誤。您可以使用觸發器而不是序列來解決這個問題,但是使用基於觸發器的解決方案的性能不會像使用序列那樣線性。下面是一個會導致錯誤的程式碼範例:
--this works just fine INSERT INTO dbo.[Tasks] (TaskName, [Priority]) VALUES ('test3', 3); --this fails since the next value for the sequence already exists in the UNIQUE index. INSERT INTO dbo.[Tasks] (TaskName) VALUES ('test4')
錯誤:
消息 2627,第 14 層,狀態 1,第 36 行 違反 UNIQUE KEY 約束“UQ__Tasks__534DF97B192F9781”。 無法在對象“dbo.Tasks”中插入重複鍵。重複鍵值為 (3)。