如何命名表变量函数唯一约束?

got*_*tqn 8 t-sql sql-server-2012 set-returning-functions unique-constraint table-variable

我正在重命名一些独特的约束以匹配我们的数据库对象命名约定。奇怪的是,有几个多行表值函数返回的表具有唯一约束,如下所示:

CREATE FUNCTION [dbo].[fn_name] (...)
RETURNS @Result 
TABLE
(
    ID BIGINT PRIMARY KEY,
    ...
    RowNum BIGINT UNIQUE 
)
BEGIN
    ...
    RETURN
END
GO
Run Code Online (Sandbox Code Playgroud)

我尝试这样命名它,但不起作用:

CREATE FUNCTION [dbo].[fn_name] (...)
RETURNS @Result 
TABLE
(
    ID BIGINT PRIMARY KEY,
    ...
    RowNum BIGINT
    ,CONSTRAINT UC_fn_name_RowNum UNIQUE([RowNum])  
)
BEGIN
    ...
    RETURN
END
GO
Run Code Online (Sandbox Code Playgroud)

当它是表变量函数定义的一部分时,是否可以设置唯一约束的名称?

Sol*_*zky 8

表变量,无论是从语句中的aDECLARE还是从 aRETURNS中创建的CREATE FUNCTION,以及用户定义的表类型 (UDTT),都不允许命名约束。根据CREATE FUNCTION的 MSDN 页面:

参数
...
        < column_constraint >::= 和 < table_constraint>::=
        ... 不允许命名约束。

此规则的“声明”例外可在DECLARE @local_variable的 MSDN 页面上找到,其中指出(在DEFAULT的解释下):

为了保持与早期版本的 SQL Server 的兼容性,可以将约束名称分配给 DEFAULT。

但是,这似乎是文档的错误,因为我无法为 DEFAULT 约束分配名称,没有完成此操作的语法描述,并且文档中没有执行此操作的示例(我查看了早在 SQL Server 2000 中)。

当涉及到临时表时,问题更直接一些:如果您明确命名任何约束,这将禁止代码同时在两个不同的会话中运行。约束是对象(与索引不同)并且需要在同一架构中具有唯一的名称。因此,如果某些代码创建了一个具有给定名称约束的本地临时表,那么如果两个会话同时运行该代码,由于名称冲突,第二个会话在创建其临时表时会出错(发生在tempdb,其中存在临时表)。例如,在 SSMS 的一个查询选项卡中运行以下命令:

CREATE TABLE #Session1 (Col1 INT NOT NULL CONSTRAINT [UQ_DifferentSession] UNIQUE);
Run Code Online (Sandbox Code Playgroud)

在另一个查询选项卡中,运行以下命令:

CREATE TABLE #Session2 (Col1 INT NOT NULL CONSTRAINT [UQ_DifferentSession] UNIQUE);
Run Code Online (Sandbox Code Playgroud)

即使临时表除了是在不同会话中创建的本地临时表之外还有不同的名称,您仍然会收到以下错误:

消息 2714,级别 16,状态 5,第 1 行
数据库中已经有一个名为“UQ_DifferentSession”的对象。
消息 1750,级别 16,状态 0,行 1
无法创建约束。请参阅以前的错误。

与临时表类似,表变量在“声明”之前也没有任何定义,然后该定义仅驻留在tempdb. 但是我们无法测试表变量的名称冲突,因为您无法命名它们的约束。

另一方面,多语句 TVF 中的返回表和用户定义的表类型的存在与临时表略有不同,因为它们将定义存储在它们所在的数据库中。但是它们存储在本地数据库中的元数据实际上从未用于存储数据;它们的元数据仅用作将在tempdb. 当使用该元数据“模板”时,tempdb(主键、唯一约束、默认约束和检查约束)中的命名对象以UQ__#BC4FB52__A259EE56FAB8BB6F.


关于命名约束以符合命名约定的愿望(如对问题的评论所述):

虽然使用它不会有任何伤害sp_rename(如@Peter 的回答中所指出的),但这只是表面的变化。拥有命名约定的主要原因之一是为了维护,这样如果您以后需要ALTERDROP对象,您就无需编写查询来发现其中的内容,然后将其连接到动态 SQL 中。但这种担忧在这里无关紧要,因为无论如何都没有办法ALTERDROP他们。

此外,任何通过的名称更改都sp_rename将是短暂的,因为任何更改ALTER FUNCTION都会删除并重新创建约束,从而为它们提供新生成的对象名称。这可能可以使用捕获CREATE FUNCTIONALTER FUNCTIONCREATE TYPE语句的 DDL 触发器以编程方式处理,但这种努力的最终结果不会是您的生活变得更轻松;-)。这纯粹是从选择sys.objectssys.indexessys.key_constraints看起来“干净”。