【发布时间】:2011-04-25 16:41:12
【问题描述】:
背景故事
在我们计划在我们的一个主表中弃用自然键列的工作中。该项目包含 100 多个链接到此表/列的应用程序; 400 多个直接引用此列的存储过程;以及这些应用程序之间的大量公用表也引用了此列。
Big Bang 和 Start from Scratch 方法已经不存在了。我们将一次弃用本专栏的一个应用程序,验证更改,然后继续下一个……我们制定了一个长期目标,以使这项工作切实可行。
我遇到的问题是很多这些应用程序都有共享存储过程和表。如果我完全转换应用程序 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 时也能保持这些列正确填充的替代解决方案?
【问题讨论】:
-
此外,如果您要添加 ID 列,请不要将它们命名为 ID,这是一种不好的做法,可能会导致错误(您可能会在复杂查询中意外加入错误的列)和报告困难。使用 tablenameID。
标签: sql-server database tsql triggers refactoring-databases