При подготовке базы 1С 7.7 к миграции данных на платформу 1С 8 (например, с использованием правил Конвертации Данных) разработчики часто сталкиваются с ошибками загрузки. Одной из частых причин является наличие у одного элемента справочника Номенклатура нескольких подчиненных единиц измерения из справочника Единицы с одинаковым кодом ОКЕИ или одинаковым наименованием.
Рассмотрим несколько способов поиска таких дубликатов встроенными средствами языка 1С 7.7 и с помощью прямых SQL-запросов.
Разберем самый понятный и надежный способ для файловых баз (DBF). Алгоритм заключается в последовательном обходе справочника Номенклатура, сборе всех связанных единиц измерения в объект ТаблицаЗначений и последующем сворачивании таблицы по названию единицы и ссылке на владельца.
Проанализируем пример кода обработки:
ТЗ = СоздатьОбъект("ТаблицаЗначений");
ТЗ.НоваяКолонка("Номенклатура", "Справочник.Номенклатура");
ТЗ.НоваяКолонка("Единица", "Строка", 20);
ТЗ.НоваяКолонка("Количество", "Число", 15, 0);
Спр = СоздатьОбъект("Справочник.Номенклатура");
СпрЕдиницы = СоздатьОбъект("Справочник.Единицы");
Спр.ВыбратьЭлементы();
Пока Спр.ПолучитьЭлемент() = 1 Цикл
Если Спр.ЭтоГруппа() = 1 Тогда
Продолжить;
КонецЕсли;
СпрЕдиницы.ИспользоватьВладельца(Спр.ТекущийЭлемент());
СпрЕдиницы.ВыбратьЭлементы();
Пока СпрЕдиницы.ПолучитьЭлемент() = 1 Цикл
ТЗ.НоваяСтрока();
ТЗ.Номенклатура = Спр.ТекущийЭлемент();
ТЗ.Единица = СокрЛП(СпрЕдиницы.Наименование);
ТЗ.Количество = 1;
КонецЦикла;
КонецЦикла;
// Сворачиваем таблицу: если одинаковых единиц у одной номенклатуры несколько,
// колонка Количество просуммируется
ТЗ.Свернуть("Номенклатура, Единица", "Количество");
ТЗ.ВыбратьСтроки();
Пока ТЗ.ПолучитьСтроку() = 1 Цикл
Если ТЗ.Количество > 1 Тогда
Сообщить("Найден дубль единицы (" + ТЗ.Единица + ") у позици: " + ТЗ.Номенклатура);
КонецЕсли;
КонецЦикла;
Рассмотрим вариант оптимизации обхода для крупных баз данных. В платформе 1С 7.7 при вызове метода ВыбратьЭлементы() для подчиненного справочника Единицы без предварительной установки ИспользоватьВладельца() выполняются сплошная выборка всех единиц базы данных. Из текущего элемента справочника единиц доступна ссылка на родительскую номенклатуру через системный реквизит Владелец.
Этот способ позволяет избежать лишних повторных перевыборок в цикле и существенно ускоряет работу в файловом режиме.
Если база данных работает под управлением MS SQL Server (или используются внешние компоненты прямых запросов, такие как 1CPP), выясним ситуацию с помощью группирующего SQL-запроса. Запрос связывает таблицы номенклатуры и единиц по полю связи ParentExt и находит позиции, у которых общее количество единиц не совпадает со количеством уникальных кодов ОКЕИ.
Рассмотрим структуру SQL-запроса:
SELECT
спрНоменклатура.id [Номенклатура $Справочник.Номенклатура],
COUNT(спрЕдиницы.ОКЕИ) [ВсегоЕдиниц],
COUNT(DISTINCT спрЕдиницы.ОКЕИ) [УникальныхОКЕИ]
FROM Справочник.Номенклатура спрНоменклатура
INNER JOIN Справочник.Единицы спрЕдиницы
ON спрНоменклатура.id = спрЕдиницы.ParentExt
GROUP BY спрНоменклатура.id
HAVING COUNT(спрЕдиницы.ОКЕИ) <> COUNT(DISTINCT спрЕдиницы.ОКЕИ)
Посмотрим на порядок действий после получения списка проблемных позиций:
НайтиСсылки(), чтобы убедиться, что дубль не используется в проведенных документах.