Алгоритмы: улучшаем загрузку из эксель

05.08.25

Разработка - Математика и алгоритмы

Покажу на примерах приемы, которые улучшают алгоритм загрузки из эксель.

Деяния юноши являются основой мудрости старика.

Неизвестный автор

Всем привет!

Напишу про алгоритмы и только.

Про загрузку из эксель много написано, и, кажется, уже ничего нового не написать, и ничему новому никого не научить. Вот такую ставлю перед собой задачу - написать вам что-то новое на примере задачи загрузки из эксель.

Я и сам думал, что загрузка из эксель уже изъезженная тема, но при очередном решении задачи как-то само получилось решить некоторые моменты по-иному. Об этом и пойдет речь. 

Давайте сразу договоримся, что "загрузку из эксель" и "загрузку из макета" - будем считать одним и тем же процессом для заданной задачи. Более подробно я описал такой подход в статье Загрузка номенклатуры из Эксель. Новый взгляд. 

 1. Стандартно загрузка из эксель подразумевает последовательный обход строк и колонок таблицы (эксель или макета) для получения значений полей.

По задаче при загрузке контрагентов некоторые строки повторялись - проверить это можно минимум по 4 полям (колонкам). По старинке можно было бы проверять и сверять каждое из четырех полей.

текПоле1 = 0; текПоле2 = 0; текПоле3 = 0; текПоле4 = 0;	
Для НомерСтроки = 2 По Макет.ВысотаТаблицы Цикл 
		
	Поле1 = СокрЛП(Макет.Область(НомерСтроки,1,НомерСтроки,1).Текст); 
	Поле2 = СокрЛП(Макет.Область(НомерСтроки,7,НомерСтроки,7).Текст);
	Поле3 = СокрЛП(Макет.Область(НомерСтроки,8,НомерСтроки,8).Текст);
	Поле4 = СокрЛП(Макет.Область(НомерСтроки,9,НомерСтроки,9).Текст);  
		
	Если текПоле1 = Поле1 И текПоле2 = Поле2 И текПоле3 = Поле3 И текПоле4 = Поле4 Тогда Продолжить; КонецЕсли;
		
	//обработка полей
	//...
		
	//в конце цикла обязательно запоминаем текущие значения полей
	текПоле1 = Поле1;
	текПоле2 = Поле2;
	текПоле3 = Поле3;
	текПоле4 = Поле4;

КонецЦикла;

При этом , как мы видим, сверяются всегда две строки, стоящие рядом, то есть 1 и 2 , 2 и 3, 3 и 4. При таком алгоритме не сверяются строки 1 и 3, 2 и 4, 1 и 4. Конечно, дополнительно можно упорядочить таблицу по всем сравниваемым полям. Но об этом нужно помнить.

Этот алгоритм я решил запрограммировать по-другому - создаю для каждой строки таблицы (эксель или макета) КлючСтроки - его же и сверяю при обходе. Смотрите, как теперь выглядит код.

МассивСтрок = Новый Массив;
Для НомерСтроки = 2 По Макет.ВысотаТаблицы Цикл 
		
	//сначала проверим задвоенность 	
	КлючСтроки = СокрЛП(Макет.Область(НомерСтроки,1,НомерСтроки,1).Текст) //номер в реестре
	+ СокрЛП(Макет.Область(НомерСтроки,7,НомерСтроки,7).Текст) //состояние 
	+ СокрЛП(Макет.Область(НомерСтроки,8,НомерСтроки,8).Текст) //номер
	+ СокрЛП(Макет.Область(НомерСтроки,9,НомерСтроки,9).Текст); //дата
		
	//проверим на новую запись или дубль
	Если МассивСтрок.Найти(КлючСтроки) = Неопределено Тогда 
         МассивСтрок.Добавить(КлючСтроки); 
    Иначе 
         Продолжить; 
    КонецЕсли;		

    //обработка строк в цикле
    //...

КонецЦикла;
			

После отладки код и вовсе записывается в пару строк.

МассивСтрок = Новый Массив;
Для НомерСтроки = 2 По Макет.ВысотаТаблицы Цикл 
		
	//проверим на новую запись или дубль по ключу строки 	
	КлючСтроки = СокрЛП(Макет.Область(НомерСтроки,1,НомерСтроки,1).Текст) + СокрЛП(Макет.Область(НомерСтроки,7,НомерСтроки,7).Текст) + СокрЛП(Макет.Область(НомерСтроки,8,НомерСтроки,8).Текст) + СокрЛП(Макет.Область(НомерСтроки,9,НомерСтроки,9).Текст); 
	
	Если МассивСтрок.Найти(КлючСтроки) = Неопределено Тогда МассивСтрок.Добавить(КлючСтроки); Иначе Продолжить; КонецЕсли;		
			
    //обработка строк в цикле
    //...
КонецЦикла;

Зафиксируем такой алгоритм решения задач как искусственное создание индекса (ключа строки) по полям структуры данных. 

 2. По задаче я загружал из эксель 3000 контрагентов, и сама по себе загрузка занимала длительное время. С помощью замера производительности выяснилось, что самая затратная операция при загрузке была на таком коде: 

Если НомерКолонки = 3 Тогда
ЗначениеЯчейки = Справочники.Контрагенты.НайтиПоРеквизиту("НомерВРеестре", Стр.НомерВРеестре);
КонецЕсли;

Здесь я решил опробовать другой способ получения контрагентов. Сначала создаю Соответствие.

СоответствиеКонтрагентов = Новый Соответствие;
Выборка = Справочники.Контрагенты.Выбрать();
Пока Выборка.Следующий() Цикл
    Если Выборка.НомерВРеестре>0 Тогда
        СоответствиеКонтрагентов.Вставить(Выборка.НомерВРеестре, Выборка.Ссылка);
    КонецЕсли;
