如果表中的主键Map
是单列Id
,那么Images
表中的外键实际上只是列MapId
,它引用Id
父表上的列。
如果表上的主键Map
是单列Id
,那么您将无法插入与 具有相同值的另一行Id
。
可以为 IDENTITY 列插入具有指定值的行,但是你必须做一个SET IDENTITY_INSERT tablename ON
语句,然后你必须记住做一个相应的SET IDENTITY_INSERT tablename OFF
语句。
为了实现 Map 表内容的历史记录,我会考虑创建一个单独的“MapHistory”表来存储更改历史记录,并使用触发器来维护它。
CREATE TABLE MapHistory (
[change_date] datetime NOT NULL,
[Id] int NOT NULL,
[CreatedAt] datetime NOT NULL,
...
要存储更新前行的“历史记录” Map
,您可以引用deleted
触发器中的特殊逻辑表。(为了完整起见,当从 Map 表中删除一行时,我还可能在历史表中存储一行。)
CREATE TRIGGER map_update ON Map AFTER UPDATE,DELETE AS
BEGIN
SET NOCOUNT ON
-- store column values as they existed prior to the update or delete
INSERT MapHistory (change_date, Id, CreatedAt, ... )
SELECT CURRDATE(), Id, CreatedAt, ... FROM deleted
END
使用这种方法,您的代码可以简单得多。您需要做的就是UPDATE
在Map
表上执行,数据库将负责维护 MapHistory 表。
这种方法的一个小缺点是现在“当前”值在一个表中,而先前值的历史记录在另一个表中。
如果您希望将当前值也存储在MapHistory
表中,则可以修改触发器以改为触发AFTER INSERT, UPDATE
,并改为引用特殊逻辑inserted
表,以便将插入的更新行的“副本”创建到历史表中。
也可以在历史记录表中同时存储“旧”和“新”行,但这样您实际上会存储冗余数据。在这种情况下,您可能希望包含一个列,指示该行是来自“已删除”表还是“插入”表。
CREATE TRIGGER map_update ON Map AFTER INSERT,UPDATE,DELETE AS
BEGIN
SET NOCOUNT ON
-- store column values as they existed prior to an update or delete
INSERT MapHistory (source, change_date, Id, CreatedAt, ... )
SELECT 'D', CURRDATE(), Id, CreatedAt, ... FROM deleted
-- store column values as they exist after an update or insert
INSERT MapHistory (source, change_date, Id, CreatedAt, ... )
SELECT 'I' CURRDATE(), Id, CreatedAt, ... FROM inserted
END
附录:
这种方法允许您将Id
IDENTITY 作为Map
表中的简单主键。我认为change_date
我在表格中添加的列MapHistory
可能是多余的,它可能符合您为该CreatedAt
列指定的目的。