【发布时间】:2021-05-12 09:26:34
【问题描述】:
我想在不删除表/列的情况下将 SQL Server 中的现有列更改为计算并持久化。
我有一个自动递增的ID 和另一列ReportID,它是用这个计算格式化的:
ReportID = 'RPT'+{FiscalYear}+{0s}+{Auto Incremented ID}
例如:
- 对于 ID = 1, 2, ...., 10, 11, ..., 100, 101
- ReportID 将为
RPT2122000001、RPT2122000002、...、RPT2122000010、RPT2122000011、...、RPT2122000101、RPT2122000102
以前,我们在“插入后”触发器中执行此操作 - 计算值并更新行。但是通过这样做,当负载很高并且报告由不同的用户并行生成时,一些 ReportID 会出现重复。
所以,为了解决这个问题,我想用'RPT'+{FiscalYear}+{0s}+{Auto Incremented ID} 将现有列更改为计算列,但问题是我希望现有数据保持不变。因为如果现在计算,所有上一年的数据都将被修改为当前财政年度,这是错误的。
当我通过在 Management Studio 中设置计算值直接尝试时,它也在内部运行 drop 并在后台重新添加。
我看到了很多答案,但都不够满意。
我尝试使用计算值创建一个新列,然后尝试重命名,这也是不允许的。
编辑 1
错误:
Computed column 'ReportID' in table 'Tmp_wp_tra_report_creation' cannot be persisted because the column is non-deterministic
编辑 2
财政年度计算:
(select (case when ((select top 1 a.Pc_FromDate from wp_pc_calendar a where a.Pc_FromDate>=getdate())<=getdate()) then (select top 1 b.Pc_FinYear from wp_pc_calendar b where b.Pc_FromDate>=getdate() order by b.Pc_FromDate asc ) else (case when ((select top 1 c.Pc_FromDate from wp_pc_calendar c where c.Pc_FromDate<=getdate() )<=getdate()) then (select top 1 d.Pc_FinYear from wp_pc_calendar d where d.Pc_FromDate<=getdate() order by d.Pc_FromDate desc ) else 'No Records' end) end) as finyear)
另外,有没有不创建新列的方法?
【问题讨论】:
-
(1) 添加一个计算和持久化的 new 列,并检查是否一切正常。如果是,(2) 删除现有列和触发器,然后 (3) 将新列重命名为旧列的名称。您不能将现有列更改为“就地”computed 列-您需要创建新列/删除现有列-别无他法,抱歉
-
顺便说一句,你可以把它变成一个计算列,但是把它变成一个持久列几乎没有意义。如果您需要快速查找该列,请将其编入索引;这将理所当然地坚持下去。持久列现在真的只需要浮点列来使它们具有确定性,这是一种不寻常的情况。当您不能只索引计算列时,保留列的选项在以前版本的引擎中更有意义。
-
那么您不能按原样使用计算列。至少它必须执行类似
COALESCE(alreadystoredvalue, newcomputedcolumn)的操作,以便获取旧数据(如果存在)。PERSISTED不是的意思是“只计算一次并且保持不变”;如果您稍后更改数据,计算列将更新。 Demo。请注意,计算列也不能引用行外的值,除非是不稳定的 hack,例如调用函数,这会导致表不一致。 -
TL;DR 计算列必须是确定性的,这意味着它不能依赖于您计算值的时间,而只能依赖于行的当前状态。如果它确实取决于计算的时间,那么计算列不是正确的方法。如果触发器不适合您,则将其重写为事务安全或使用存储过程而不是简单的
INSERT,可能结合序列之类的东西来安全、可靠地生成递增值。跨度> -
您能否向我们展示一下触发器,以便我们了解您为什么会出现重复,因为可能有一个简单的修复方法。此外,财政年度似乎是基于当前日期的 - 您可以将其存储在参数表中,并根据需要安排工作以每天/每月/每年更新一次。此外,reportid 看起来像是一个显示值,可以在显示代码中计算出来。
标签: sql sql-server tsql computed-field