我想知道哪些列真正发生了变化

发布于 2024-09-09 02:57:19 字数 624 浏览 2 评论 0原文

我有一个在 SQLCLR 程序集中实现的后触发器。在其中我想知道哪些列已真正更新(并且它们的值已更改)。

不幸的是,SqlContext.TriggerContext.IsUpdatedColumn 返回 true,即使列值仍然相同。我猜想,这只是因为由不太智能的服务器应用程序准备的 SQL 查询会重写所有列,即使其中一些列尚未被用户更改。

第二个问题是某些列具有 ntext 类型,因此我什至无法从 INSERTED 伪表中选择它们(MS SQL Server 不允许从 INSERTED 中选择具有 ntext 类型的字段)。这就是为什么现在我使用以下查询 SELECT 更改的行:

SELECT * FROM [dbo].[MyTable] WHERE [id] IN (SELECT [id] FROM INSERTED)

我应该做什么来了解哪些列不仅被更新,而且被更改?

现在我有一个简单的想法:创建另一个触发器,BEFORE,并从内部保存更新的行。然后,当执行 AFTER 触发器时,比较列值。这个想法是我能做的最好的事情吗?如果是这样,在 BEFORE 和 AFTER 触发器之间保留更改的行的最佳位置是什么?由于我关闭了上下文连接(也许只是不关闭?),因此在执行 AFTER 触发器之前将删除临时表。

I have an after trigger implemented in SQLCLR assembly. Within it I'd like to know, what columns have been really updated (and their values have been changed).

Unfortunately, SqlContext.TriggerContext.IsUpdatedColumn returns true, even when a column value is still the same. I guess, it's just because an SQL query, prepared by a not-very-smart server application, rewrites all columns, even if some of them have not been changed by user.

The second problem is some of the columns have ntext type, so I cannot even SELECT them from INSERTED pseudo table (MS SQL Server doesn't allow SELECT fields which have ntext type from INSERTED). That's why now I SELECT changed rows with the following query:

SELECT * FROM [dbo].[MyTable] WHERE [id] IN (SELECT [id] FROM INSERTED)

What should I do to get to know, what columns are not just updated, but changed?

Now I have a simple idea: create another trigger, BEFORE, and save updated rows from within. Then, when AFTER trigger is being executed, compare column values. Is this idea the best thing I can do? If so, what is the best place to keep the changed rows between BEFORE and AFTER triggers? A temporary table will be dropped before the AFTER trigger is executed, since I close context connection (maybe, just don't close?).

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

我家小可爱 2024-09-16 02:57:19

好的,现在我已经解决了这个问题。

首先,我创建了源表的完整副本(数据 + 结构):

IF NOT EXISTS(SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 'copyTable')
SELECT * INTO copyTable FROM MyTable

然后,我将源表与其触发器开头的副本进行比较:

SELECT A.* FROM MyTable A, copyTable B WHERE
    A.id IN (SELECT [id] FROM INSERTED) AND
    A.id = B.id AND
    A.{0} <> B.{0}

将 {0} 替换为您需要的列。此栏正是您必须了解的栏目,是否更新。就我而言,它是动态定义的,但您可以静态计算所需的所有列。

Et voila - 您只选择了真正更改的行。

最后,在触发器结束时,不要忘记使用新值更新 copyTable:

UPDATE copyTable SET
    id = s.id,
    col1 = s.col1,
    ... all columns you'd like to control ...
FROM MyTable s WHERE
    s.id IN (SELECT [id] FROM INSERTED) AND
    copyTable.id = s.id

也许有更好的解决方案,但这也有效。

问候,

OK, now I've solved the problem.

First of all, I've created a full copy of source table (data + structure):

IF NOT EXISTS(SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 'copyTable')
SELECT * INTO copyTable FROM MyTable

Then, I'm comparing the source table with its copy at the beginning of my trigger:

SELECT A.* FROM MyTable A, copyTable B WHERE
    A.id IN (SELECT [id] FROM INSERTED) AND
    A.id = B.id AND
    A.{0} <> B.{0}

Replace {0} with a column you require. This column is exactly the column you have to know, is it updated or not. In my case, it is being defined dynamically, but you can count statically all columns you need.

Et voila - you've selected just the rows that are really changed.

Finally, at the end of the trigger, don't forget to update copyTable with the new values:

UPDATE copyTable SET
    id = s.id,
    col1 = s.col1,
    ... all columns you'd like to control ...
FROM MyTable s WHERE
    s.id IN (SELECT [id] FROM INSERTED) AND
    copyTable.id = s.id

Maybe, there is a better solution, but this works too as well.

Regards,

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文