【问题标题】:Best way to use SQL trigger with conditional count to audit database reports?使用带有条件计数的 SQL 触发器来审计数据库报告的最佳方法是什么?
【发布时间】:2020-09-21 11:20:57
【问题描述】:

我希望在我的 SQL 服务器中实现一个触发器,以便在进行报告编辑时保存它们。

服务器运行报告/听写软件包。基本上,“report_text”草稿由 user1 创建,然后由 user2 编辑,然后由 user2 完成。用户 1 的草稿被保存到一个表中,并在数据库中的每次保存时覆盖,一旦用户 1 完成并且用户 2 进行编辑,数据将被进一步覆盖。因此,一旦 user2 保存编辑,user1 的最终草稿就会丢失。

一旦 user1 完成,我正在尝试将“report_text”保存到新表中。

一个单独的表保存一个带有report_id、access_time 和访问报告的用户的审计日志。每次访问都会将新行插入到审计表中,直到最终确定,因此审计表中的每个 report_id 可以有 2 到 4 行(取决于在最终确定之前访问过该文件的用户数)。当每个 report_id 的审计表中每个 report_id 的行数从 2 变为 3 时,触发器应捕获“report_text”。

USE SERVER
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO

ALTER trigger [dbo].[prelim_text_trigger]
on [dbo].[report_to_user]
AFTER INSERT
AS
BEGIN

SET NOCOUNT ON;

INSERT INTO
dbo.report_compare (report_id)

SELECT report_id
FROM inserted
WHERE (SELECT COUNT(report_id) 
FROM report_to_user 
GROUP BY report_id 
HAVING count(report_id) > 2);

END

我尝试了以下代码但没有成功。 dbo.report_compare 中没有插入任何内容,并且在触发器运行时审计表 dbo.report_to_user 存在问题。我认为触发器失败,事务正在回滚。

我做错了什么?我是否应该做出条件声明,以便在不满足条件的情况下进行交易?这是否准确计算了整个表中存在的实例 report_id 的数量,还是仅从临时表 from inserted 中计算?

接下来,如果触发器失败,我希望交易继续进行。如果我在触发器的开头添加XACT_ABORT OFFCOMMIT TRANS 会起作用吗?

另外,是否应该将FOR EACH ROW 添加到此触发器中,以防数据库同时保存多个报告?

更新

我已经修改了代码,如下:

ALTER trigger [dbo].[report_compare_trigger]
on [dbo].[report_test_to_user]
after insert

as
set xact_abort off
begin

set nocount on;

merge report_compare as target 
    using (select report_id from inserted) as source (report_id) 
    on (target.report_id = source.report_id)
    when not matched then insert (report_id) values (report_id);

if (select accession_id from report_compare where report_compare.report_id = (select report_id from inserted)) is null
    begin
        update report_compare
        set accession_id = id from accession_test
        where report_compare.report_id = (select report_id from inserted) and accession_test.report_id = (select report_id from inserted);
    end

update report_compare
    set report_compare.id_count = id_count + 1 
    where report_compare.report_id = (select report_id from inserted);

if (select date_opened from report_compare where report_compare.report_id = (select report_id from inserted)) is null
    begin
        update report_compare
        set date_opened = cre_time from report_test_section
        where report_compare.report_id = (select report_id from inserted) and report_test_section.report_id = (select report_id from inserted);
    end

if (select user_id from inserted) <> 'EmergencyDept'
    begin
        if (select users from report_compare where report_compare.report_id = (select report_id from inserted)) is null
            begin
                update report_compare
                set users = isnull(users, '') + user_id from inserted where report_compare.report_id = (select report_id from inserted)
            end
        else
            begin
update report_compare
        set users = isnull(users, '') + ', ' + user_id from inserted where report_compare.report_id = (select report_id from inserted)
            end
    end

end;

【问题讨论】:

    标签: sql sql-server count triggers


    【解决方案1】:

    可能有点离题,但听起来您可能会受益于temporal tables - 可从 SQL Server 2016 获得。SQL Server 还具有审计功能,因此您不必完全重新发明轮子。

    我尝试了以下代码但没有成功。没有插入任何东西 dbo.report_compare 并且审计表存在问题 触发器运行时的 dbo.report_to_user。

    什么样的问题?

    该语句是否真的返回一行?

    SELECT report_id
    FROM inserted
    WHERE (SELECT COUNT(report_id) 
    FROM report_to_user 
    GROUP BY report_id 
    HAVING count(report_id) > 2);
    

    【讨论】:

    • 我会研究审计功能,我不知道这些,但我们使用的是 SQL 2008,所以我认为临时表可能已经过时了。就问题类型而言,信息没有正确写入设置触发器的表中。最终结果是最终用户系统中没有签署报告。一旦我删除了触发器,一切都会再次变得愉快,如果最终用户退出了报告,那么这些报告就会得到修复。所以触发器阻止了任何向前的进展。
    • 我刚刚尝试用from report_to_user(它将来自的表)替换from inserted的代码作为测试查询,我得到了错误Msg 4145, Level 15, State 1, Line 6 An expression of non-boolean type specified in a context where a condition is expected, near ';'.所以我的东西本质上是错误的写在那里
    • 如果我将 from inserted 替换为特定的报告 ID select report_id, count(report_id) from report_to_user group by report_id having count(report_id) &gt; 2 and report_id = 'xxxxx',这样的事情似乎有效,但现在我正在阅读,如果您在之后读取或写入表格,则会出现突变错误插入触发器......所以也许这应该是插入之前
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-03-25
    • 1970-01-01
    • 2010-10-16
    • 2012-07-14
    • 2011-04-28
    • 1970-01-01
    相关资源
    最近更新 更多