КонецЦикла;

 Затем получаю контрагента из Соответствия.

Если НомерКолонки = 3 Тогда
    ЗначениеЯчейки = СоответствиеКонтрагентов.Получить(Стр.НомерВРеестре);
КонецЕсли;

После отладки код записываю в одну строку - платформа 1С быстрее формирует Соответствие и быстрее обрабатывает условие Если, когда код записан в одну строку.

//до цикла
СоответствиеКонтрагентов = Новый Соответствие;
Выборка = Справочники.Контрагенты.Выбрать();
Пока Выборка.Следующий() Цикл Если Выборка.НомерВРеестре>0 Тогда СоответствиеКонтрагентов.Вставить(Выборка.НомерВРеестре, Выборка.Ссылка); КонецЕсли; КонецЦикла;

//внутри цикла при обходе строк
Если НомерКолонки = 3 Тогда ЗначениеЯчейки = СоответствиеКонтрагентов.Получить(Стр.НомерВРеестре); КонецЕсли;

Зафиксируем такой алгоритм решения задач как замена поиска справочника по реквизиту на поиск по ключу Соответствия.

 3. Обработка строк в цикле зачастую происходит по однотипному алгоритму.

Стр.НомерВРеестре = СокрЛП(Макет.Область(НомерСтроки, 1, НомерСтроки, 1).Текст);

Для 17 полей прописывать похожие строки мне показалось трудоемкой задачей. Как оказалось в дальнейшем, количество полей увеличилось до 39, поскольку пришлось загружать три эксель в одну обработку для дальнейшего анализа. И следующий способ сильно облегчил написание кода.

//до цикла
СписокПолей = "НомерВРеестре, ИНН, Контрагент, Поле4, Поле5, Поле6, Поле7, Номер, Дата, Поле10, Поле11, Поле12, Поле13, Поле14, Поле15, Поле16, Поле17";
МассивПолей = СтрРазделить(СписокПолей, ","); //задаем массив полей
СоответствиеПолей = Новый Соответствие; //задаем соответствие полей
СоответствиеПолей.Вставить("НомерВРеестре", 1);
СоответствиеПолей.Вставить("ИНН", 2);
СоответствиеПолей.Вставить("Контрагент", 3);
СоответствиеПолей.Вставить("Поле4", 4);
СоответствиеПолей.Вставить("Поле5", 5);
СоответствиеПолей.Вставить("Поле6", 6);
СоответствиеПолей.Вставить("Поле7", 7);
СоответствиеПолей.Вставить("Номер", 8);
СоответствиеПолей.Вставить("Дата", 9);
СоответствиеПолей.Вставить("Поле10", 10);
СоответствиеПолей.Вставить("Поле11", 11);
СоответствиеПолей.Вставить("Поле12", 12);
СоответствиеПолей.Вставить("Поле13", 13);
СоответствиеПолей.Вставить("Поле14", 14);
СоответствиеПолей.Вставить("Поле15", 15);
СоответствиеПолей.Вставить("Поле16", 16);
СоответствиеПолей.Вставить("Поле17", 17);

//внутри цикла
Для НомерСтроки = 1 По Макет.ВысотаТаблицы Цикл

    //проверка на задвоенность ...

    //если не задвоено, то создадим запись
    Стр = СписокКонтрагентов.Добавить(); //табличная часть обработки
    Для Каждого Ключ Из МассивПолей Цикл

        Поле = СокрЛП(Ключ);
        НомерКолонки = СоответствиеПолей[Поле];
        ЗначениеЯчейки = СокрЛП(Макет.Область(НомерСтроки,НомерКолонки,НомерСтроки,НомерКолонки).Текст);
        Если ПустаяСтрока(ЗначениеЯчейки) Тогда Продолжить; КонецЕсли;
        Если НомерКолонки = 3 Тогда ЗначениеЯчейки = СоответствиеКонтрагентов.Получить(Стр.НомерВРеестре);
        ИначеЕсли НомерКолонки = 12 ИЛИ НомерКолонки = 13 ИЛИ НомерКолонки = 14 Тогда ЗначениеЯчейки = Булево(Число(ЗначениеЯчейки));
        ИначеЕсли НомерКолонки = 6 ИЛИ НомерКолонки = 9 ИЛИ НомерКолонки = 10 Тогда ЗначениеЯчейки = ДатаИзСтроки(ЗначениеЯчейки);
        КонецЕсли;
        Стр[Поле] = ЗначениеЯчейки; //число преобразуется автоматом
    КонецЦикла;
КонецЦикла;

Зафиксируем такой способ программирования как компактность кода засчёт заранее заданной структуры хранения полей эксель или макета. Еще такой способ называют методом табличного программирования.

 4. Очень хочется поделиться с вами еще с одним алгоритмом. Но он напрямую не связан с загрузкой данных из эксель или макета. Он связан с обработкой полученных данных. Когда у вас есть табличная часть, по которой вам надо найти определенные строки для дальнейшего анализа, вы используете метод табличной части НайтиСтроки().

Если исходная табличная часть у вас была отсортирована по каким-либо полям, то метод НайтиСтроки() вернет массив найденных строк не обязательно в том же отсортированном порядке.

Зная такой нюанс, вы всегда корректно решаете задачу. Я использую для сортировки найденных строк метод пузырька.  

ПараметрыПоиска = Новый Структура;
ПараметрыПоиска.Вставить("Контрагент", Стр.Контрагент);
ПараметрыПоиска.Вставить("Обработан", Ложь);
МассивНайденныхСтрок = Оплаты.НайтиСтроки(ПараметрыПоиска);

