2015-07-13 60 views
7

我创建了一个计算列作为主键的表。 表创建fine.And这里是脚本..SQL Server计算列作为主键

SET ANSI_NULLS ON 
GO 

SET QUOTED_IDENTIFIER ON 
GO 

SET ARITHABORT ON 
GO 

SET ANSI_PADDING ON 
GO 

CREATE TABLE [planning.A062].[RMAllocation](
    [Id] [int] IDENTITY(100,1) NOT NULL, 
    [RMAllocatonId] AS ('RMA_'+CONVERT([nvarchar](100),[Id])) PERSISTED NOT NULL, 
    [RequsitionNo] [nvarchar](100) NULL, 
    [RMDemandId] [nvarchar](104) NULL, 
    [HierarchyId] [nvarchar](102) NULL, 
    [Season] [nvarchar](50) NULL, 
    [VendorSupplierNo] [nvarchar](100) NULL, 
    [Year] [int] NULL, 
    [Month] [int] NULL, 
    [Week] [int] NULL, 
    [Day] [int] NULL, 
    [PlannedQty] [int] NULL, 
    [ConfirmedQty] [int] NULL, 
    [Status] [int] NULL, 
    [CreatedBy] [int] NULL, 
    [SyncId] [nvarchar](100) NULL, 
    [CreatedOn] [datetime2](7) NULL, 
    [UpdatedBy] [int] NULL, 
    [UpdatedOn] [datetime2](7) NULL, 
    [IsActive] [bit] NULL, 
    [RecordDateTime] [datetime2](7) NULL, 
CONSTRAINT [PK_RMAllocation] PRIMARY KEY CLUSTERED 
(
    [RMAllocatonId] ASC 
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] 
) ON [PRIMARY] 

GO 

SET ANSI_PADDING OFF 
GO 

问题是,当我改变这个表(添加/编辑列)使用设计器视图,它给了我下面的错误。

enter image description here

错误

Unable to create index 'PK_RMAllocation'. 
Cannot define PRIMARY KEY constraint on nullable column in table 'RMAllocation'. 
Could not create constraint. See previous errors. 

当我使用脚本来完成修改,它的工作原理。即使我已经宣布计算列为NOT NULL。这是怎么发生的?

+0

你为什么要这么做?我从来没有想过计算列是PK ... – Shnugo

+0

这就是要求 – tarzanbappa

+0

我认为计算列在插入时没有值... – Shnugo

回答

11

这太长了评论。设计师有些不妥。在计算列可将用于主键(例如,here)的文档中,SQL Server非常明确。

我的猜测是设计师正在删除表格中的所有约束并重新添加它们。它最终以错误顺序添加它们,因此主键被分配在计算列上的not null之前。除了明显的不使用设计师之外,我不知道是否有任何解决方法。

+3

不使用GUI设计器是一个很好的解决方法:-) –

+0

不应该使用设计器来完成设计,并且永远不应该使用它进行更改。应该生成脚本并将其放在Source控件中,以便它们可以移动到其他服务器。 – HLGEM

+0

SSMS设计师与这个问题无关。错误来自数据库引擎。请参阅Martin的答案以获得正确答案。正如我在他的回答评论中指出的那样:本文档(https://technet.microsoft.com/en-US/library/ms191250.aspx)说:“用作CHECK,FOREIGN KEY或NOT NULL约束的计算列必须被标记为“持久”。“它还指出:“通过指定ISNULL(check_expression,常量),一个可为空的表达式可以变成不可空的表达式,其中常量是一个非空值,用于替代任何空结果。” –

0

在插入时,系统不知道新的[id]值。您需要一个稍后更新值的触发器。

+0

它不在插入时。它在设计级别即将到来 – tarzanbappa

+0

我明白了。问题是你不能有一个主要索引的空值。在我看来,您可以:1.-在视图中为RMA创建一列。 2.-从主索引中删除计算列。 –

5

根据the documentation(重点煤矿)

计算列不能用作默认或外键 约束定义或具有NOT NULL约束定义

因此,即使在TSQL中它可以工作也可能有点令人惊讶。

当设计者通过重新创建表来实现更改时,它会在列定义上丢失NOT NULL

[Id] [int] IDENTITY(100,1) NOT NULL, 
[RMAllocatonId] AS ('RMA_'+CONVERT([nvarchar](100),[Id])) PERSISTED, 
[RequsitionNo] [nvarchar](100) NULL, 

语义一个NOT NULL不变的这个级联和NOT NULL列永远不能NULL反正。

你能说服SQL Server的另一种方式,该列将NOT NULL -able即使在没有NOT NULL的是通过在ISNULL包装的定义。

下正常工作与设计师

[RMAllocatonId] AS (ISNULL('RMA_'+CONVERT([nvarchar](100),[Id]),'')) PERSISTED 
+1

这里引用的文档是指_non_-persisted计算列。此文档(https://technet.microsoft.com/en-US/library/ms191250.aspx)说:“用作CHECK,FOREIGN KEY或NOT NULL约束的计算列必须标记为”PERSISTED“。”它还指出:“通过指定ISNULL(check_expression,常量),一个可为空的表达式可以变成不可空的表达式,其中常量是一个非空值,用于替代任何空结果。” –

+0

@srutzky谢谢。说得通。 –

0

当两个Id值是相同的,相应的RMAllocatonId值将是相同的。当两个Id值不同时,对应的RMAllocatonId值将会不同。因此使Id独一无二等于使RMAllocatonId独一无二。

如果你问我,只是把Id它属于哪里,并用它做的PRIMARY KEY ...