Суббота, 18.05.2024
Мой сайт
Меню сайта
Статистика

Онлайн всего: 1
Гостей: 1
Пользователей: 0
Главная » 2017 » Июль » 4 » Несколько конфигураций 1С (SQL сервер, триггеры)
21:24
Несколько конфигураций 1С (SQL сервер, триггеры)

Несколько конфигураций 1С (SQL сервер, триггеры)

Довольно часто используется не одна программа (конфигурация) а сразу несколько. Причин много. У каждого свой участок работы и человеку вовсе не надо любоваться на что-то чужое. Чужое можно отключать настройками просмотра но и с точки зрения элементарной сохранности информации лучше не хранить сразу всё в огромном общем файле.  Если уж что-то сломается (из-за разрушения жесткого диска например) пусть оно сломается под одной чьей-то базой а не под большой общей базой.
Пример ниже надуманный но зато простой. Пусть есть бухгалтерия которая знать ничего не хочет кроме сумм отгрузки и оплаты и сбыт, который занимается заказами и отгрузками и который, в свою очередь знать не знает и не хочет про оплаты. Довольно часто в такую самостоятельную программу может быть вынесен например сложный расчёт зарплаты, от которого бухгалтерам попадают только суммы по фамилиям.
Есть две конфигурации 1C_zakaz (сбыт, заказы) и 1С_buh (бухгалтерия). Обе конфигурации есть на сервере 1С и на SQL сервере. Структура конфигураций:
 

1C_zakaz

1C_buh

Справочники

Документы


Оба отдела (сбыт и бухгалтерия) имеют дело с одними и теми же покупателями. Значит и тем и другим нужен справочник покупателей. Он называется «Покупатели». Только у сбыта в нем есть контактный телефон, а у бухгалтерии есть номер счета.
В конфигурации сбыта есть документ «Заказы» со списком заказов. В этом документе может быть зафиксирована длительная переписка с заказчиком и обсуждение деталей. Но бухгалтерии всё это становится интересно только когда доходит до стадии перемещения материальных ценностей, т.е отгрузки. Потому документ «Отгрузка» тоже есть и в той и в другой конфигурации. Но бухгалтерию интересует только сумма потому в бухгалтерской конфигурации нет даже списка отгруженных товаров.
Теоретически все удобно. Каждый работает со свой информацией. Но над этой компанией может быть ещё и директор которого может интересовать информация и из той и из другой базы. Кроме того если появляется новый покупатель его надо вводить сразу в два справочника в двух конфигурациях. Если меняется информации о нём то менять её тоже надо сразу в двух базах. Это просто только теоретически. Практически таких по сути общих справочников обычно много и поддержание правильности (согласованности) информации обычно висит на ком-то довольно неприятной (т.к требующей достаточной аккуратности и дисциплинированности) работой. Это проблема и действительно неприятная.
Но начну с начала, т.е с механизма объединения информации. Я не буду описывать инструменты 1С потому… что они позволяют решить проблему единственный доступным 1С способом.   Но 1С, ограничив себя одной базой, сузил возможности и себе и пользователям. Хотя свои возможности там, конечно, есть.
На SQL сервере создались две базы для двух конфигураций:
 

1С_zakaz

1C_buh

Просто по тому, что насоздавалось легко «угадать» что справочники он пишет в таблицы, названия которых начинают с “_Reference”, а документы в таблицы с “_Document”. Табличные части документов это таблицы в «окончанием» “_VT”.
Перед именами всех таблиц тут написано «dbo.». Это имя пользователя, который создал базу данных, означающее «собственник базы данных» (database owner). Оно обычно именно такое, а полный путь к таблице (чтобы взять из неё информацию) даже длиннее. Он включает и имя базы данных, в которой хранится информации. Вот так обычно выглядит строка для выборки информации из таблицы:

