Логирование засобами MS SQL PDF Печать E-mail

За матеріалами статті Володимира Сердюка "Реалізація системи логирования для 1С(SQL)"

в даній статті описується варіант мінімальної реалізації, а конкретнее тільки <відловлювання> самого факту зміни реквизитов довідників і шапок документів. Запитаєте навіщо?

Автор: Андрій Вахрин
источник : 1CSQL

А всі дуже просто. Ця стаття може цілком сприйматися як продовження Одержання даних із зовнішньої бази 1С. Т.е. якщо використати механізми описані в згаданій статті не для разового переносу, а для постійного обміну даними між базами, то виникає кілька проблем: Нам постійно необхідно перетягати ВЕСЬ уміст ВСІХ довідників. Якщо документ не входить у зазначений нами діапазон завантаження, але був у цей період змінений. Отут нас і врятує логирование. Ну й, природно, безпосереднє відстеження внесених користувачами змін.

итак, почнемо.

Для початку створимо дві таблиці, які будуть нам необхідні для работи. Одна з них потрібна нам буде тільки для того, щоб <отлавливать> користувача, що вносить зміни.

CREATE Table dbo.CurrentUsers (SPID int NOT NULL CONSTRAINT PK_SPID PRIMARY KEY CLUSTERED, User1S char (20), UserNT char(20), UserSQL char(20), ClientSQL char(20))

вторая буде містити в собі безпосередньо балка змін.

CREATE Table dbo.Журнализменений (Тип Char(1), Час DateTime, Користувач Char(60), ИД Char(9), Таблиця Char(80), Полючи Char(500))

вторим кроком буде запис ідентифікатора процесу, при вході користувача в 1С и видалення цього ідентифікатора при виході.

я роблю це в такий спосіб:

//_____________________________________________________________________________ процедура Приначалеработисистеми() Завантажник = CreateObject("Toy.Loader"); Хендл = Завантажник.LoadLibrary(Каталогиб() + "ExtCompsToysql21.dll"); глтой = Создатьобъект("ToyQuery"); // запис SPID у службову таблицю WshShell = CreateObject("WScript.Shell"); глтой.З'єднатися(0); глтой.Виконати("INSERT INTO dbo.CurrentUsers (SPID, User1S, UserNT, UserSQL, ClientSQL) | VALUES (@@SPID,'"+ Имяпользователя() + "','"+ WshShell.ExpandEnvironmentStrings("%username%") + "',SYSTEM_USER,'"+ WshShell.ExpandEnvironmentStrings("%clientname%") + "')"); конецпроцедури //Приначалеработисистеми //_____________________________________________________________________________ процедура Призавершенииработисистеми() глтой.З'єднатися(0); глтой.Виконати("DELETE FROM dbo.CurrentUsers WHERE SPID = @@SPID"); Завантажник.FreeLibrary(Хендл); конецпроцедури //Призавершенииработисистеми

Ну от начебто б підготовчі роботи й закінчені. Тепер приступимося до основного. Т.е. до створення механізму, що і буде здійснювати запис балки в створену таблицю. Це, звичайно, можна зробити й поправивши всі модулі об'єктів 1С, додавши у процедуру Призаписи() деяка кількість коду. Ах, так! І ще не забути відловити у всіх інших можливих місцях конфігурації й зовнішніх обробок, де можливі зміни об'єктів з наступним записом. Але, як говорив ніколи улюблений всіма детишками ніколи великої країни дідусь Ленін, <ми підемо іншим шляхом>! Ми <намалюємо> тригери на необхідні таблиці.

какие ж таблиці ми виберемо? Ну, мені здається природним, що насамперед це будуть таблиці довідників (SC*)

