GO
IF OBJECT_ID('Audit_Log', 'U') IS NOT NULL
DROP TABLE Audit_Log;
GO
CREATE TABLE Audit_Log (
audit_id INT IDENTITY(1,1) PRIMARY KEY,
action_date DATETIME DEFAULT GETDATE(), -- Дата и время операции
db_user VARCHAR(100) DEFAULT SYSTEM_USER, -- Пользователь БД
operation VARCHAR(10), -- Тип операции (UPDATE, INSERT, DELETE)
table_name VARCHAR(100), -- Имя таблицы
record_id INT, -- Первичный ключ измененной записи
old_value VARCHAR(MAX), -- Старое значение
new_value VARCHAR(MAX) -- Новое значение
);
GO
GO
IF OBJECT_ID('trg_books_audit', 'TR') IS NOT NULL
DROP TRIGGER trg_books_audit;
GO
CREATE TRIGGER trg_books_audit
ON Books
AFTER UPDATE
AS
BEGIN
SET NOCOUNT ON;
-- Проверяем, изменилось ли поле copies_count
IF UPDATE(copies_count)
BEGIN
INSERT INTO Audit_Log (operation, table_name, record_id, old_value, new_value)
SELECT
'UPDATE',
'Books',
i.book_id,
'Количество: ' + CAST(d.copies_count AS VARCHAR),
'Количество: ' + CAST(i.copies_count AS VARCHAR)
FROM inserted i
JOIN deleted d ON i.book_id = d.book_id
WHERE d.copies_count <> i.copies_count;
END
END;
GO
-- Выдаем книгу (уменьшает copies_count на 1)
EXEC sp_issue_book @book_id = 2, @reader_id = 1;
-- Просматриваем результаты аудита
SELECT * FROM Audit_Log;
GO
-- Создаем защищенное представление с маскированным телефоном
CREATE OR ALTER VIEW v_Readers_Safe AS
SELECT
reader_id,
full_name,
birth_date,
address,
-- Маскируем телефон, оставляя видимыми только последние цифры
STUFF(phone, 4, 8, ' (XXX) XXX-') AS masked_phone
FROM Readers;
GO
-- Выдаем права роли библиотекаря на просмотр представления, а не самой таблицы
GRANT SELECT ON v_Readers_Safe TO lib_librarian;
-- Запрещаем прямой доступ к исходной таблице с полными телефонами
REVOKE SELECT ON Readers FROM lib_librarian;
GO
BACKUP DATABASE LibraryDB
TO DISK = 'C:\Backups\LibraryDB_Full.bak'
WITH FORMAT,
INIT,
NAME = 'LibraryDB-Full Database Backup',
STATS = 10;
GO