SQL Server - 如何定义需要列名的默认值函数?

Paw*_*wel 0 sql-server default-value table

声明默认列值时不允许使用列名。有没有解决方法来实现这样的目标?

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
)
Run Code Online (Sandbox Code Playgroud)

要求是默认情况下最新的任务获得最低优先级(最高 int 值)。在任务在表中之后,它可以被优先化/去优先化,例如优先级值与表中的任何其他任务交换。

Han*_*non 5

我会使用序列来实现这一点。

每次调用该序列时都会生成一个唯一编号,它满足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];

Run Code Online (Sandbox Code Playgroud)

结果:

任务 ID 任务名称 优先事项
1 测试1 1
2 测试2 2
3 测试1 3

虽然使用序列可能会引入间隙,但您可以向列提供任意值这一事实向我表明您不需要[Priority]列中严格单调递增的值。如果间隙对您来说是个问题,您可以使用NO CACHE编译指示重新定义序列,以确保序列不会产生间隙。

这种方法的一个警告是,如果您手动为序列尚未生成的列分配值,序列将导致错误。您可以使用触发器而不是序列来解决这个问题,但是使用基于触发器的解决方案的性能不会像使用序列那样线性。以下是会导致错误的代码示例:

--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')
Run Code Online (Sandbox Code Playgroud)

错误:

消息 2627,级别 14,状态 1,第 36 行
    违反 UNIQUE KEY 约束“UQ__Tasks__534DF97B192F9781”。 
无法在对象“dbo.Tasks”中插入重复键。重复的键值为 (3)。