【发布时间】:2018-07-31 12:01:58
【问题描述】:
我正在使用 SQL Server 和系统版本化(临时)表。在我的主表中,我有一个 INT 列,该列当前允许 NULL。我想将其更新为不允许空值,但表的系统/历史副本允许空值。
我运行这个语句:
ALTER TABLE dbo.MyTable
ALTER COLUMN MyInt INT NOT NULL;
我得到这个错误:
无法将值 NULL 插入到列“MyInt”、表“mydb.dbo.MyTable_History”中;列不允许空值。更新失败。
我已经使用这个脚本创建了系统版本表:
ALTER TABLE dbo.MyTable
ADD
ValidFrom DATETIME2 (2) GENERATED ALWAYS AS ROW START HIDDEN CONSTRAINT DFMyTable_ValidFrom DEFAULT DATEADD(SECOND, -1, SYSUTCDATETIME()),
ValidTo DATETIME2 (2) GENERATED ALWAYS AS ROW END HIDDEN CONSTRAINT DFMyTable_ValidTo DEFAULT '9999.12.31 23:59:59.99',
PERIOD FOR SYSTEM_TIME (ValidFrom, ValidTo);
ALTER TABLE dbo.MyTable
SET (SYSTEM_VERSIONING = ON (HISTORY_TABLE = dbo.MyTable_History));
GO
在这种情况下,是否有其他方法可以使主表的列不可为空?我想我可以(也许)使用任意垃圾值手动更新现有的系统版本化空值,但似乎这种情况应该支持临时表。
【问题讨论】:
-
您可以尝试
ALTER TABLE ... WITH NOCHECK ADD CONSTRAINT CK_MyInt_NotNull CHECK (MyInt IS NOT NULL)在事后为新行添加约束,而无需检查现有行。 (免责声明:未经测试。)这有点不确定,因为它实际上与标记列NOT NULL不同,它会在重新导入数据时中断,但这也是您的方案失败的原因:版本化表版本数据,但是不是结构。任何成功的结构更改都会传播到历史记录表,即使它有效,也不会完全忠实于历史记录。 -
@JeroenMostert 在我的临时审计系统中,我将审计表保留为可为空,并将其留给主表以强制执行约束。希望这里可能有一种方法可以做同样的事情,因为似乎所有其他解决方法都不理想。感谢您的额外想法,我自己没想到。
-
临时表真的很酷,只要你的用例完全匹配它们的实现,如果它们略有不同,真的很令人沮丧。这是希望未来的版本(不是双关语)给我们历史查询善良,而不与引擎的实现非常密切的联系。
-
当你已经有空值时你不能这样做。更新它们或删除表。
标签: sql-server temporal-tables