Но SQL серверу вовсе не обязательно брать информацию только из одной подключенной к нему базы. Это – ограничение исключительно 1С. SQL сервер же и придуман чтобы брать информацию буквально откуда угодно, как-то её объединять (если сказано) и отправлять тому, кто всё это запросил. Он без всяких проблем может подключиться к серверу в другом городе, что-то там взять, соединить с тем, что храниться на нем и вернуть. Это всё будет делать сервер. Программисту же достаточно правильно написать что и откуда он хочет получить.
Это самое простое из того, что вообще может быть:
SELECT zakaz_pok._Description AS zakza_p,
    buh_pok._Description AS buh_p,
            zakaz_pok._Fld11 AS tel, buh_pok._Fld9 AS chet
  FROM [1C_zakaz].[dbo].[_Reference7] AS zakaz_pok
    INNER JOIN [1C_buh].[dbo]._Reference8 buh_pok
    ON zakaz_pok._Code = buh_pok._Code

Строка объединяет два справочника покупателей из двух конфигураций по коду и вытаскивает из базы сбыта (1C_zakaz) контактный телефон а из бухгалтерской базы (1C_buh) – номер счета.
В обычных (не 1С-овских) базах из-за простоты обращения к другой базе довольно часто общие справочники вообще выносятся в отдельную базу (к которой обращаются все приложения) или хранятся в одном каком-то месте к которому все обращаются.
Примерно также выбирая информацию сразу из всех баз (конфигураций) можно получить любую информацию в любом виде (ничего не перегоняя и не объединяя средствами 1С). Дальше это всё хоть начальству на компьютер хоть для интересующихся в Интернете.
Есть ещё довольно частая проблема которую относительно легко решить силами 1С. Иногда бывает полезно хранить информацию обо всех изменениях в базе данных. Но это скорее административно – системная информация, не нужная пользователю. Пользователю она потребуется тот единственный раз в жизни когда он случайно удалит очень нужный ему документ. Информацию полезно хранить но очень не хочется захламлять этой довольно объемной информаций основную базу данных. Потому можно воспользоваться другим инструментом 1С сервера. Это триггеры, т.е программы которые отрабатывают при каких-то изменениях в базе данных.
Пусть я хочу чтобы в отдельной базе 1С_edit сохранялась информация обо всех изменениях в справочнике товаров.
Создаю базу и таблицу в ней:

Надо описать кто тут кто.
ID – идентификатор строки. Как бы неправильно когда строка не имеет идентификатора (в данном случае набор случайных символов) по которому её нельзя найти. Потому обычно все строки таблиц содержат такой идентификатор.
dt_sys – дата и время изменений
edit_type – тип изменения. Их всего три – добавление, удаление и корректировка. При корректировке одно удаляется а другое добавляется.
User_ - пользователь, который откорректировал информацию
TovarID – идентификатор строки справочника товара которую корректировали.
Tovar_Code – код товара
Tovar_name – наименование товара
Завела я три триггера для таблицы, в которой содержится справочник товаров:

Триггер, который отрабатывает при корректировке получает две таблицы. «deleted» - старые значения, «inserted» - новые:

Вот он и сохраняет в отдельных строках вначале то, что было («Ud») а потом то, что стало («Ui»). Берёт он информацию из созданных 1С-ом полей с цифрами и сохраняет в поля с более-менее понятными названиями.
Тексты всех триггеров:
ALTER TRIGGER [dbo].[Tovar_INSERT] ON 1C_zakaz].[dbo].[_Reference8]
FOR INSERT

AS
  INSERT INTO [1C_edit].[dbo].Tovar (dt_sys,edit_type,TovarID,
                        Tovar_Code,Tovar_name,User_)
  SELECT GetDate(), 'I',[_IDRRef]
      ,[_Code]
      ,[_Description]
      ,[_Fld13]
   FROM inserted
 

ALTER TRIGGER [dbo].[Tovar_UPDATE] ON [1C_zakaz].[dbo].[_Reference8]
FOR update

