Published on

December 4, 2016

Как создать таблицу аудита в SQL Server

Таблицы аудита являются неотъемлемой частью любой базы данных. Они позволяют отслеживать транзакции и изменения, внесенные важными таблицами, предоставляя ценную информацию для целей аудита и соответствия требованиям. В этой статье мы рассмотрим процесс создания таблицы аудита для примера таблицы Inventory в SQL Server.

Шаг 1: Создание базы данных Inventory

Сначала нам нужно создать базу данных, в которой будут храниться наша таблица Inventory, таблица аудита и триггеры аудита. Вот скрипт для создания базы данных:

USE MASTER
GO

IF NOT EXISTS (SELECT [name] FROM sys.databases WHERE [name] = 'InventoryDB')
    CREATE DATABASE InventoryDB
GO

USE InventoryDB
GO

Шаг 2: Создание таблицы Inventory

Затем мы создаем таблицу Inventory, которую хотим аудитировать. Вот скрипт для создания таблицы:

USE InventoryDB
GO

IF EXISTS (SELECT [name] FROM sys.tables WHERE [name] = 'InventoryMasters')
    DROP TABLE InventoryMasters
GO

CREATE TABLE [dbo].[InventoryMasters] (
    [InventoryID] [int] IDENTITY(1,1) NOT NULL,
    [ItemNO] varchar(10),
    [InventoryDate] Datetime null,
    [InventorySeq] int,
    [InventoryType] char(1),
    [Qty] int
)

Шаг 3: Создание таблицы аудита

Теперь нам нужно создать таблицу аудита для хранения информации об аудите. Вот скрипт для создания таблицы аудита:

CREATE TABLE [dbo].[Audit_InventoryMasters] (
    [Audit_InventoryID] [int] IDENTITY(1,1) NOT NULL,
    [InventoryID] [int],
    [ItemNO] varchar(10),
    [RemainingQty] int,
    [InQty] int,
    [OutQty] int,
    [ResultQty] int,
    [AuditDate] Datetime null,
    [AuditbyUser] int,
    [AuditType] char(1),
    CONSTRAINT [PK_Audit_InventoryMasters] PRIMARY KEY CLUSTERED (
        [Audit_InventoryID] ASC
    ) WITH (
        PAD_INDEX = OFF,
        STATISTICS_NORECOMPUTE = OFF,
        IGNORE_DUP_KEY = OFF,
        ALLOW_ROW_LOCKS = ON,
        ALLOW_PAGE_LOCKS = ON
    ) ON [PRIMARY]
) ON [PRIMARY]

Шаг 4: Создание триггеров

Теперь, когда мы создали наши таблицы, мы можем приступить к созданию триггеров для аудита транзакций в нашей таблице Inventory. Мы создадим триггеры для операций Insert, Update и Delete.

Триггер Insert

Триггер Insert будет захватывать входящее/исходящее количество каждой транзакции и вставлять его в таблицу аудита. Вот скрипт для создания триггера Insert:

USE InventoryDB
GO