Для інд = 1 По Метаданние.Довідник() Цикл тспр = Метаданние.Довідник(інд); Спроба СКЛ.Виконати("DROP TRIGGER [TR_D_SC"+ МД.Идобъекта(тспр) + "]"); Виключення Конецпопитки; Спроба СКЛ.Виконати("DROP TRIGGER [TR_I_SC"+ МД.Идобъекта(тспр) + "]"); Виключення Конецпопитки; Спроба СКЛ.Виконати("DROP TRIGGER [TR_U_SC"+ МД.Идобъекта(тспр) + "]"); Виключення Конецпопитки; // видалення стр = "CREATE TRIGGER [TR_D_SC"+ МД.Идобъекта(тспр) + "] ON [dbo].[SC"+ МД.Идобъекта(тспр) + "] | FOR DELETE | AS | SET NOCOUNT ON | DECLARE @CurrentUser char(60) | DECLARE @Поля char(500) | DECLARE @ИД char(29) | | SELECT @CurrentUser = ltrim(rtrim(User1S)) + ';' + ltrim(rtrim(UserNT)) + ';' + ltrim(rtrim(UserSQL)) + ';' | + ltrim(rtrim(ClientSQL)) FROM CurrentUsers WHERE SPID = @@SPID | SET @Поля = '' | SELECT @ИД = ID FROM DELETED | | INSERT INTO Журнализменений(Тип,Час,Користувач,ИД,Таблиця,Полючи) | VALUES('D', GetDate(), @CurrentUser, @ИД, 'Спр"+ тспр.Ідентифікатор + "', @Поля) | | SET NOCOUNT OFF"; Спроба СКЛ.Виконати(стр); Виключення Конецпопитки; // вставка стр = "CREATE TRIGGER [TR_I_SC"+ МД.Идобъекта(тспр) + "] ON [dbo].[SC"+ МД.Идобъекта(тспр) + "] | FOR INSERT | AS | SET NOCOUNT ON | DECLARE @CurrentUser char(60) | DECLARE @Поля char(500) | DECLARE @Ид char(29) | | SELECT @CurrentUser = ltrim(rtrim(User1S)) + ';' + ltrim(rtrim(UserNT)) + ';' + ltrim(rtrim(UserSQL)) + ';' | + ltrim(rtrim(ClientSQL)) FROM CurrentUsers WHERE SPID = @@SPID | SET @Поля = '' | SELECT @ИД = ID FROM INSERTED | | INSERT INTO Журнализменений(Тип,Час,Користувач,ИД,Таблиця,Полючи) | VALUES('I', GetDate(), @CurrentUser, @ИД, 'Спр"+ тспр.Ідентифікатор + "', @Поля) | | SET NOCOUNT OFF"; Спроба СКЛ.Виконати(стр); Виключення Конецпопитки; // зміна стр = "CREATE TRIGGER [TR_U_SC"+ МД.Идобъекта(тспр) + "] ON [dbo].[SC"+ МД.Идобъекта(тспр) + "] | FOR UPDATE | AS | SET NOCOUNT ON | DECLARE @CurrentUser char(60) | DECLARE @Поля char(500) | DECLARE @Ид char(29) | | SELECT @CurrentUser = ltrim(rtrim(User1S)) + ';' + ltrim(rtrim(UserNT)) + ';' + ltrim(rtrim(UserSQL)) + ';' | + ltrim(rtrim(ClientSQL)) FROM CurrentUsers WHERE SPID = @@SPID | SELECT @Поля = '' |"; Якщо тспр.Длинакода <> 0 Тоді стр = стр + " | +CASE | WHEN i.CODE <> d.CODE THEN 'Код,' | ELSE '' | END |"; Конецесли; Якщо тспр.Длинанаименования <> 0 Тоді стр = стр + " | +CASE | WHEN i.DESCR <> d.DESCR THEN 'Найменування,' | ELSE '' | END |"; Конецесли; Якщо Сокрлп(Метаданние.Довідник(інд).Власник) <> "Метаданние"Тоді стр = стр + " | +CASE | WHEN i.PARENTEXT <> d.PARENTEXT THEN 'Власник,' | ELSE '' | END |"; Конецесли; Якщо Метаданние.Довідник(інд).Количествоуровней <> 1 Тоді стр = стр + " | +CASE | WHEN i.PARENTID <> d.PARENTID THEN 'Батько,' | ELSE '' | END |"; Конецесли; стр = стр + " | +CASE | WHEN i.ISMARK <> d.ISMARK THEN 'Пометкаудаления,' | ELSE '' | END |"; Для чполе = 1 По тспр.Реквізит() Цикл тполе = тспр.Реквізит(чполе); Якщо тполе.Періодичний = 1 Тоді Продовжити; Конецесли; стр = стр + " | +CASE | WHEN i.SP" + МД.Идобъекта(тполе) + " <> d.SP"+ МД.Идобъекта(тполе) + " THEN '"+ тполе.Ідентифікатор + ",' | ELSE '' | END |"; Конеццикла; стр = стр + " | FROM INSERTED i, DELETED d | WHERE i.Row_ID = d.Row_ID | | SELECT @ИД = ID from DELETED | | IF @Поля <> '' | BEGIN | INSERT INTO Журнализменений(Тип,Час,Користувач,ИД,Таблиця,Полючи) | VALUES('U', GetDate(), @CurrentUser, @ИД, 'Спр"+ тспр.Ідентифікатор + "', @Поля) | END | | SET NOCOUNT OFF"; Спроба СКЛ.Виконати(стр); Виключення Конецпопитки; конеццикла;