AS
  INSERT INTO [1C_edit].[dbo].Tovar (dt_sys,edit_type,TovarID,
                        Tovar_Code,Tovar_name,User_)
  SELECT GetDate(), 'Ud',[_IDRRef]
      ,[_Code]
      ,[_Description]
      ,[_Fld13]
   FROM deleted
   INSERT INTO [1C_edit].[dbo].Tovar (dt_sys,edit_type,TovarID,
                        Tovar_Code,Tovar_name,User_)
  SELECT GetDate(), 'Ui',[_IDRRef]
      ,[_Code]
      ,[_Description]
      ,[_Fld13]
   FROM inserted
ALTER TRIGGER [dbo].[Tovar_DELETE] ON [1C_zakaz].[dbo].[_Reference8]
FOR DELETE

AS
  INSERT INTO [1C_edit].[dbo].Tovar (dt_sys,edit_type,TovarID,
                        Tovar_Code,Tovar_name,User_)
  SELECT GetDate(), 'D',[_IDRRef]
      ,[_Code]
      ,[_Description]
      ,[_Fld13]
   FROM deleted
1C про то, что к его базе что-то добавили ничего не знает. Но добавленное ему и не мешает. Он продолжает отрабатывать свои действия а SQL сервер делает то, что просит сервер 1С и то, что должно выполняться само при любых изменениях данных (и описано в триггерах).
Я вначале добавила строку «Товар1». Потом ввела строку с ошибкой, потом исправила ошибку потом удалила эту строку. Информация обо всех этих действиях сохранилась:

Использовать это можно разными способами. Можно переносить в отдельную локальную сеть и обновлять эту совершенно отдельною базу внося в ней те же изменения. Можно оптимизировать нагрузку на сеть например видя что кто-то работает утром а если он начнёт на 15 минут позже то не будет это делать в момент когда кто-то запускает особо тяжёлые запросы информации (быстрее всё будет работать).
К сожаление есть проблема. Обычно люди месяцами работают в базе и ничего с ней не случается. Заливка резервной копии через DT файл – аварийное действие при аварийной ситуации. Но если это сделано то могут измениться названия таблиц, в которые 1С пишет информацию (не говоря уж о том, что из новой создаваемой базы исчезнут все триггеры). Это всё надо будет перенастроить, но это ни в какое сравнение не идёт с другими  вариантами по трудоёмкости и трудозатратам.
Триггеры позволяют решить и проблему мгновенного добавления информации в соседнюю (по SQL серверу) базу  раз уж 1С не может обращаться к чужим данным.
Достаточно  написать триггеры которые синхронно обновляют справочники в другой базе.
Пусть я хочу чтобы автоматически менялась информация в справочнике покупателей. Я знаю, в каких таблицах хранится информация и знаю и в каких полях что хранится.
Вставка (INSERT):

ALTER TRIGGER [dbo].[Pokup_INSERT] ON [1C_zakaz].[dbo].[_Reference7]
FOR INSERT
AS
  Declare @mark binary(1)
  Declare @Met binary(1)
  SELECT @mark = MIN(_Marked) FROM [1C_buh].dbo._Reference8
  SELECT @Met = MIN(_IsMetadata) FROM [1C_buh].dbo._Reference8
  INSERT INTO [1C_buh].[dbo]._Reference8(
      [_IDRRef]
      ,[_Marked]
      ,[_IsMetadata]
      ,[_Code]
      ,[_Fld18]
      ,[_Description])
  SELECT convert(binary(16),newid())
      ,@mark
      ,@Met
      ,[_Code]
      ,[_Fld12]
      ,[_Description]
   FROM inserted
