背景故事
在我们计划在我们的一个主表中弃用自然键列的工作中。该项目包含 100 多个链接到此表/列的应用程序;400 多个直接引用此列的存储过程;以及这些应用程序之间的大量公用表也引用了此列。
生活大爆炸和从头开始的方法不在图片中。我们将一次弃用本专栏一个应用程序,验证更改,然后继续下一个……我们有一个长期的目标来使这项工作切实可行。
我遇到的问题是很多这些应用程序都有共享的存储过程和表。如果我完全转换应用程序 A 的所有表/存储过程,应用程序 B 和 C 将被破坏,直到转换。这些反过来可能会破坏应用程序 D、E、F...等。我已经为代码类和存储过程实现了一个策略,我坚持的部分是数据库的转换状态。
这是我们所拥有的基本示例:
Users
---------------------------
Code varchar(32) natural key
Access
---------------------------
UserCode varchar(32) foreign key
AccessLevel int
我们现在的目标只是像这样的过渡状态:
Users
---------------------------
Code varchar(32)
Id int surrogate key
Access
---------------------------
UserCode varchar(32)
UserID int foreign key
AccessLevel int
在过渡阶段的想法是,未迁移的应用程序和存储过程仍然能够访问所有适当的数据,并且新的数据可以开始推送到正确的列——一旦所有存储过程和应用程序的迁移完成,我们终于可以删除额外的列。
我想使用 SQL Server 的触发器自动拦截任何新的插入/更新,并对每个受影响的表执行以下操作:
CREATE TRIGGER tr_Access_Sync
ON Access
INSTEAD OF INSERT(, UPDATE)
AS
BEGIN
DIM @code as Varchar(32)
DIM @id as int
SET @code = (SELECT inserted.code FROM inserted)
SET @id = (SELECT inserted.code FROM inserted)
-- This is a migrated application; find the appropriate legacy key
IF @code IS NULL AND @id IS NOT NULL
SELECT Code FROM Users WHERE Users.id = @id
-- This is a legacy application; find the appropriate surrogate key
IF @id IS NULL AND @code IS NOT NULL
SELECT Code FROM Users WHERE Users.id = @id
-- Impossible code:
UPDATE inserted SET inserted.code=@code, inserted.id=@id
END
问题
到目前为止,我遇到的两个大问题是:
- 我不能执行“AFTER INSERT”,因为 NULL 约束会使插入失败。
- 我提到的“不可能的代码”是我希望如何干净地代理原始查询;如果原始查询中有 x、y、z 列或只有 x,理想情况下我希望使用相同的触发器来执行这些操作。如果我添加/删除另一列,我希望触发器保持功能。
任何人都有一个可能的代码示例,或者即使只有一个值传递给 SQL,也可以使用另一种解决方案来保持这些列正确填充?