CREATE TRIGGER trInventoryInsert ON [dbo].[InventoryMasters] FOR INSERT AS
BEGIN
    SET NOCOUNT ON;

    DECLARE @Count int = 0;
    DECLARE @DateCount int = 0;
    DECLARE @InventoryID int = 0;
    DECLARE @InventoryDate datetime;
    DECLARE @InventorySeq int;
    DECLARE @InventoryType char(1);
    DECLARE @ItemNO varchar(10);
    DECLARE @Qty int;
    DECLARE @Result_Qty int = 0;
    DECLARE @FinalInventoryType char(1);
    DECLARE @Unit_Qty int = 0;
    DECLARE @New_QtyCheck int = 0;
    DECLARE @New_OUT_QtyCheck int = 0;

    SELECT @InventoryID = i.InventoryID FROM inserted i;
    SELECT @InventoryDate = i.InventoryDate FROM inserted i;
    SELECT @InventorySeq = i.InventorySeq FROM inserted i;
    SELECT @InventoryType = i.InventoryType FROM inserted i;
    SELECT @ItemNO = i.ItemNO FROM inserted i;
    SELECT @Qty = i.Qty FROM inserted i;

    SELECT @Count = COUNT(*) FROM Audit_InventoryMasters WHERE ItemNO = @ItemNO;

    IF (@Count > 0)
    BEGIN
        SELECT @DateCount = COUNT(*) FROM Audit_InventoryMasters WHERE ItemNO = @ItemNO AND AuditDate = @InventoryDate;

        IF (@DateCount > 0)
        BEGIN
            SELECT TOP 1 @New_QtyCheck = InQty FROM Audit_InventoryMasters WHERE ItemNO = @ItemNO AND AuditDate = @InventoryDate;
            SELECT TOP 1 @New_OUT_QtyCheck = OutQty FROM Audit_InventoryMasters WHERE ItemNO = @ItemNO AND AuditDate = @InventoryDate;

            IF (@InventoryType = 'I')
            BEGIN
                UPDATE Audit_InventoryMasters SET InQty = @Qty + @New_QtyCheck WHERE ItemNO = @ItemNO AND AuditDate = @InventoryDate;
                UPDATE Audit_InventoryMasters SET RemainingQty = RemainingQty + @Qty WHERE ItemNO = @ItemNO AND AuditDate > @InventoryDate;
                UPDATE Audit_InventoryMasters SET ResultQty = RemainingQty + InQty - OutQty WHERE ItemNO = @ItemNO AND AuditDate >= @InventoryDate;
            END
            ELSE
            BEGIN
                UPDATE Audit_InventoryMasters SET OutQty = @Qty + @New_OUT_QtyCheck WHERE ItemNO = @ItemNO AND AuditDate = @InventoryDate;
                UPDATE Audit_InventoryMasters SET RemainingQty = RemainingQty - @Qty WHERE ItemNO = @ItemNO AND AuditDate > @InventoryDate;
                UPDATE Audit_InventoryMasters SET ResultQty = RemainingQty + InQty - OutQty WHERE ItemNO = @ItemNO AND AuditDate >= @InventoryDate;
            END
        END
        ELSE
        BEGIN
            IF NOT EXISTS (SELECT * FROM Audit_InventoryMasters WHERE AuditDate < @InventoryDate)
            BEGIN
                SET @Unit_Qty = 0;
            END
            ELSE
            BEGIN
                SELECT TOP 1 @Unit_Qty = ResultQty FROM Audit_InventoryMasters WHERE ItemNO = @ItemNO AND AuditDate < @InventoryDate;
            END

            IF (@InventoryType = 'I')
            BEGIN
                SET @Result_Qty = @Unit_Qty + @Qty;

                INSERT INTO Audit_InventoryMasters (InventoryID, ItemNO, RemainingQty, InQty, OutQty, ResultQty, AuditDate, AuditbyUser, AuditType)
                VALUES (@InventoryID, @ItemNO, @Unit_Qty, @Qty, 0, @Result_Qty, @InventoryDate, 101, 'I');

                UPDATE Audit_InventoryMasters SET RemainingQty = RemainingQty + @Qty WHERE ItemNO = @ItemNO AND AuditDate > @InventoryDate;
                UPDATE Audit_InventoryMasters SET ResultQty = RemainingQty + InQty - OutQty WHERE ItemNO = @ItemNO AND AuditDate >= @InventoryDate;
            END
            ELSE
            BEGIN
                SET @Result_Qty = @Unit_Qty - @Qty;

                INSERT INTO Audit_InventoryMasters (InventoryID, ItemNO, RemainingQty, InQty, OutQty, ResultQty, AuditDate, AuditbyUser, AuditType)
                VALUES (@InventoryID, @ItemNO, @Unit_Qty, 0, @Qty, @Result_Qty, @InventoryDate, 101, 'I');

                UPDATE Audit_InventoryMasters SET RemainingQty = RemainingQty - @Qty WHERE ItemNO = @ItemNO AND AuditDate > @InventoryDate;
                UPDATE Audit_InventoryMasters SET ResultQty = RemainingQty + InQty - OutQty WHERE ItemNO = @ItemNO AND AuditDate >= @InventoryDate;
            END
        END
    END
    ELSE
    BEGIN
        IF (@InventoryType = 'I')
        BEGIN
            INSERT INTO Audit_InventoryMasters (InventoryID, ItemNO, RemainingQty, InQty, OutQty, ResultQty, AuditDate, AuditbyUser, AuditType)
            VALUES (@InventoryID, @ItemNO, 0, @Qty, 0, @Qty, @InventoryDate, 101, 'I');
        END
        ELSE
        BEGIN
            INSERT INTO Audit_InventoryMasters (InventoryID, ItemNO, RemainingQty, InQty, OutQty, ResultQty, AuditDate, AuditbyUser, AuditType)
            VALUES (@InventoryID, @ItemNO, 0, 0, @Qty, -@Qty, @InventoryDate, 101, 'I');
        END
    END