что за таємничі об'єкти СКЛ і МД, я сподіваюся, ви помнете з попередньої статті.

Тепер візьмемося за документи. Було б просто чудово, якби все необхідні нам зміни перебували тільки в Журналі (_1SJOURN) (до речі, ті зміни, які впливають на необхідність вигрузки/завантаження саме там і перебувають, в основному), але прийде ще и підсапувати таблиці шапок документів (DH*)

// журнал документів (створення нового видалення документа) попитка СКЛ.Виконати("DROP TRIGGER [TR_D_JOURN]"); исключение конецпопитки; стр = "CREATE TRIGGER [TR_D_JOURN] ON [dbo].[_1SJOURN] | FOR DELETE | AS | SET NOCOUNT ON | DECLARE @CurrentUser char(60) | DECLARE @Поля char(500) | DECLARE @ИД char(29) | | SELECT @CurrentUser = ltrim(rtrim(User1S)) + ';' + ltrim(rtrim(UserNT)) + ';' + ltrim(rtrim(UserSQL)) + ';' | + ltrim(rtrim(ClientSQL)) FROM CurrentUsers WHERE SPID = @@SPID | SET @Поля = '' | SELECT @ИД = IDDOC FROM DELETED | | INSERT INTO Журнализменений(Тип,Час,Користувач,ИД,Таблиця,Полючи) | VALUES('D', GetDate(), @CurrentUser, @ИД, 'Журнал', @Поля) | | SET NOCOUNT OFF"; попитка СКЛ.Виконати(стр); исключение конецпопитки; // вставка попитка СКЛ.Виконати("DROP TRIGGER [TR_I_JOURN]"); исключение конецпопитки; стр = "CREATE TRIGGER [TR_I_JOURN] ON [dbo].[_1SJOURN] | FOR INSERT | AS | SET NOCOUNT ON | DECLARE @CurrentUser char(60) | DECLARE @Поля char(500) | DECLARE @Ид char(29) | | SELECT @CurrentUser = ltrim(rtrim(User1S)) + ';' + ltrim(rtrim(UserNT)) + ';' + ltrim(rtrim(UserSQL)) + ';' | + ltrim(rtrim(ClientSQL)) FROM CurrentUsers WHERE SPID = @@SPID | SET @Поля = '' | SELECT @ИД = IDDOC FROM INSERTED | | INSERT INTO Журнализменений(Тип,Час,Користувач,ИД,Таблиця,Полючи) | VALUES('I', GetDate(), @CurrentUser, @ИД, 'Журнал', @Поля) | | SET NOCOUNT OFF"; попитка СКЛ.Виконати(стр); исключение конецпопитки; // update загальних реквізитів документів попитка СКЛ.Виконати("DROP TRIGGER [TR_U_JOURN]"); исключение конецпопитки; стр = "CREATE TRIGGER [TR_U_JOURN] ON [dbo].[_1SJOURN] | FOR UPDATE | AS | SET NOCOUNT ON | DECLARE @CurrentUser char(60) | DECLARE @Поля char(500) | DECLARE @Ид char(29) | | SELECT @CurrentUser = ltrim(rtrim(User1S)) + ';' + ltrim(rtrim(UserNT)) + ';' + ltrim(rtrim(UserSQL)) + ';' | + ltrim(rtrim(ClientSQL)) FROM CurrentUsers WHERE SPID = @@SPID | SELECT @Поля = '' | | +CASE | WHEN i.DATE_TIME_IDDOC <> d.DATE_TIME_IDDOC THEN 'Датадок,' | ELSE '' | END | | +CASE | WHEN i.DOCNO <> d.DOCNO THEN 'Номер,' | ELSE '' | END | | +CASE | WHEN i.CLOSED <> d.CLOSED THEN 'Проведений,' | ELSE '' | END | | +CASE | WHEN i.ISMARK <> d.ISMARK THEN 'Пометкаудаления,' | ELSE '' | END |"; для інд = 1 По Метаданние.Общийреквизитдокумента() Цикл тполе = Метаданние.Общийреквизитдокумента(інд); Якщо тполе.Сортування = 0 Тоді Продовжити; Конецесли; стр = стр + " | +CASE | WHEN i.SP" + МД.Идобъекта(тполе) + " <> d.SP"+ МД.Идобъекта(тполе) + " THEN '"+ тполе.Ідентифікатор + ",' | ELSE '' | END |"; конеццикла; стр = стр + " | FROM INSERTED i, DELETED d | WHERE i.Row_ID = d.Row_ID | | SELECT @ИД = IDDOC from DELETED | | IF @Поля <> '' | BEGIN | INSERT INTO Журнализменений(Тип,Час,Користувач,ИД,Таблиця,Полючи) | VALUES('U', GetDate(), @CurrentUser, @ИД, 'Журнал', @Поля) | END | | SET NOCOUNT OFF"; попитка СКЛ.Виконати(стр); исключение конецпопитки; // документи для інд = 1 По Метаданние.Документ() Цикл тдок = Метаданние.Документ(інд); // видалення вставка відслідковуються пожурналу // зміну Спроба СКЛ.Виконати("DROP TRIGGER [TR_U_DH"+ МД.Идобъекта(тдок) + "]"); Виключення Конецпопитки; стр = "CREATE TRIGGER [TR_U_DH"+ МД.Идобъекта(тдок) + "] ON [dbo].[DH"+ МД.Идобъекта(тдок) + "] | FOR UPDATE | AS | SET NOCOUNT ON | DECLARE @CurrentUser char(60) | DECLARE @Поля char(500) | DECLARE @Ид char(29) | | SELECT @CurrentUser = ltrim(rtrim(User1S)) + ';' + ltrim(rtrim(UserNT)) + ';' + ltrim(rtrim(UserSQL)) + ';' | + ltrim(rtrim(ClientSQL)) FROM CurrentUsers WHERE SPID = @@SPID | SELECT @Поля = '' |"; Для чполе = 1 По Метаданние.Общийреквизитдокумента() Цикл тполе = Метаданние.Общийреквизитдокумента(чполе); Якщо тполе.Сортування = 1 Тоді Продовжити; Конецесли; стр = стр + " | +CASE | WHEN i.SP"+ МД.Идобъекта(тполе) + " <> d.SP"+ МД.Идобъекта(тполе) + " THEN '"+ тполе.Ідентифікатор + ",' | ELSE '' | END |"; Конеццикла; Для чполе = 1 По тдок.Реквизитшапки() Цикл тполе = тдок.Реквизитшапки(чполе); стр = стр + " | +CASE | WHEN i.SP"+ МД.Идобъекта(тполе) + " <> d.SP"+ МД.Идобъекта(тполе) + " THEN '"+ тполе.Ідентифікатор + ",' | ELSE '' | END |"; Конеццикла; Для чполе = 1 По тдок.Реквизиттабличнойчасти() Цикл тполе = тдок.Реквизиттабличнойчасти(чполе); Якщо тполе.Итогпоколонке = 1 Тоді стр = стр + " | +CASE | WHEN i.SP"+ МД.Идобъекта(тполе) + " <> d.SP"+ МД.Идобъекта(тполе) + " THEN '"+ тполе.Ідентифікатор + ",' | ELSE '' | END |"; Конецесли; Конеццикла; стр = стр + " | FROM INSERTED i, DELETED d | WHERE i.IDDOC = d.IDDOC | | SELECT @ИД = IDDOC from DELETED | | IF @Поля <> '' | BEGIN | INSERT INTO Журнализменений(Тип,Час,Користувач,ИД,Таблиця,Полючи) | VALUES('U', GetDate(), @CurrentUser, @ИД, 'Дока" + тдок.Ідентифікатор + "', @Поля) | END | | SET NOCOUNT OFF"; Спроба СКЛ.Виконати(стр); Виключення Конецпопитки; конеццикла;

вот і все.

з.и. Деякі таки можуть запитати: і що тепер робити? Як зв'язати це логирование із завантаженням з іншої бази?

1. Виконуємо всі вимоги статті <Одержання даних із зовнішньої бази 1С>. 2. Запускаємо на тій же базі логирование відповідно до установок поточної статті. 3. І спокійно, для кожного об'єкта, що завантажує, додаємо в запити перевірку на його измененность у плині певного періоду. От приклад одержання Коду і Найменування з довідника Фірми, елементи якого були змінені в період з 01.10.2004:

select distinct Спр.Код , Спр.Найменування from Спрфирми Спр , Журнализменений Ж where Ж.Час >= '2004-10-01' and Ж.Таблиця LIKE '%Спрфирми%' and Ж.ИД = Спр.Посилання

 

оригинал статті: http://1csql.ru/materials/articles/develop/018.htm
Опублікована: 9 листопада 2004
 
« Пред.   След. »