我找到了几篇相关的文章,但没有人回答我的问题。在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)
。有想法吗?
答案 0 :(得分:1)
对于在计算列上创建约束,必须将其声明为持久化,如果已将计算列定义为不确定性,则不能这样做。您的函数不是确定性的,因此不能将其用作约束。
我认为,最好的方法是在ader表上插入/更新触发器,这将更新表tdetail中的相关行。
答案 1 :(得分:1)
您不能将其添加到PK:
如果计算列的值由确定性表达式定义且数据类型为,则计算列可用作索引中的键列或任何PRIMARY KEY或UNIQUE约束的一部分。结果允许在索引列中。 -CREATE TABLE (Transact-SQL)。
如果您在用户定义的函数中引用任何表,则该表是不确定的。
如果无法使用计算列,哪种方法更好?
请勿将其添加到PK。据我了解,transactionid唯一地标识它的日期,因此将其添加到PK /集群键中是没有意义的,甚至更糟的是,它可能带来额外的开销-请记住,集群键是任何非集群索引的一部分:
如果表具有聚集索引,或者索引位于索引视图上,则行定位符是该行的聚集索引键。 -Nonclustered Index Architecture