来自其他表的计算列作为主键SQL Server

时间:2018-10-24 07:31:23

标签: sql-server

我找到了几篇相关的文章,但没有人回答我的问题。在SQL Server上是否可以从另一个表的计算列中创建主键?

我有此功能,将从剧院表中获取日期时间:

CREATE FUNCTION GetTransactionDate(@tranid nchar(18))
RETURNS DATETIME
AS
BEGIN
    DECLARE @dtstamp DATETIME
    SELECT @dtstamp = dtstamp FROM theader 
        WHERE transactionid = @tranid ORDER BY dtstamp ASC
    RETURN @dtstamp
END
GO

我正在尝试更改现有的tdetail表以添加新的PK dtstamp

-- Drop existing constraints
ALTER TABLE tdetail
    DROP CONSTRAINT [PK_tdetail]

-- Add new column
ALTER TABLE tdetail
    ADD dtstamp AS GetTransactionDate(transactionid)

-- Re-create constraints with dtstamp
ALTER TABLE tdetail
    ADD CONSTRAINT [PK_tdetail] PRIMARY KEY CLUSTERED(transactionid, offerid, divisionid, dtstamp)

我们的transactionid的有效期仅为一年(dayOfYear + "." + generatedSequence),并且我们计划将其保留期限再延长几年,这就是为什么我们试图将dtstamp用作主键。

**theader table**
transactionid                 dtstamp
269.A0000009           2017-09-26 20:00:00.000
269.A0000009           2018-09-26 20:25:21.973

**tdetail table**
269.A0000009  
269.A0000009    (ERROR – duplicate PK)

如果无法使用计算列,哪种方法更好?

更新

我想过一种更好的方法:添加具有默认值YEAR(GETDATE())的可空列->将表从null dtstamp更新为theader的值->最后将dtstamp列更改为not null并使其成为主键。这个可以吗?我只是将tdetails.dtstamp设为smallint,当我加入theader和tdetails时-我将使where子句等于YEAR(theader.dtstamp)。有想法吗?

2 个答案:

答案 0 :(得分:1)

对于在计算列上创建约束,必须将其声明为持久化,如果已将计算列定义为不确定性,则不能这样做。您的函数不是确定性的,因此不能将其用作约束。

我认为,最好的方法是在ader表上插入/更新触发器,这将更新表tdetail中的相关行。

答案 1 :(得分:1)

您不能将其添加到PK:

  

如果计算列的值由确定性表达式定义且数据类型为,则计算列可用作索引中的键列或任何PRIMARY KEY或UNIQUE约束的一部分。结果允许在索引列中。   -CREATE TABLE (Transact-SQL)

如果您在用户定义的函数中引用任何表,则该表是不确定的。

  

如果无法使用计算列,哪种方法更好?

请勿将其添加到PK。据我了解,transactionid唯一地标识它的日期,因此将其添加到PK /集群键中是没有意义的,甚至更糟的是,它可能带来额外的开销-请记住,集群键是任何非集群索引的一部分:

  

如果表具有聚集索引,或者索引位于索引视图上,则行定位符是该行的聚集索引键。 -Nonclustered Index Architecture