END

Триггер Update

Триггер Update будет захватывать любые изменения, внесенные в таблицу Inventory, и соответствующим образом обновлять таблицу аудита. Вот скрипт для создания триггера Update:

USE InventoryDB
GO

CREATE TRIGGER trInventoryUpdate ON [dbo].[InventoryMasters] FOR UPDATE AS
BEGIN
    SET NOCOUNT ON;

    DECLARE @Count int = 0;
    DECLARE @DateCount int = 0;
    DECLARE @InventoryID int = 0;
    DECLARE @InventoryDate datetime;
    DECLARE @InventorySeq int;
    DECLARE @InventoryType char(1);
    DECLARE @ItemNO varchar(10);
    DECLARE @Qty int;
    DECLARE @Result_Qty int = 0;
    DECLARE @FinalInventoryType char(1);
    DECLARE @Unit_Qty int = 0;
    DECLARE @New_QtyCheck int = 0;
    DECLARE @New_OUT_QtyCheck int = 0;
    DECLARE @result_IN_Qty int = 0;
    DECLARE @result_OUT_Qty int = 0;
    DECLARE @result_IN_Qty_CHK int = 0;
    DECLARE @result_IN_Qty_CHK_1 int = 0;
    DECLARE @result_OUT_Qty_CHK int = 0;
    DECLARE @result_OUT_Qty_CHK_1 int = 0;

    SELECT @InventoryID = d.InventoryID FROM deleted d;
    SELECT @InventoryDate = d.InventoryDate FROM deleted d;
    SELECT @InventorySeq = d.InventorySeq FROM deleted d;
    SELECT @InventoryType = d.InventoryType FROM deleted d;
    SELECT @ItemNO = d.ItemNO FROM deleted d;
    SELECT @Qty = d.Qty FROM deleted d;

    SELECT @Count = COUNT(*) FROM Audit_InventoryMasters WHERE ItemNO = @ItemNO;

    IF (@Count > 0)
    BEGIN
        SELECT @DateCount = COUNT(*) FROM Audit_InventoryMasters WHERE ItemNO = @ItemNO AND AuditDate = @InventoryDate;

        IF (@DateCount > 0)
        BEGIN
            SELECT TOP 1 @New_QtyCheck = InQty FROM Audit_InventoryMasters WHERE ItemNO = @ItemNO AND AuditDate = @InventoryDate;
            SELECT TOP 1 @New_OUT_QtyCheck = OutQty FROM Audit_InventoryMasters WHERE ItemNO = @ItemNO AND AuditDate = @InventoryDate;

            SELECT @result_IN_Qty = SUM(Qty) FROM InventoryMasters WHERE ItemNO = @ItemNO AND InventoryDate = @InventoryDate AND InventoryType = 'I';
            SELECT @result_OUT_Qty = SUM(Qty) FROM InventoryMasters WHERE ItemNO = @ItemNO AND InventoryDate = @InventoryDate AND InventoryType = 'O';

            IF (@InventoryType = 'I')
            BEGIN
                SELECT @result_IN_Qty_CHK = SUM(InQty) FROM Audit_InventoryMasters WHERE ItemNO = @ItemNO AND AuditDate = @InventoryDate;

                UPDATE Audit_InventoryMasters SET InQty = @result_IN_Qty WHERE ItemNO = @ItemNO AND AuditDate = @InventoryDate;
                UPDATE Audit_InventoryMasters SET RemainingQty = RemainingQty - @Qty WHERE ItemNO = @ItemNO AND AuditDate > @InventoryDate;
                UPDATE Audit_InventoryMasters SET ResultQty = RemainingQty + InQty - OutQty WHERE ItemNO = @ItemNO AND AuditDate >= @InventoryDate;

                SELECT @ROWINCOUNT = COUNT(*) FROM InventoryMasters WHERE ItemNO = @ItemNO AND InventoryDate = @InventoryDate AND InventoryType = 'I';

                IF (@ROWINCOUNT > 1)
                BEGIN
                    IF (@Qty = 0)
                    BEGIN
                        UPDATE Audit_InventoryMasters SET RemainingQty = RemainingQty - (@result_IN_Qty_CHK - @result_IN_Qty) WHERE ItemNO = @ItemNO AND AuditDate > @InventoryDate;
                    END
                    ELSE
                    BEGIN
                        IF (@result_IN_Qty_CHK >= @result_IN_Qty)
                        BEGIN
                            SET @result_IN_Qty_CHK_1 = @result_IN_Qty_CHK - @result_IN_Qty;
                            UPDATE Audit_InventoryMasters SET RemainingQty = RemainingQty - @result_IN_Qty_CHK_1 WHERE ItemNO = @ItemNO AND AuditDate > @InventoryDate;
                        END
                        ELSE
                        BEGIN
                            SET @result_IN_Qty_CHK_1 = @result_IN_Qty - @result_IN_Qty_CHK;
                            UPDATE Audit_InventoryMasters SET RemainingQty = RemainingQty + @result_IN_Qty_CHK_1 WHERE ItemNO = @ItemNO AND AuditDate > @InventoryDate;
                        END
                    END
                END
                ELSE
                BEGIN
                    IF (@Qty >= @New_QtyCheck)
                    BEGIN
                        UPDATE Audit_InventoryMasters SET RemainingQty = RemainingQty + (@Qty - @New_QtyCheck) WHERE ItemNO = @ItemNO AND AuditDate > @InventoryDate;
                    END
                    ELSE
                    BEGIN
                        UPDATE Audit_InventoryMasters SET RemainingQty = RemainingQty - (@New_QtyCheck - @Qty) WHERE ItemNO = @ItemNO AND AuditDate > @InventoryDate;
                    END
                END
            END
            ELSE
            BEGIN
                SELECT @result_OUT_Qty_CHK = SUM(OutQty) FROM Audit_InventoryMasters WHERE ItemNO = @ItemNO AND AuditDate = @InventoryDate;

                UPDATE Audit_InventoryMasters SET OutQty = @result_OUT_Qty WHERE ItemNO = @ItemNO AND AuditDate = @InventoryDate;
                UPDATE Audit_InventoryMasters SET RemainingQty = RemainingQty + @Qty WHERE ItemNO = @ItemNO AND AuditDate > @InventoryDate;
                UPDATE Audit_InventoryMasters SET ResultQty = RemainingQty + InQty - OutQty WHERE ItemNO = @ItemNO AND AuditDate >= @InventoryDate;

                SELECT @ROWINCOUNT = COUNT(*) FROM InventoryMasters WHERE ItemNO = @ItemNO AND InventoryDate = @InventoryDate AND InventoryType = 'O';

                IF (@ROWINCOUNT > 1)
                BEGIN
                    IF (@Qty = 0)
                    BEGIN
                        UPDATE Audit_InventoryMasters SET RemainingQty = RemainingQty + (@result_OUT_Qty_CHK - @result_OUT_Qty) WHERE ItemNO = @ItemNO AND AuditDate > @InventoryDate;
                    END
                    ELSE
                    BEGIN
                        IF (@result_OUT_Qty_CHK >= @result_OUT_Qty)
                        BEGIN
                            SET @result_OUT_Qty_CHK_1 = @result_OUT_Qty_CHK - @result_OUT_Qty;
                            UPDATE Audit_InventoryMasters SET RemainingQty = RemainingQty + @result_OUT_Qty_CHK_1 WHERE ItemNO = @ItemNO AND AuditDate > @InventoryDate;
                        END
                        ELSE
                        BEGIN
                            SET @result_OUT_Qty_CHK_1 = @result_OUT_Qty - @result_OUT_Qty_CHK;
                            UPDATE Audit_InventoryMasters SET RemainingQty = RemainingQty + @result_OUT_Qty_CHK_1 WHERE ItemNO = @ItemNO AND AuditDate > @InventoryDate;
                        END
                    END
                END
                ELSE
                BEGIN
                    IF (@Qty >= @New_OUT_QtyCheck)
                    BEGIN
                        UPDATE Audit_InventoryMasters SET RemainingQty = RemainingQty - (@Qty - @New_OUT_QtyCheck) WHERE ItemNO = @ItemNO AND AuditDate > @InventoryDate;
                    END
                    ELSE
                    BEGIN
                        UPDATE Audit_InventoryMasters SET RemainingQty = RemainingQty + (@New_OUT_QtyCheck - @Qty) WHERE ItemNO = @ItemNO AND AuditDate > @InventoryDate;
                    END
                END
            END
        END
        ELSE
        BEGIN
            IF (@InventoryType = 'I')
            BEGIN
                INSERT INTO Audit_InventoryMasters (InventoryID, ItemNO, RemainingQty, InQty, OutQty, ResultQty, AuditDate, AuditbyUser, AuditType)
                VALUES (@InventoryID, @ItemNO, 0, @Qty, 0, @Qty, @InventoryDate, 101, 'I');
            END
            ELSE
            BEGIN
                INSERT INTO Audit_InventoryMasters (InventoryID, ItemNO, RemainingQty, InQty, OutQty, ResultQty, AuditDate, AuditbyUser, AuditType)
                VALUES (@InventoryID, @ItemNO, 0, 0, @Qty, -@Qty, @InventoryDate, 101, 'I');
            END
        END
    END