В справочниках есть два непонятных поля (_Marked и _IsMetadata). Туда записывается одно и то же. На всякий случай значения этих полей берутся из той таблицы Reference8 базы 1C_buh в которую осуществляется запись. Идентификатор строки _IDRRef в 1С почему-то хранится в бинарном виде. Потому стандартный идентификатор для создаваемый строк (newid())) преобразуется к этому виду командой convert().
Я могла бы переписать в бухгалтерскую базу контактный телефон, но в этой базе нет для него поля. А вот поле для пользователя в ней есть. В базе сбыта эта информации записана в поле _Fld12 а в бухгалтерской базе в поле _Fld18. Вот я и перегоняю это информацию вслед за кодом (Code).
Корректировка (UPDATE):

ALTER TRIGGER [dbo].[Pokup_UPDATE] ON [1C_zakaz].[dbo].[_Reference7]
FOR UPDATE
AS
  Declare @IDRRef binary(16)
  Declare @Code nvarchar(9)
  Declare @Desc nvarchar(50)
  Declare @User_ nvarchar(20)
  SELECT @Code = [_Code] FROM inserted
  SELECT @IDRRef = [_IDRRef] FROM [1C_buh].dbo._Reference8
            WHERE [_Code] = @Code
  SELECT @Desc = [_Description] FROM inserted
  SELECT @User_ = [_Fld12] FROM inserted
 
            UPDATE [1C_buh].[dbo]._Reference8
        SET [_Description] = @Desc,
                                    _Fld18 = @User_
                                   WHERE [_IDRRef] = @IDRRef
Что там было раньше, т.е строки таблицы deleted меня не интересует. Я хочу чтобы в бухгалтерской базе все поменялось на содержание inserted. Но вначале надо найти ту строку, которую надо будет поменять. Я её и нахожу с помощью поиска по коду (Code).
Сам код обычно не меняется. Меняется название (в поле _Description) и пользователь который внёс изменение. Эту информацию я и считываю а потом переписываю в нужную строку нужной таблицы.
С таким же успехом можно было бы сразу написать WHERE _Code = @Code. Поиск идентификатора строки выгладит некоторой избыточностью. Это привычка. Не всегда надо поменять только одну строку. В общем случае работа с идентификаторами быстрее.
Удаление (DELETE):

ALTER TRIGGER [dbo].[Pokup_DELETE] ON [1C_zakaz].[dbo].[_Reference7]
FOR DELETE
AS
  Declare @IDRRef binary(16)
  Declare @Code nvarchar(9)
  SELECT @Code = [_Code] FROM deleted
  SELECT @IDRRef = [_IDRRef] FROM [1C_buh].dbo._Reference8
            WHERE [_Code] = @Code
  DELETE FROM [1C_buh].[dbo]._Reference8 WHERE [_IDRRef] = @IDRRef
Результат выглядит так:
https://youtu.be/USHefsL_hCA

С другой стороны (т.е с базы 1C_buh) должно быть написано тоже самое. У меня не написано (потому что я описываю как это примерно делать а не делаю). Возможно надо будет ещё предусмотреть чтоб он поменьше раз запускали друг друга. Ведь корректировка запускает один триггер, корректирующий чужой справочник. А эта корректировка (в свою очередь) запускает другой триггер (корректирующий исходный справочник). Если не ошибаюсь там хватало проверки на присутствие информации (при вставке) и  совпадение информации (при корректировке). Т.е IF (EXIST()) надо вставить во все тексты и что-то корректировать только если корректировка всё ещё требуется. Точно помню что метод работал.
Точно также можно изменять любую другую информацию. В описываемой базе можно например автоматически создавать документы на отгрузку в бухгалтерской базе переписывая в них только суммы по документам базы сбыта.

 

Просмотров: 438 | Добавил: akostina76 | Рейтинг: 0.0/0
Всего комментариев: 0
Имя *:
Email *:
Код *:
Форма входа
Поиск
Календарь
Архив записей
Друзья сайта
  • Официальный блог
  • Сообщество uCoz
  • FAQ по системе
  • Инструкции для uCoz
  • Copyright MyCorp © 2024
    Бесплатный конструктор сайтов - uCoz