//упорядочим массив по номеру строки исходной табличной части
Колво = МассивНайденныхСтрок.Количество();
Для к=0 По Колво-2 Цикл
    Для р=1 По Колво-1 Цикл
        Если МассивНайденныхСтрок[к].НомерСтроки > МассивНайденныхСтрок[р].НомерСтроки Тогда
            Врем = МассивНайденныхСтрок[к];
            МассивНайденныхСтрок[к] = МассивНайденныхСтрок[р];
            МассивНайденныхСтрок[р] = Врем;
        КонецЕсли;
    КонецЦикла;
КонецЦикла;
 
//обработка строк в цикле
Для Каждого СтрМассива Из МассивНайденныхСтрок Цикл
    //...
    СтрМассива.Обработан = Истина;
    //...
КонецЦикла;

Если исходная табличная часть была отсортирована, например, по Контрагенту и Дате, то массив найденных строк можно сортировать по НомеруСтроки - результат будет одинаковым.

Алгоритм сортировки найденных строк можно записать в одну строку - так платформа быстрее его обработает.

ПараметрыПоиска = Новый Структура;
ПараметрыПоиска.Вставить("Контрагент", Стр.Контрагент); 
ПараметрыПоиска.Вставить("Обработан", Ложь);
МассивНайденныхСтрок = ОплатыКФ.НайтиСтроки(ПараметрыПоиска);
		
//упорядочим массив по номеру строки исходной табличной части
Колво = МассивНайденныхСтрок.Количество();
Для к=0 По Колво-2 Цикл Для р=1 По Колво-1 Цикл Если МассивНайденныхСтрок[к].НомерСтроки>МассивНайденныхСтрок[р].НомерСтроки Тогда Врем = МассивНайденныхСтрок[к]; МассивНайденныхСтрок[к] = МассивНайденныхСтрок[р]; МассивНайденныхСтрок[р] = Врем; КонецЕсли; КонецЦикла; КонецЦикла;
		

 Зафиксируем - метод НайтиСтроки() возвращает неотсортированные строки - упорядочивать надо самим. 

На этом все. Всем добра!

Программируйте алгоритмы разные и прекрасные!

Вступайте в нашу телеграмм-группу Инфостарт

загрузка из эксель

См. также

Загрузка и выгрузка в Excel Маркетплейсы Программист Бухгалтер Пользователь 1С v8.3 Бухгалтерский учет 1С:Розница 2 1С:Управление нашей фирмой 1.6 1С:ERP Управление предприятием 2 1С:Бухгалтерия 3.0 1С:Управление торговлей 11 1С:Комплексная автоматизация 2.х Россия Бухгалтерский учет Управленческий учет Платные (руб)

Реальный помощник, с помощью которого Вы преобразуете необходимые документы для Wildberries, OZON, ЯндексМаркет, Мегамаркет, Aliexpress, Детский мир, МагнитЭкспресс (быв.Казань-Экспресс), Леруа Мерлен, ЭНФАНТА (Акушерство), ЛаМода, Летуаль, Твой дом, Золотое Яблоко в документы "Отчет комиссионера (агента) о продажах" и другие. Работает в 1С:БП 3.0, 1С:БП 3.0 КОРП, 1С:УТ 11, 1С:УНФ, 1С:КА 2, 1С:ERP Управление предприятием.

5400 руб.

12.08.2021    40937    470    71    

196

Загрузка и выгрузка в Excel Логистика, склад и ТМЦ Ценообразование, анализ цен Файловый обмен (TXT, XML, DBF), FTP Бухгалтер Пользователь 1С v8.3 1С:Бухгалтерия 2.0 1С:Управление торговлей 10 1С:Розница 2 1С:Управление нашей фирмой 1.6 1С:ERP Управление предприятием 2 1С:Бухгалтерия 3.0 1С:Управление торговлей 11 1С:Комплексная автоматизация 2.х 1С:Управление нашей фирмой 3.0 1С:Розница 3.0 Платные (руб)

Эволюция не стоит на месте - новая удобная версия функциональной обработки для Вашего бизнеса! Что же Вы получаете? Удобный и интуитивно понятный интерфейс с 3-мя этапами работы. 2 режима - автоматический и ручной. Чтение XLSX, XLSM, CSV, XML/YML форматов без офиса, на любом сервере! Визуальное связывание колонок файла и реквизитов простым перетаскиванием колонок. Создание или обновление номенклатуры с иерархией, характеристик, доп. реквизитов, упаковок, загрузка практически неограниченного количества картинок на одну номенклатуру (с возможностью загрузки в несколько потоков одновременно), с хранением в томах или в базе. Загрузка номенклатуры поставщиков или поиск по их данным номенклатуры. Загрузка доп. реквизитов в характеристики. Загрузка штрихкодов с генерацией новых. Создание элементов справочников и ПВХ "на лету" для выбранных реквизитов. (Обновление от 09.07.2025, версия 9.11 - 10.1)

18000 руб.

20.11.2015    165070    410    386    

534

SALE! 10%

Загрузка и выгрузка в Excel Оптовая торговля Бухгалтер Пользователь 1С v8.3 Управляемые формы 1C v8.2 1С:Бухгалтерия 2.0 1С:Бухгалтерия 3.0 1С:Управление производственным предприятием 1С:ERP Управление предприятием 2 1С:Управление холдингом 1С:Комплексная автоматизация 1.х 1С:Комплексная автоматизация 2.х 1С:Управление нашей фирмой 1.6 1С:Управление нашей фирмой 3.0 1С:Управление торговлей 10 1С:Управление торговлей 11 1С:Розница 2 1С:Розница 3.0 Бухгалтерский учет Управленческий учет Платные (руб)

Универсальная обработка для загрузки документов из Excel в 1С. Забудьте о ручном вводе: загружайте документы из Excel в 1С за секунды! Не требует указания параметров (номера колонок, номер первой строки таблицы и т.д.) и предварительной настройки. Просто выбираете файл эксель, документ 1С и нажимаете кнопку "Загрузить"

8000 7200 руб.

09.11.2016    254858    1135    936    

1070

Загрузка и выгрузка в Excel Розничная торговля Логистика, склад и ТМЦ Ценообразование, анализ цен Прайсы Системный администратор Программист 1С v8.3 1С:Комплексная автоматизация 1.х 1С:Розница 2 1С:ERP Управление предприятием 2 1С:Управление торговлей 11 1С:Комплексная автоматизация 2.х Управленческий учет Платные (руб)

Загрузка номенклатуры из файлов Excel (xls, xlsx, ods, csv, mxl) в УТ11, КА 2, ERP 2, Розница 2. Задействованы все возможности конфигурации - заполнение реквизитов номенклатуры, дополнительных реквизитов и сведений, характеристики, доп.реквизиты и сведения характеристик. Дополнительные обработки для расширения возможностей.

11100 руб.

29.10.2014    223389    686    528    

472

Загрузка и выгрузка в Excel Маркетплейсы Программист Бухгалтер Пользователь 1С v8.3 Бухгалтерский учет Оперативный учет 1С:Управление торговлей 10 1С:ERP Управление предприятием 2 1С:Бухгалтерия 3.0 1С:Управление торговлей 11 1С:Комплексная автоматизация 2.х 1С:Управление нашей фирмой 3.0 1С:Розница 3.0 Бухгалтерский учет Платные (руб)

Обработки загрузки данных о продажах WildBerries предназначены для следующих конфигураций: Бухгалтерия предприятия, редакция 3.0; Управление нашей фирмой, редакция 3.0; Розница, редакция 3.0; Управление торговлей, редакция 11; Управление торговлей, редакция 10.3

6000 руб.

11.12.2019    61175    1045    3    

273

ЭДО и ОФД Загрузка и выгрузка в Excel Бухгалтер Бухгалтерский учет 1С:Управление торговлей 10 1С:Управление производственным предприятием 1С:Бухгалтерия 3.0 1С:Управление торговлей 11 1С:Комплексная автоматизация 2.х Россия Бухгалтерский учет Платные (руб)

Кто получает документы в формате XML из различных сервисов ЭДО (формат 820 приказ ФНС 31 мая 2019 или формат 970 (2025г) 19.12.2023 № ЕД-7-26/970@) и набивает их вручную в 1С, тот наверняка хотел бы автоматизировать этот процесс. Поддержка конфигураций: Бухгалтерии 3, УПП 1.3, 1С:КА 2.4 и 1С:КА 2.5, УТ10, УТ11.4 и УТ11.5. Для бухгалтерии 3 добавлена поддержка формат 5.03 от 23/01/2025

3600 руб.

11.02.2020    98117    325    159    

242
Отзывы
27. gybson 08.08.25 21:41 Сейчас в теме
Ключи строк "AA","B" и "A","AB" будут одинаковые. Незаполненные значения будут обработаны неправильно. На большом количестве полей и строк сбои будут обязательно. Используйте СтрСоединить
Artem-B; RustIG; +2 Ответить
Остальные комментарии
Подписаться на ответы Инфостарт бот Сортировка: Древо развёрнутое
Свернуть все
1. Nikola23 709 05.08.25 10:15 Сейчас в теме
Вы молодец, что решили не делать запрос в цикле (поиск контрагента). Почему-то эти цикличные запросы продолжают появляться в решениях разработчиков... добро пожаловать в список тех, кто знает, "как надо"

Еще рекомендую посмотреть, как Эксель читается в таб док, а так док - при помощи построителя сразу превращается в таблицу значений)
RustIG; SerVer1C; Rafaraf; +3 1 Ответить
2. RustIG 1895 05.08.25 10:39 Сейчас в теме
(1) Николай, я с вами не согласен. И ни в какие списки тех, кто знает "как надо" - не стремлюсь. :)

запрос в цикле (поиск контрагента)

нужная вещь, и если по другому нельзя, то можно применять.
здесь критерий истины - это замер производительности и поиск баланса - проходить цикл за один раз всей таблицы значений и в процессе обхода искать ссылки через запрос, или сначала выгрузить из вашей таблицы значений в массив колонку с полем, далее в одном запросе с параметром этого массива найти все ссылки, и снова загрузить в таблицу значений найденные ссылки через повторный обход в цикле таблицы значений... ищем баланс, замеряем время выполнения

при помощи построителя сразу превращается в таблицу значений

да собственно, я в курсе - и иногда применяю такой метод. Только ваш построитель не найдет Контрагента из справочника, придется дополнительно обрабатывать Таблицу значений ...


запрос в цикле

постараюсь найти и предоставить пример, когда запрос в цикле - очень нужная вещь.
1) есть задачи, в которых запрос в цикле необходимый элемент алгоритма.
2) есть разовые задачи, когда обработать за раз данные с помощью запроса в цикле - получается быстрее, чем заморачиваться над вынесением запроса за пределы цикла. Надо принять это, что разовые операции можно делать так, как вам удобно.
3) Механизм представлений в ЗУП - пример конфигурации, в которой запросы в цикле - стандарт, нежели исключение.
4) Запрос в цикле внутри алгоритма, который оперирует данными самой БД - это чаще всего ошибка. А запрос в цикле в алгоритме, который тащит данные из внешнего источника и записывает в БД - это чаще всего необходимый способ обработки данных.
3. w.r. 653 05.08.25 18:45 Сейчас в теме
Конечно есть смысл заморочиться, если на постоянку грузишь. А если нет, то загрузил за 10 минут или за 100, разницы особой нет
4. RustIG 1895 05.08.25 19:16 Сейчас в теме
(3) статья не об этом, не раздувайте тему. Эмоции по этому вопросу у каждого свои. Лучше напишите, что из прочитанного в статье применяли в своей практике.
9. Grigoriy251 136 07.08.25 16:06 Сейчас в теме
(4) ничего, данный метод ужасен и долог.
29. RustIG 1895 11.08.25 13:05 Сейчас в теме
(9) Вы , наверное, имеете в виду другой известный способ загрузки из макета в таблицу значений
ТабДок = ЭлементыФормы.ТабличныйДокументМакета;
	ПоследняяСтрока = ТабличныйДокументМакета.ВысотаТаблицы;
    ПоследняяКолонка = ТабличныйДокументМакета.ШиринаТаблицы;
    ОбластьЯчеек = ТабДок.Область(1,1, ПоследняяСтрока, ПоследняяКолонка);
    ИсточникДанных = Новый ОписаниеИсточникаДанных(ОбластьЯчеек);
    ПостроительОтчета = Новый ПостроительОтчета;
    ПостроительОтчета.ИсточникДанных = ИсточникДанных;
	ПостроительОтчета.Выполнить();
    ТЗ = ПостроительОтчета.Результат.Выгрузить();
Показать


На ИС есть статья 5 способов загрузки https://infostart.ru/1c/tools/1411881/

Ваш способ подходит, когда структура и записи внешней таблицы один в один загрузятся в базу 1С. Удобно.
Но в моей задаче, нужно сначала почистить записи из внешней таблицы. Можно конечно загрузить сначала 12 000 строк в таблицу значений, как вы настаиваете, затем удалять из нее дубли и просто не подходящие с пустыми полями строки. Наверное, в следующей раз сделаю как вы сказали, чтобы замерить время выполнения. :)

это вам не 10 строк товаров соединять для установки цен номенклатуры
Прикрепленные файлы:
5. w.r. 653 06.08.25 04:28 Сейчас в теме
(4)

По теме. Решение у вас тоже странное. Можно считать всю таблицу эксель во временную таблицу и дальше уже с ней работать
6. RustIG 1895 06.08.25 09:27 Сейчас в теме
(5) В чем странность? Не понял вас.
Для разных задач использую разные способы решения - иногда во временную таблицу кидаю данные , потом обрабатываю. Разве речь идет только об этом?

Придется немного отойти от темы в сторону. В данной задаче я сделал АРМ - автоматизированное рабочее место - для проведения анализа данных. С этой обработкой работали два аналитика. Выглядит она так - скрины прикладываю. Структура внешних данных менялась в процессе работы: колонки и содержание полей редактировались при нахождении ошибок. Сам алгоритм обработки сведений и загрузки данных в базу тоже менялся в зависимости от найденных необработанных сценариев.

В целом подобный способ работы с эксель я описывал лет 10 назад - в статье в начале есть ссылка на статью - про работу с макетом, как с промежуточным звеном - это не для задач, где 100 тыс строк надо обрабатывать.
К примеру, для расчета АВС-категорий было и такое - уже не помню сколько было строк для анализа - 30 тыс. может быть - тогда промежуточных макетов не было - чтение из эксель было напрямую и без промежуточных временных таблиц значений - сразу в табличную часть обработки для дальнейшего расчета АВС-категорий. Пример простой обработки с минимум функций вот здесь.

Я тогда также применил несколько ноу-хау, чем удивил директора-1с-ника. Ускорил загрузку и обработку данных эксель.
Может однажды поделюсь с коллегами.

Суть статьи -
1) Ключи строк.
Искусственно можно самим создавать индексы у любых таблиц - так называемые ключи строк есть автоматом в динамических списках. В табличных частях документов, обработках - это только НомерСтроки - но вы можете расширить до своих ключей. Я в своей практике построение своих ключей использовал для разного рода задач, и на ИС читал красивые решения, когда ключи строк в запросах создавали.
2) Получение справочника по реквизиту можно заменить Соответствием.
Тут комментарии излишне.
3) Развитие метода табличного программирования для любых задач, в том числе для задач загрузки данных из эксель и дальнейшей обработки сведений.
4) нюанс метода НайтиСтрки() - у меня на ИС две-три обработки используют этот нюанс - после поиска строк, обязательно делаю сортировку. Кажется, об этом мало говорили на ИС.

Наша с вами 1с-ная жизнь - она такая в большинстве своем - пишем ежедневно небольшие алгоритмы и так до бесконечности. Часть приемов становятся шаблонами мышления и шаблонами разработки. Вот об этом речь. Я тут не о глобальном, а о приземленном.
Прикрепленные файлы:
7. RustIG 1895 06.08.25 10:19 Сейчас в теме
Конфигурация Бухгалтерия предприятия, редакция 3.0 (3.0.176.38) - практически свежая.
Метод НайтиПоРеквизиту() используется в 174 местах.
Если эти вызовы попадут в групповую обработку или в длительные операции, то. конечно, они замедлят общий процесс - групповая обработка это сразу обход по циклу.
В целом, так невидимо пропадает эффективность алгоритмов (КПД).
Другое объяснение, к примеру, если вы используете при создании нового документа автозаполнение полей (такое встречается):
Док = Документы.Тестовый.Создать();
Док.ЗаполнениеРеквизитов();

- при этом в процедуре ЗаполнениеРеквизитов() применяется метод НайтиПоРеквизиту() -
тогда при групповом создании документов вы попадаете в невидимую ловушку.

В данном случае, для ускорения , я бы переписал процедуру ЗаполнениеРеквизитов().
Я уже неоднократно так делал. Например, для заполнения счетов БУ в документе АктСверки...

Кто понял - тот молодец!
Всем добра!
Прикрепленные файлы:
8. SerVer1C 936 07.08.25 15:33 Сейчас в теме
когда запрос в цикле - очень нужная вещь

Уверен (на 99,9%) что любой запрос в цикле можно заменить на 1 запрос после цикла, в котором будут параметры, полученные в теле цикла. Пусть даже вам придется цикл крутить повторно для постобработки, но это будет в разы быстрее, чем запрос в цикле.
RustIG; w.r.; +2 Ответить
10. RustIG 1895 07.08.25 18:52 Сейчас в теме
(8) если речь идет о получении какого-то одного значения через запросную или объектную модель внутри цикла - то , конечно, это долго. Я за это не "топлю"!
Понятно, что линейный последовательный обход в цикле можно ускорить так, как вы написали. На этом ловятся начинающие 1сники, особенно на собеседованиях или на экзаменах по 1С.

Если в цикле получаем одно значение, но запросы не используем, а используем объектную модель - к примеру НайтиПоРеквизиту() или НайтиПоНаименованию() или НайтиПоКоду() - то это тоже не правильно. Но почему вы не упоминаете этот случай? А вспоминаете только "запрос в цикле" ? Почему все только зациклены только на "запросе в цикле"?

Я вам сейчас найду другой класс задач, в которых в цикле получаем не одно значение, а список значений, и с каждой следующей итерацией цикла получаемый список значений уточняется (на него накладывается очередной отбор). В итоге по оконцовке получаем список значений или одно значение, используя запрос в цикле - очень красивые решения получаются при этом.
11. SerVer1C 936 07.08.25 19:08 Сейчас в теме
(10)
Если в цикле получаем одно значение, но запросы не используем, а используем объектную модель - к примеру НайтиПоРеквизиту() или НайтиПоНаименованию() или НайтиПоКоду() - то это тоже не правильно. Но почему вы не упоминаете этот случай? А вспоминаете только "запрос в цикле" ? Почему все только зациклены только на "запросе в цикле"?

Я почему то был уверен, что это и так понятно. Под запросом я понимал непосредственно запрос к СУБД, а не "Запрос" как объект встроенного языка. Разработчик должен разбираться в том, какой метод в коде может обращаться к базе данных.
14. RustIG 1895 07.08.25 19:26 Сейчас в теме
(11)
Под запросом я понимал непосредственно запрос к СУБД, а не "Запрос" как объект встроенного языка.

не все так рассуждают, тем более не все используют такой понятийный аппарат. Чувствуется, что у нас с вами конкретно и у 1с-ников в целом разная школа программирования. В этом вопросе есть большой пробел, да и во многих других вопросах...
могу только порадоваться, что я начал этот диалог, и что вы его подхватили.

(11)
Под запросом я понимал непосредственно запрос к СУБД, а не "Запрос" как объект встроенного языка.

Я внедренец, очень много приходится разбираться в чужом коде в типовых конфигурациях - сейчас не получится выделить из цикла обращение к СУБД. Алгоритмы и механизмы усложнились. Любая групповая обработка документов - это обработка в цикле и в каждой итерации это обращение к СУБД.
12. RustIG 1895 07.08.25 19:10 Сейчас в теме
(8)
Функция ПолучитьСписокХарактеристик()
	
	ПустойМассив = Новый Массив;
	Если ОтборПоСвойствам.Количество() = 0 Тогда
		Возврат ПустойМассив;
	КонецЕсли;
	
	ТЗ = ОтборПоСвойствам.Скопировать(,); 	
	ТЗ.Свернуть("Свойство");
	
	СписокХарактеристик = Новый Массив;
	Для Каждого СтрТЗ Из ТЗ Цикл 

		ПараметрыПоиска = Новый Структура;
		ПараметрыПоиска.Вставить("Свойство", СтрТЗ.Свойство);
		
		МассивСтрок = ОтборПоСвойствам.НайтиСтроки(ПараметрыПоиска);
		СписокЗначенийСвойств = Новый Массив;
		Для Каждого Стр Из МассивСтрок Цикл
			//накапливаем список значений свойств
			СписокЗначенийСвойств.Добавить(Стр.Значение);			
		КонецЦикла;
		
		Запрос = Новый Запрос;
		Запрос.Текст = "ВЫБРАТЬ
		|	ЗначенияСвойствОбъектов.Объект
		|ИЗ
		|	РегистрСведений.ЗначенияСвойствОбъектов КАК ЗначенияСвойствОбъектов
		|ГДЕ
		|	ЗначенияСвойствОбъектов.Свойство = &Свойство
		|	И ЗначенияСвойствОбъектов.Значение В(&СписокЗначенийСвойств)
		|	И ВЫБОР
		|			КОГДА &ИспользоватьСписокХарактеристик
		|				ТОГДА ЗначенияСвойствОбъектов.Объект В (&СписокХарактеристик)
		|			ИНАЧЕ ИСТИНА
		|		КОНЕЦ
		|	И ВЫБОР
		|			КОГДА &ИспользоватьСписокХарактеристик
		|				ТОГДА ВЫРАЗИТЬ(ЗначенияСвойствОбъектов.Объект КАК Справочник.ХарактеристикиНоменклатуры).ПометкаУдаления = ЛОЖЬ
		|			ИНАЧЕ ИСТИНА
		|		КОНЕЦ";
		
		Запрос.УстановитьПараметр("Свойство", СтрТЗ.Свойство);
		Запрос.УстановитьПараметр("СписокЗначенийСвойств", СписокЗначенийСвойств);
		
		Запрос.УстановитьПараметр("ИспользоватьСписокХарактеристик", ?(СписокХарактеристик.Количество() = 0, Ложь, Истина));
		Запрос.УстановитьПараметр("СписокХарактеристик", СписокХарактеристик);
		
		Результат = Запрос.Выполнить();
		Если Результат.Пустой() Тогда
			Возврат ПустойМассив;
		КонецЕсли;
		
		СписокХарактеристик = Результат.Выгрузить().ВыгрузитьКолонку("Объект");
		
	КонецЦикла; 	
		
	Возврат СписокХарактеристик;
	
КонецФункции
Показать


Вот этот алгоритм использован в работе Подбор номенклатуры по характеристикам - там суть такая - вы ставите одну галочку напротив свойства - определенный цвет/определенный размер и т.д., список номенклатуры уменьшается с каждым выбранным свойством.

Обратите внимание , в алгоритме используется запрос в цикле. Это другой класс задач. В моей практике я встречался с подобным способом решения раза три, в задачах совсем не похожих друг на друга. По мере возможности , здесь покажи все примеры таких задач.
13. SerVer1C 936 07.08.25 19:16 Сейчас в теме
(12)
вы ставите одну галочку напротив свойства - определенный цвет/определенный размер и т.д., список номенклатуры уменьшается с каждым выбранным свойством.

Я, наверное, не в контексте данного алгоритма, но не пойму, что мешает собрать все выбранные свойства и отправить 1 запрос для получения результирующего списка по номенклатуре?
17. RustIG 1895 07.08.25 19:40 Сейчас в теме
(13) Сергей, это сложно объяснить. Видимо, придется погрузиться в контекст.
И возможно поэтому с подобной задачей мало кто справится из программистов.
За 20 лет на ИС ни одной статьи на эту тему, ни одного обсуждения.

Задача следующая. Выбираем номенклатуру по "Цвету": Красный или Белый или Зеленый, по "Материалу": либо пластик, либо пластик+. Сколько уже вариантов появилось? 6? Нет, их 1000 - тысяча характеристик, потому есть еще 20 других свойств с 100 разными значениями. И с каждым новым добавлением свойства и значений, список номенклатуры, которая подходит по характеристикам, сужается.

Может быть вы лично решите задачу без повторных вызовов запроса в цикле. Это будет очень круто!
Ильдарович, возможно решит легко. Я к примеру , не понимаю его способ мышления и решения задач. Хотя он вроде сложные задачи решает и описывает.

Я вам больше скажу - ни в одной типовой 1с такого решения нет, и нет подобного функционала.
18. SerVer1C 936 07.08.25 19:46 Сейчас в теме
(17) Думаю, нет обсуждений, потому что это и ежу понятно, что запросы к СУБД в цикле - это полный трэш.
А если не получается сделать без запросов в цикле, то я вижу тут 2 варианта: 1-й: недостаток квалификации - нужно апать левел вверх; 2-й: несоответствующая архитектура хранения данных под условия текущих задач - нужно менять структуру хранения данных.
19. RustIG 1895 07.08.25 19:52 Сейчас в теме
(18) лучше предметно говорить. вот первую задачу я предоставил.
далее по мере возможности буду накидывать задачи - попробуем обсудить.

Вторая задача.
Могу спросить про структуру подчиненности - для построения дерева нужно обратиться к СУБД для каждого родительского документа - в целом работа с деревьями это всегда циклы и рекурсия. Поэтому как решать задачу построения связанных документов без циклов и обращений к СУБД внутри цикла - я пока не знаю.
20. RustIG 1895 07.08.25 21:06 Сейчас в теме
(18)
нет обсуждений, потому что это и ежу понятно, что запросы к СУБД в цикле - это полный трэш.

я не про обсуждение "запроса в цикле", а про обсуждение класса задач, в которых запрос в цикле сужает пространство поиска.
тут , видимо, вы прочитали не внимательно :( и пошли по кругу....
21. RustIG 1895 07.08.25 21:27 Сейчас в теме
(8) вот еще была задача и красивое решение, использующее запрос в цикле.
Функция ПолучитьКоличествоДоговоров(Цепочка)
	
	МассивСтрок = СтрРазделить(Цепочка,",",Ложь);
	Если МассивСтрок.Количество()=0 Тогда
		Возврат 0;
	КонецЕсли;
	
	СписокДоговоров = Новый Массив;
	Для Каждого НомерСтроки Из МассивСтрок Цикл 		
		
		Мин 	= ИсходнаяТаблица.Получить(НомерСтроки-1).Мин;
		Макс 	= ИсходнаяТаблица.Получить(НомерСтроки-1).Макс; 
		Процент = ИсходнаяТаблица.Получить(НомерСтроки-1).Процент;
		
		Запрос = Новый Запрос;
		Запрос.Текст = "ВЫБРАТЬ
		|	НаценкиПоставщиков.ДоговорПоставки КАК ДоговорПоставки
		|ИЗ
		|	РегистрСведений.НаценкиПоставщиков КАК НаценкиПоставщиков
		|ГДЕ
		|	НаценкиПоставщиков.Мин = &Мин
		|	И НаценкиПоставщиков.Макс = &Макс
		|	И НаценкиПоставщиков.Процент = &Процент
		|	И НаценкиПоставщиков.Производитель = ЗНАЧЕНИЕ(Справочник.Производители.ПустаяСсылка)
		|	И НаценкиПоставщиков.ДоговорПоставки.ПометкаУдаления = ЛОЖЬ
		|	И (НаценкиПоставщиков.ДоговорПоставки.ДатаКонца = ДАТАВРЕМЯ(1, 1, 1)
		|			ИЛИ НаценкиПоставщиков.ДоговорПоставки.ДатаКонца > &ТекДата)
		|	И ВЫБОР
		|			КОГДА &ИспользоватьСписокДоговоров
		|				ТОГДА НаценкиПоставщиков.ДоговорПоставки В (&СписокДоговоров)
		|			ИНАЧЕ ИСТИНА
		|		КОНЕЦ";
				
		Запрос.УстановитьПараметр("Мин" 	, Мин);
		Запрос.УстановитьПараметр("Макс" 	, Макс);
		Запрос.УстановитьПараметр("Процент" , Процент);
		Запрос.УстановитьПараметр("ТекДата" , ТекущаяДата());
		Запрос.УстановитьПараметр("ИспользоватьСписокДоговоров", ?(СписокДоговоров.Количество() = 0, Ложь, Истина));
		Запрос.УстановитьПараметр("СписокДоговоров", СписокДоговоров);
		
		Результат = Запрос.Выполнить();
		Если Результат.Пустой() Тогда
			Возврат 0 ;
		КонецЕсли;
		
		СписокДоговоров = Результат.Выгрузить().ВыгрузитьКолонку("ДоговорПоставки");

	КонецЦикла; 	
		
	Возврат СписокДоговоров.Количество();	
	
КонецФункции
Показать


С каждой итерацией круг поиска сужается...
15. RustIG 1895 07.08.25 19:29 Сейчас в теме
для справки, в 2020 году я все также топил за то, чтобы в вопросе "что такое запрос в цикле" не было однозначного мнения, что это плохо, при этом все используют и сопровождают типовые конфигурации, в которых запросы в цикле уже не различимы и не видимы....
комментарий 2020 года
16. SerVer1C 936 07.08.25 19:34 Сейчас в теме
(15)
запросы в цикле уже не различимы и не видимы....

Такое имеет место быть, но это очень плохо, поэтому работа для экспертов всегда будет. Подобные места нужно выявлять и переписывать.
22. RustIG 1895 07.08.25 21:38 Сейчас в теме
(8) запрос в цикле используется при групповом удалении документов - Удаление документов для любых баз на управляемых формах
23. SerVer1C 936 08.08.25 08:26 Сейчас в теме
(22) Вы почему то ссылаетесь на свои же публикации как на истину во языцех. Может, те алгоритмы возможно оптимизировать? В крайнем случае (математическом пределе) мы же можем считать в память (объекты) "ВСЮ" базу данных за 1 запрос и потом алгоритмами отбирать то, что нам нужно. И не будет никаких запросов в цикле. Подумайте над этим.
24. RustIG 1895 08.08.25 09:05 Сейчас в теме
(23)
Вы почему то ссылаетесь на свои же публикации как на истину во языцех

Так спросите - почему я на них ссылаюсь? А не делайте выводы. Вывод не правильный.
Ссылаюсь потому, что код можете посмотреть - или мне надо часы тратить в поисках примеров - я вчера два часа из своей жизни потратил, чтобы вам примеры привести - а вы интерес не проявили и не вникли.
25. RustIG 1895 08.08.25 09:13 Сейчас в теме
(23)
В крайнем случае (математическом пределе) мы же можем считать в память (объекты) "ВСЮ" базу данных за 1 запрос и потом алгоритмами отбирать то, что нам нужно. И не будет никаких запросов в цикле. Подумайте над этим.

вот это слишком сложно. вы опять заговорили абстракциями , и не предметно.
Предметно - берете задачу - и решаем.

Я когда получал сертификат спеца по платформе 1С, решал задачу программирования проводок документа по нескольким регистрам - мы в цикле по табличной части Товаров проходили и делали записи в несколько регистров накоплений и бухгалтерии. Обращение к СУБД в цикле.

И ничего - многие на этих конфигурациях выросли.
Сейчас изменили парадигму - в регистры делают записи предварительно подготовленными наборами ТЗ, а не отдельно по каждой строке товаров.

Сергей, чем вы занимаетесь по 1С? какой у вас опыт?
я вижу что вы умный специалист. но почему -то примеров привел вам я больше, чем вы что-то предметно мне написали. в этом вопросе вы кажетесь теоретиком, чем практиком. без обид.
я лично внедренец, у внедренцев специфичная работа - далеко отличается от разработчиков, у меня есть пробелы в знании БСП, в чем-то еще.... Но запросы в цикле я вижу каждый день. Меня умиляет отношение коллег, которые охают-ахают при виде использования запроса в цикле...
26. RustIG 1895 08.08.25 09:20 Сейчас в теме
(23) вообще тему "запроса в цикле" давно уже обсудили коллеги 1С - и на ИС, и на других форумах. Зачем этот вопрос поднимать здесь и доказывать что-то ? В этом вопросе никто не скажет ничего нового.
Наслаждайтесь тем, что я описал в статье.
27. gybson 08.08.25 21:41 Сейчас в теме
Ключи строк "AA","B" и "A","AB" будут одинаковые. Незаполненные значения будут обработаны неправильно. На большом количестве полей и строк сбои будут обязательно. Используйте СтрСоединить
Artem-B; RustIG; +2 Ответить
28. RustIG 1895 11.08.25 12:27 Сейчас в теме
(27) Спасибо, очень хорошее замечание - для общего случая такие нюансы нужно иметь в виду и всегда проверять в частном случае.
В моем случае типы полей разные:: номер в реестре (число) + состояние (текст) + номер (число) + дата (дата) - хоть и в текстовом формате. Поэтому конкатенация полей однозначная.

Дублируются записи внутри каждого контрагента, поэтому можно усилить алгоритм и проверять дубли только внутри каждого контрагента (номера в реестре) - при условии , что таблица (строки) упорядочены по контрагенту. При начальной загрузке строк никакого упорядочивания нет, поэтому таким образом не получится. Получится, если из эксель загрузить в ТЗ любыми платформенными методами, затем начав обрабатывать ТЗ.

Также можно усилить алгоритм , если использовать СтрСоединить - как вы и подсказали.
Оставьте свое сообщение