Pau*_*ith 6 sql sql-server legacy triggers default-value
我们正在执行到SQL Server的数据库迁移,并且为了支持遗留应用程序,我们在SQL Server表上定义了视图,这些视图以遗留应用程序所期望的方式呈现数据.
但是,当字段可能具有默认值时,我们现在遇到在这些视图上定义的INSTEAD OF INSERT触发器的问题.
我试着举个例子.
数据库中的表有3个字段,a,b和c.c是全新的,遗留应用程序不知道它,所以我们也有一个视图有2个字段,a和b.
当遗留应用程序尝试在其视图中插入值时,我们使用INSTEAD OF INSERT触发器来查找应该在字段c中的值,如下所示:
INSERT INTO realTable(a, b, c) SELECT Inserted.a, Inserted.b, Calculated.C FROM...
Run Code Online (Sandbox Code Playgroud)
(查找的详细信息无关紧要.)
除非字段b具有默认值,否则此触发器效果很好.这是因为如果查询
INSERT INTO legacyView(a) VALUES (123)
Run Code Online (Sandbox Code Playgroud)
执行,然后在触发器中,Inserted.b为NULL,而不是b的默认值.现在我有一个问题,因为我无法区分上面的查询,它将默认值放入b,并且:
INSERT INTO legacyView(a,b) VALUES (123, NULL)
Run Code Online (Sandbox Code Playgroud)
即使b是非NULLABLE,我也不知道如何在触发器中编写INSERT查询,这样如果为b提供了值,则在触发器中使用它,但如果不是,则使用默认值.
编辑:补充说,我宁愿不复制触发器中的默认值.默认值已经在数据库模式中,我希望我可以直接使用它们.
小智 1
Paul:我已经解决了这个问题;最终。这是一个有点肮脏的解决方案,可能不适合每个人的口味,但我对 SQL Server 等还很陌生:
在 Replace_of_INSERT 触发器中:
将 Inserted 虚拟表的数据结构复制到临时表:
SELECT * INTO aTempInserted FROM Inserted WHERE 1=2
Run Code Online (Sandbox Code Playgroud)创建一个视图以确定视图基础表(来自系统表)的默认约束,并使用它们构建将复制临时表中的约束的语句:
SELECT 'ALTER TABLE dbo.aTempInserted
ADD CONSTRAINT ' + dc.name + 'Temp' +
' DEFAULT(' + dc.definition + ')
FOR ' + c.name AS Cmd, OBJECT_NAME(c.object_id) AS Name
FROM sys.default_constraints AS dc
INNER JOIN sys.columns AS c
ON dc.parent_object_id = c.object_id
AND dc.parent_column_id = c.column_id
Run Code Online (Sandbox Code Playgroud)使用游标迭代检索到的集合并执行每个语句。这将为您留下一个与要插入的表具有相同默认值的临时表。
将默认记录插入临时表(从 Inserted 虚拟表创建时,所有字段均可为空):
INSERT INTO aTempInserted DEFAULT VALUES
Run Code Online (Sandbox Code Playgroud)将记录从 Inserted 虚拟表复制到视图的基础表中(如果触发器没有阻止的话,它们最初将被插入到该表中),连接临时表以提供默认值。这需要使用 COALESCE 函数,以便仅默认未提供的值:
INSERT INTO realTable([a], [b],
SELECT COALESCE(I.[a], T.[a]),
COALESCE(I.[a], T.[b])
FROM Inserted AS I,
aTempInserted AS T
Run Code Online (Sandbox Code Playgroud)删除临时表