2015-07-13 122 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 ...