半计算列只能在插入触发器后使用?

Posted

技术标签:

【中文标题】半计算列只能在插入触发器后使用?【英文标题】:Semi computed column only possible with after insert trigger? 【发布时间】:2012-10-10 22:47:59 【问题描述】:

我的数据库中的每个表都有一个列,需要为新行计算,但有需要保留的旧值。我有一个使用更新后触发器的工作解决方案,但它的某些内容并不适合我。尤其是对每个表都有这样的触发器的想法。我希望还有其他我忽略的想法。

如果有一种方法可以使用 DEFAULT 列值,我会非常高兴,但这似乎是不可能的。据我所知,DEFAULT 标量函数无法查看插入行中的其他值。

这是一个示例数据库,用于演示我当前的解决方案。为了方便,我把它放在 SQL Fiddle 上:

http://sqlfiddle.com/#!3/65f88/1

但这里是重新创建它的代码(以防将来由于任何原因无法访问 SQL Fiddle):

CREATE TABLE tmpTest (
    id INT IDENTITY PRIMARY KEY,
    origin INT DEFAULT 15,
    code VARCHAR(9),
    name VARCHAR(100),
    UNIQUE (code)
)

GO

CREATE TRIGGER tmpTest_code ON tmpTest
AFTER INSERT AS
    UPDATE t SET
      t.code = RIGHT(UPPER(master.dbo.fn_varbintohexstr(t.origin)), 2)
             + RIGHT(UPPER(master.dbo.fn_varbintohexstr(t.id)), 7)
    FROM tmpTest t 
    INNER JOIN inserted i ON i.id = t.id
    WHERE t.code IS NULL

GO

INSERT INTO tmpTest (name) VALUES ('one')
INSERT INTO tmpTest (name) VALUES ('two')
INSERT INTO tmpTest (name) VALUES ('three')
INSERT INTO tmpTest (name) VALUES ('four')
INSERT INTO tmpTest (name) VALUES ('five')
INSERT INTO tmpTest (name) VALUES ('six')
INSERT INTO tmpTest (name) VALUES ('seven')
INSERT INTO tmpTest (name) VALUES ('eight')
INSERT INTO tmpTest (name) VALUES ('nine')
INSERT INTO tmpTest (name) VALUES ('ten')

INSERT INTO tmpTest (origin, code, name) VALUES (3, '030000001', 'legacy one')
INSERT INTO tmpTest (origin, code, name) VALUES (3, '030000002', 'legacy two')
INSERT INTO tmpTest (origin, code, name) VALUES (3, '030000003', 'legacy three')
INSERT INTO tmpTest (origin, code, name) VALUES (3, '030000004', 'legacy four')
INSERT INTO tmpTest (origin, code, name) VALUES (3, '030000005', 'legacy five')
INSERT INTO tmpTest (origin, code, name) VALUES (3, '030000006', 'legacy six')
INSERT INTO tmpTest (origin, code, name) VALUES (3, '030000007', 'legacy seven')
INSERT INTO tmpTest (origin, code, name) VALUES (3, '030000008', 'legacy eight')
INSERT INTO tmpTest (origin, code, name) VALUES (3, '030000009', 'legacy nine')
INSERT INTO tmpTest (origin, code, name) VALUES (3, '03000000A', 'legacy ten')

【问题讨论】:

记住 master.dbo.fn_varbintohexstr 是一个 udocumented 函数... 请看这个答案,它可以让你使用一个简单的计算列:***.com/questions/6637096/… 哦,谢谢。我以后会担心这个,但现在我不必担心了。哇哦。 我没有看到绕过触发器的方法,但如果触发器代码足够通用,您可以使用 DDL 触发器为新表自动创建它。基本上,您定义了一个在创建表时触发的触发器,然后创建后插入触发器。 感谢@TToni 的建议。这至少应该可以缓解我的主要维护问题之一。 【参考方案1】:

如果代码列的要求是UNIQUE,为什么不将其更改为默认值,例如NEWID(),同时保留所有当前值?

另一种方法是创建另一个列,其值为

ISNULL(code, <formula based on id and origin)

这样,对于现有记录,其值将与代码匹配,而对于代码可能为空的新值,它将与您的新公式匹配。

无论哪种方式,它都应该避免令人不快的触发解决方案,我同意。

最后但同样重要的是,我会使用HASHBYTES 而不是fn_varbintohexstr

【讨论】:

以上是关于半计算列只能在插入触发器后使用?的主要内容,如果未能解决你的问题,请参考以下文章

.Net SqlDataAdapter 在使用列上的默认值插入后检索身份

如何在 phpmyadmin 中创建触发器,插入后将更新花药表中的字段?

插入后触发多次插入后无法正常工作

SQL AFTER 插入更新触发器

完成表中的数据插入后如何触发触发器

基于变化表中的值在插入之前触发 PL/SQL 触发器