END

Триггер Delete

Триггер Delete будет захватывать удаление записей из таблицы Inventory и соответствующим образом обновлять таблицу аудита. Вот скрипт для создания триггера Delete:

USE InventoryDB
GO

CREATE TRIGGER trInventoryDelete ON [dbo].[InventoryMasters] FOR DELETE AS
BEGIN
    SET NOCOUNT ON;

    DECLARE @Count int = 0;
    DECLARE @DateCount int = 0;
    DECLARE @InventoryID int = 0;
    DECLARE @ROWINCOUNT int = 0;
    DECLARE @InventoryDate datetime;
    DECLARE @InventorySeq int;
    DECLARE @InventoryType char(1);
    DECLARE @ItemNO varchar(10);
    DECLARE @Qty int;
    DECLARE @Result_Qty int = 0;
    DECLARE @FinalInventoryType char(1);
    DECLARE @Unit_Qty int = 0;
    DECLARE @New_QtyCheck int = 0;
    DECLARE @New_OUT_QtyCheck int = 0;
    DECLARE @result_IN_Qty int = 0;
    DECLARE @result_OUT_Qty int = 0;
    DECLARE @result_IN_Qty_CHK int = 0;
    DECLARE @result_IN_Qty_CHK_1 int = 0;
    DECLARE @result_OUT_Qty_CHK int = 0;
    DECLARE @result_OUT_Qty_CHK_1 int = 0;

    SELECT @InventoryID = d.InventoryID FROM deleted d;
    SELECT @InventoryDate = d.InventoryDate FROM deleted d;
    SELECT @InventorySeq = d.InventorySeq FROM deleted d;
    SELECT @InventoryType = d.InventoryType FROM deleted d;
    SELECT @ItemNO = d.ItemNO FROM deleted d;
    SELECT @Qty = d.Qty FROM deleted d;

    SELECT @Count = COUNT(*) FROM Audit_InventoryMasters WHERE ItemNO = @ItemNO;

    IF (@Count > 0)
    BEGIN
        SELECT @DateCount = COUNT(*) FROM Audit_InventoryMasters WHERE ItemNO = @ItemNO AND AuditDate = @InventoryDate;

        IF (@DateCount > 0)
        BEGIN
            IF (@InventoryType = 'I')
            BEGIN
                SELECT @ROWINCOUNT = COUNT(*) FROM InventoryMasters WHERE ItemNO = @ItemNO AND InventoryDate = @InventoryDate AND InventoryType = 'I' AND InventorySeq = @InventorySeq;

                IF (@ROWINCOUNT <= 0)
                BEGIN
                    SELECT @Qty = InQty - (SELECT ISNULL(SUM(Qty), 0) FROM InventoryMasters WHERE ItemNO = @ItemNO AND InventoryDate = @InventoryDate AND InventoryType = 'I') FROM Audit_InventoryMasters WHERE ItemNO = @ItemNO AND AuditDate = @InventoryDate;
                END

                UPDATE Audit_InventoryMasters SET InQty = InQty - @Qty WHERE ItemNO = @ItemNO AND AuditDate = @InventoryDate;
                UPDATE Audit_InventoryMasters SET RemainingQty = RemainingQty - @Qty WHERE ItemNO = @ItemNO AND AuditDate > @InventoryDate;
                UPDATE Audit_InventoryMasters SET ResultQty = RemainingQty + InQty - OutQty WHERE ItemNO = @ItemNO AND AuditDate >= @InventoryDate;
            END
            ELSE
            BEGIN
                SELECT @ROWINCOUNT = COUNT(*) FROM InventoryMasters WHERE ItemNO = @ItemNO AND InventoryDate = @InventoryDate AND InventoryType = 'O' AND InventorySeq = @InventorySeq;

                IF (@ROWINCOUNT <= 0)
                BEGIN
                    SELECT @Qty = OutQty - (SELECT ISNULL(SUM(Qty), 0) FROM InventoryMasters WHERE ItemNO = @ItemNO AND InventoryDate = @InventoryDate AND InventoryType = 'O') FROM Audit_InventoryMasters WHERE ItemNO = @ItemNO AND AuditDate = @InventoryDate;
                END

                UPDATE Audit_InventoryMasters SET OutQty = OutQty - @Qty WHERE ItemNO = @ItemNO AND AuditDate = @InventoryDate;
                UPDATE Audit_InventoryMasters SET RemainingQty = RemainingQty + @Qty WHERE ItemNO = @ItemNO AND AuditDate > @InventoryDate;
                UPDATE Audit_InventoryMasters SET ResultQty = RemainingQty + InQty - OutQty WHERE ItemNO = @ItemNO AND AuditDate >= @InventoryDate;
            END
        END
    END
END

Заключение

В этой статье мы узнали, как создать таблицу аудита в SQL Server для отслеживания транзакций и изменений, внесенных в таблицу Inventory. Реализуя триггеры для операций Insert, Update и Delete, мы можем захватывать и сохранять необходимую информацию об аудите в таблице аудита. Эти данные аудита могут использоваться для целей аудита, соответствия требованиям и исторического анализа.

Не забудьте адаптировать предоставленные скрипты под свою конкретную структуру таблицы и требования. С полученными знаниями из этой статьи вы теперь можете реализовать таблицы аудита в своих собственных базах данных SQL Server.

Click to rate this post!
[Total: 0 Average: 0]

Let's work together

Send us a message or book free introductory meeting with us using button below.