Перед тем как начать - небольшое лирическое отступление:
Про совместимость ссылок между базами
Совместимость ссылок - имеется у баз, работающих на одинаковых конфигурациях, а также, на родствернных, например, у конфигураций КА и УПП, КА2 и ERP.
Если в одной из таких баз ссылку на номенклатуру преобразовать в строку функцией "ЗначениеВСтрокуВнутр", то во второй можно обратно распаковать эту строку функцией "ЗначениеИзСтрокиВнутр". При этом если элемент есть во второй базе - в результате получим ссылку на него, а если его в базе нет - получим битую ссылку "<Объект не найден> (...)", но у ссылки будет тип "СправочникСсылка.Номенклатура". Всё это справедливо и когда ссылки на номенклатуру помещены, например, в таблицу значений.
При несовместимости ссылок - система выдаст ошибку или вернет "Неопределено". Аналогично "ЗначениеВСтрокуВнутр/ЗначениеИзСтрокиВнутр" работают "ЗначениеВФайл"/"ЗначениеИФайла", а также помещении/изъятии ссылок в объект "ХранилищеЗначения" (натыкались на это при оптимизации обменов с мобильным клиентом).
Другие методы сериализации, преобразующие в XML или JSON - работают без проблем, т.к. в них тип данных заявляется напрямую, что-то вроде: Type="Справочник.Номенклатура", потому они будут работать и при несовместимости ссылок. Но программно работать с этими видами сериализации - немного сложнее.
В собственном сериализаторе 1С для указания типа ссылки используется GUID типа, описанный в конфигураторе, его можно посмотреть, выгрузив конфигурацию в файлы...
1. Сверка данных между базами
Задача:
Есть две базы, между которыми происходит автоматический обмен по правилам. Из базы А в базу Б выгружаются все Реализации. Важно: база А первична, в базе Б никакие новые реализации вручную не создаются. Обратно ничего не выгружается.
Главный бухгалтер сверяя отчеты замечает, что суммы за месяц разные и просит проверить что всё корректно перенесено из базы А в базу Б, а также если что-то перенесено некорректно - срочно исправить это. Возможно, в базе Б подчиненными гл.бухгалтера "по неосторожности" изменены какие-либо данные. Вопросы организации прав тут опустим.
Задача обычно возникает накануне проверки или сдачи отчетности, соответственно "срок: ВЧЕРА".
Решение:
В базе Б формируется запрос документов (Ссылка, Номер, Дата, Организация, Контрагент, Сумма), результат сохраняется в файл. В базе А формируется аналогичный запрос, данные из базы Б загружаются во временную таблицу запроса и производится сверка таблиц в запросе. Полученные расхождения ставятся на регистрацию в обмен. После обмена - повторяем сверку, убеждаемся, что расхождений нет и сообщаем главному бухгалтеру, что проблема была устранена, просьба проверить. Он сверяет отчеты и подтверждает, что всё ок.
ВЫБРАТЬ
Документ.Номер КАК Номер,
Документ.Дата КАК Дата,
Документ.СуммаДокумента КАК СуммаДокумента
ИЗ
Документ.РеализацияТоваровУслуг КАК Документ
ГДЕ
Документ.Дата МЕЖДУ &ДатаНач И &ДатаКон
И Документ.Проведен
Если ссылки совместимы между конфигурациями (в частности, если используется одна и та-же конфигурация), то добавьте поле Документ.Ссылка в список полей выборки.
ЗначениеВФайл("D:\TEMP\tempdata.dat", РезультатЗапроса);
Сообщить("Выполнено");
D:\TEMP\ - у меня это каталог временных файлов, у Вас может быть другой путь.
Имя файла "tempdata.dat" - тоже можете заменить на произвольное, желательно оставить расширение ".dat" (например, "УдалиМеня.dat")
ВЫБРАТЬ
ВЫРАЗИТЬ(ТЗ.Номер КАК СТРОКА(20)) КАК Номер,
ВЫРАЗИТЬ(ТЗ.Дата КАК ДАТА) КАК Дата,
ВЫРАЗИТЬ(ТЗ.СуммаДокумента КАК ЧИСЛО(15, 2)) КАК СуммаДокумента
ПОМЕСТИТЬ втДанныеБ
ИЗ
&ТЗ КАК ТЗ
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
Документ.Номер КАК Номер,
Документ.Дата КАК Дата,
Документ.СуммаДокумента КАК СуммаДокумента,
Документ.Ссылка КАК Ссылка
ПОМЕСТИТЬ втДанныеА
ИЗ
Документ.РеализацияТоваровУслуг КАК Документ
ГДЕ
Документ.Дата МЕЖДУ &ДатаНач И &ДатаКон
И Документ.Проведен
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
ЕСТЬNULL(втДанныеА.Номер, втДанныеБ.Номер) КАК Номер,
ЕСТЬNULL(втДанныеА.Дата, втДанныеБ.Дата) КАК Дата,
ЕСТЬNULL(втДанныеА.СуммаДокумента, "Отсутствует") КАК СуммаДокументаА,
ЕСТЬNULL(втДанныеБ.СуммаДокумента, "Отсутствует") КАК СуммаДокументаБ,
ЕСТЬNULL(втДанныеА.СуммаДокумента, 0) - ЕСТЬNULL(втДанныеБ.СуммаДокумента, 0) КАК Расхождение,
втДанныеА.Ссылка КАК Ссылка
ИЗ
втДанныеА КАК втДанныеА
ПОЛНОЕ СОЕДИНЕНИЕ втДанныеБ КАК втДанныеБ
ПО (втДанныеА.Номер = втДанныеБ.Номер)
И (втДанныеА.Дата = втДанныеБ.Дата)
ГДЕ
(втДанныеА.СуммаДокумента ЕСТЬ NULL
ИЛИ втДанныеБ.СуммаДокумента ЕСТЬ NULL
ИЛИ ЕСТЬNULL(втДанныеА.СуммаДокумента, 0) <> ЕСТЬNULL(втДанныеБ.СуммаДокумента, 0))
На вкладке "Параметры" параметр ТЗ типа "ТаблицаЗначений" нужно загрузить из файла:
Для каждого СтрокаДанных из РезультатЗапроса Цикл
Если СтрокаДанных.Ссылка=NULL Тогда
Сообщить(СтрФормат("Удалите в базе ""Б"" документ %1 от %2 на сумму %3", СтрокаДанных.Номер, СтрокаДанных.Дата, СтрокаДанных.СуммаДокументаБ));
Иначе
ПланыОбмена.ЗарегистрироватьИзменения(Параметры.Узел, СтрокаДанных.Ссылка);
КонецЕсли;
КонецЦикла;
Сообщить("Выполнено");
Параметры.Узел - задаются на вкладке параметров справа от редактора кода.
Запрос в базе А, когда между базами совместимы ссылки
В случае, когда ссылки совместимы, отсутствующие документы в базе А можно зарегистрировать на удаление в базе Б.
ВЫБРАТЬ
ВЫРАЗИТЬ(ТЗ.Ссылка КАК Документ.РеализацияТоваровУслуг) КАК Ссылка,
ВЫРАЗИТЬ(ТЗ.Номер КАК СТРОКА(20)) КАК Номер,
ВЫРАЗИТЬ(ТЗ.Дата КАК ДАТА) КАК Дата,
ВЫРАЗИТЬ(ТЗ.СуммаДокумента КАК ЧИСЛО(15, 2)) КАК СуммаДокумента
ПОМЕСТИТЬ втДанныеБ
ИЗ
&ТЗ КАК ТЗ
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
Документ.Номер КАК Номер,
Документ.Дата КАК Дата,
Документ.СуммаДокумента КАК СуммаДокумента,
Документ.Ссылка КАК Ссылка
ПОМЕСТИТЬ втДанныеА
ИЗ
Документ.РеализацияТоваровУслуг КАК Документ
ГДЕ
Документ.Дата МЕЖДУ &ДатаНач И &ДатаКон
И Документ.Проведен
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
ЕСТЬNULL(втДанныеА.Номер, втДанныеБ.Номер) КАК Номер,
ЕСТЬNULL(втДанныеА.Дата, втДанныеБ.Дата) КАК Дата,
ЕСТЬNULL(втДанныеА.СуммаДокумента, "Отсутствует") КАК СуммаДокументаА,
ЕСТЬNULL(втДанныеБ.СуммаДокумента, "Отсутствует") КАК СуммаДокументаБ,
ЕСТЬNULL(втДанныеА.СуммаДокумента, 0) - ЕСТЬNULL(втДанныеБ.СуммаДокумента, 0) КАК Расхождение,
втДанныеА.Ссылка КАК Ссылка,
втДанныеБ.Ссылка КАК СсылкаТам
ИЗ
втДанныеА КАК втДанныеА
ПОЛНОЕ СОЕДИНЕНИЕ втДанныеБ КАК втДанныеБ
ПО (втДанныеА.Номер = втДанныеБ.Номер)
И (втДанныеА.Дата = втДанныеБ.Дата)
ГДЕ
(втДанныеА.СуммаДокумента ЕСТЬ NULL
ИЛИ втДанныеБ.СуммаДокумента ЕСТЬ NULL
ИЛИ ЕСТЬNULL(втДанныеА.СуммаДокумента, 0) <> ЕСТЬNULL(втДанныеБ.СуммаДокумента, 0))
Для каждого СтрокаДанных из РезультатЗапроса Цикл
Если СтрокаДанных.Ссылка=NULL Тогда
ПланыОбмена.ЗарегистрироватьИзменения(Параметры.Узел, новый УдалениеОбъекта(СтрокаДанных.СсылкаТам));
Иначе
ПланыОбмена.ЗарегистрироватьИзменения(Параметры.Узел, СтрокаДанных.Ссылка);
КонецЕсли;
КонецЦикла;
Сообщить("Выполнено");
Параметры.Узел - задаются на вкладке параметров справа от редактора кода.
Для "поиска виновных", когда на это есть время (в моем случае - предварительно сделаны бэкапы баз А и Б и после на копиях выполнялся детальный анализ) - выполняется то-же сравнение, и далее расхождения разделяются на 3 группы: Есть в базе А, но нет в базе Б, есть в базе Б, но нет в базе А, есть в А и Б но изменены. Далее, добавляем к данным информацию из журнала регистрации и получаем, кто что делал с данными.
- Документ "Реализация" указан для примера. Cверка проводилась по разным документам, и даже по оборотам счетов с точностью до регистратора.
- Если настроено COM-соединение между базами, можно не выгружать данные в таблицу, а запрашивать их напрямую в обработчике "Код установки параметров запроса".
- Если на этапе "После обмена - повторяем сверку, убеждаемся, что расхождений нет", оказалось, что расхождения есть - скорее всего, придётся копаться с правилами обмена и проверять почему не выгружается тот или иной документ или почему он выгружается/загружается некорректно.
- Для сверки счетов между базами можно использовать "Компаратор оборотов" (//infostart.ru/public/276275/), я также его использую и рекомендую.
2. Перенос данных между базами
Задача:
Пользователи меняют систему учета. Конфигурации различны, но и старая и новая - имеют иерархический справочник "Номенклатура". При этом, ссылки между базами несовместимы. Нужно в чистую базу перенести группы справочника "Номенклатура" из старой базы, сохранив их структуру и внутренние идентификаторы ссылок, чтобы потом привязать к ним элементы. Механизм загрузки элементов уже имеется, нужны только группы.
Решение:
В старой базе создается запрос, который выводит все группы, запрос упорядочивается по ссылке иерархически, но выгружается в таблицу значений (Тип выгрузки: Прямой). Далее, в таблице обрабатываются ссылки, заменяются на уникальные идентификаторы и результат выгружается в файл. В новой базе данные загружаются во временную таблицу, и производится обработка результата запроса. Вся работа заняла около 30 минут.
ВЫБРАТЬ
Номенклатура.Ссылка КАК Ссылка,
Номенклатура.Родитель КАК Родитель,
Номенклатура.Код КАК Код,
Номенклатура.Наименование КАК Наименование
ИЗ
Справочник.Номенклатура КАК Номенклатура
ГДЕ
Номенклатура.ЭтоГруппа
И НЕ Номенклатура.ПометкаУдаления
УПОРЯДОЧИТЬ ПО
Ссылка ИЕРАРХИЯ
Тип выгрузки: Выгружать в таблицу значений
РезультатЗапроса.Колонки.Добавить("СсылкаУИД", новый ОписаниеТипов("Строка", , новый КвалификаторыСтроки(40, ДопустимаяДлина.Переменная)));
РезультатЗапроса.Колонки.Добавить("РодительУИД", новый ОписаниеТипов("Строка", , новый КвалификаторыСтроки(40, ДопустимаяДлина.Переменная)));
Для каждого СтрокаДанных из РезультатЗапроса Цикл
СтрокаДанных.СсылкаУИД = Строка(СтрокаДанных.Ссылка.УникальныйИдентификатор());
СтрокаДанных.РодительУИД = Строка(СтрокаДанных.Родитель.УникальныйИдентификатор());
КонецЦикла;
РезультатЗапроса.Колонки.Удалить("Ссылка");
РезультатЗапроса.Колонки.Удалить("Родитель");
ЗначениеВФайл("D:\TEMP\tempdata.dat", РезультатЗапроса);
Сообщить("Выполнено");
D:\TEMP\ - у меня это каталог временных файлов, у Вас может быть другой путь.
Имя файла "tempdata.dat" - тоже можете заменить на произвольное, желательно оставить расширение ".dat" (например, "УдалиМеня.dat")
ВЫБРАТЬ
ТЗ.СсылкаУИД КАК СсылкаУИД,
ТЗ.РодительУИД КАК РодительУИД,
ТЗ.Код КАК Код,
ТЗ.Наименование КАК Наименование
ПОМЕСТИТЬ ВТ
ИЗ
&ТЗ КАК ТЗ
Выборку из ВТ можно не делать, отладчик сам определит, что последний запрос формирует временную таблицу и выберет из неё данные для показа.
Спр = Справочники.Номенклатура;
НачатьТранзакцию();
Для каждого СтрокаДанных из РезультатЗапроса Цикл
НовыйЭлемент = Спр.СоздатьГруппу();
НовыйЭлемент.УстановитьСсылкуНового(Спр.ПолучитьСсылку(новый УникальныйИдентификатор(СокрЛП(СтрокаДанных.СсылкаУИД))));
НовыйЭлемент.Родитель = Спр.ПолучитьСсылку(новый УникальныйИдентификатор(СокрЛП(СтрокаДанных.РодительУИД)));
НовыйЭлемент.Код = СокрЛП(СтрокаДанных.Код);
НовыйЭлемент.Наименование = СокрЛП(СтрокаДанных.НовыйЭлемент);
КонецЦикла;
ЗафиксироватьТранзакцию();
Сообщить("Выполнено");
Заключение
Запросы и код их обработки из данной статьи подходят для выполнения как в отладчике на обычных формах, так и на управляемых.
В управляемых формах код выполняется на сервере, т.е. файлы тоже сохраняются на сервере (если клиент и сервер запущены на разных машинах - это важно).
Скачать "Отладчик запросов" - можно тут: