В практике начинающих разработчиков 1С часто встречаются ситуации, когда написанный код не только выдает ошибки синтаксиса, но и архитектурно выстроен неверно, что приводит к зависаниям системы или непредсказуемым результатам. Рассмотрим классический пример "неработающего" кода, разберем причины ошибок и выясним, как написать эффективный и корректный алгоритм.
Проанализируем исходный код, представленный в обсуждении. Ошибки здесь начинаются с самых основ языка 1С. Во-первых, выясним причину остановки выполнения: в цикле Для Каждого б Из Массив Цикл используется условие Если, которое не закрыто оператором КонецЕсли. Это приводит к тому, что конфигуратор даже не сможет скомпилировать данный фрагмент кода, выдав ошибку синтаксического контроля.
Во-вторых, обратим внимание на работу с массивом. В строке Массив[б].Добавить(Код) допущена грубая логическая ошибка. При обходе коллекции Для Каждого переменная б уже содержит значение элемента массива. Попытка использовать это значение как индекс (Массив[б]) приведет к ошибке типа, если в массиве хранятся не числа. Более того, метод Добавить() принадлежит самому объекту Массив, а не его элементам (если только вы не создаете массив массивов).
В-третьих, рассмотрим строку Сообщить(Массив.Итог("Код")). У стандартного объекта Массив в 1С нет метода Итог. Данный метод существует только у объекта ТаблицаЗначений для суммирования числовых колонок. Попытка "суммировать ссылки", как предлагал автор темы, технически невозможна, так как ссылка является уникальным идентификатором (GUID), а не числом.
Разберем ошибки в тексте самого запроса. В коде автора написано: ИЗ Документ КАК Документ. В языке запросов 1С не существует универсальной таблицы Документ. Необходимо всегда указывать конкретный тип метаданных, например, Документ.РеализацияТоваровУслуг. Если же целью является получение данных из табличной части, путь должен быть еще более детальным.
Рассмотрим правильный синтаксис обращения к табличной части:
|ВЫБРАТЬ
| РеализацияТовары.Номенклатура КАК Номенклатура,
| РеализацияТовары.Цена КАК Цена
|ИЗ
| Документ.РеализацияТоваровУслуг.Товары КАК РеализацияТовары
|ГДЕ
| РеализацияТовары.Ссылка В (&МассивДокументов)
Одной из самых серьезных архитектурных ошибок является размещение конструкции Новый Запрос внутри цикла обхода документов. Рассмотрим, почему это критично. Если в вашем списке 1000 документов, система выполнит 1000 отдельных обращений к серверу базы данных. Это создает колоссальную нагрузку и замедляет работу программы.
Разберем правильный алгоритм решения задачи по шагам:
Запрос один раз.В (&МассивДокументов) в тексте запроса.Посмотрим на пример реализации правильного подхода:
// 1. Подготавливаем массив ссылок
МассивСсылок = Новый Массив;
Для Каждого Док Из СписокДокументов Цикл
МассивСсылок.Добавить(Док.Ссылка);
КонецЦикла;
// 2. Создаем запрос один раз
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ДокТовары.Номенклатура КАК Номенклатура,
| ДокТовары.Цена КАК Цена
|ИЗ
| Документ.РеализацияТоваровУслуг.Товары КАК ДокТовары
|ГДЕ
| ДокТовары.Ссылка В (&МассивСсылок)";
Запрос.УстановитьПараметр("МассивСсылок", МассивСсылок);
// 3. Выполняем запрос
РезультатЗапроса = Запрос.Выполнить();
Выборка = РезультатЗапроса.Выбрать();
Пока Выборка.Следующий() Цикл
// Обработка данных
Сообщить("Номенклатура: " + Выборка.Номенклатура + ", Цена: " + Выборка.Цена);
КонецЦикла;
Проанализируем ситуацию, упомянутую в сообщении 38: поиск "последней номенклатуры на остатках" через перебор документов. В системе 1С для получения остатков категорически не рекомендуется использовать документы. Информация об остатках хранится в Регистрах накопления.
Для решения подобных задач следует обращаться к виртуальным таблицам регистра. Например, если нам нужны актуальные остатки на складах, мы воспользуемся таблицей Остатки регистра накопления ТоварыНаСкладах. Это позволит получить готовый результат мгновенно, без суммирования ссылок и сложного перебора истории движений.
Рассмотрим пример запроса к регистру накопления:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ТоварыНаСкладахОстатки.Номенклатура,
| ТоварыНаСкладахОстатки.КоличествоОстаток
|ИЗ
| РегистрНакопления.ТоварыНаСкладах.Остатки(&Период, ) КАК ТоварыНаСкладахОстатки";
Запрос.УстановитьПараметр("Период", ТекущаяДата());
Результат = Запрос.Выполнить();
Важный момент: Если вам действительно нужно найти последний созданный документ, ориентируйтесь на поле Дата (или МоментВремени для учета позиции внутри секунды), а не на Код или Номер, так как нумерация может быть сбита или содержать префиксы, что сделает сортировку по ним некорректной.
Используйте встроенный инструмент Конструктор запроса. Он поможет избежать опечаток в именах таблиц и автоматически сформирует правильную структуру кода, включая установку параметров и обход выборки. Это сэкономит ваше время и убережет от элементарных синтаксических ошибок.