Как исправить критические ошибки в коде 1С и правильно составить запрос для получения данных?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

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

Анализ синтаксических ошибок и логических нестыковок

Проанализируем исходный код, представленный в обсуждении. Ошибки здесь начинаются с самых основ языка 1С. Во-первых, выясним причину остановки выполнения: в цикле Для Каждого б Из Массив Цикл используется условие Если, которое не закрыто оператором КонецЕсли. Это приводит к тому, что конфигуратор даже не сможет скомпилировать данный фрагмент кода, выдав ошибку синтаксического контроля.

Во-вторых, обратим внимание на работу с массивом. В строке Массив[б].Добавить(Код) допущена грубая логическая ошибка. При обходе коллекции Для Каждого переменная б уже содержит значение элемента массива. Попытка использовать это значение как индекс (Массив[б]) приведет к ошибке типа, если в массиве хранятся не числа. Более того, метод Добавить() принадлежит самому объекту Массив, а не его элементам (если только вы не создаете массив массивов).

В-третьих, рассмотрим строку Сообщить(Массив.Итог("Код")). У стандартного объекта Массив в 1С нет метода Итог. Данный метод существует только у объекта ТаблицаЗначений для суммирования числовых колонок. Попытка "суммировать ссылки", как предлагал автор темы, технически невозможна, так как ссылка является уникальным идентификатором (GUID), а не числом.

Исправление структуры запроса

Разберем ошибки в тексте самого запроса. В коде автора написано: ИЗ Документ КАК Документ. В языке запросов 1С не существует универсальной таблицы Документ. Необходимо всегда указывать конкретный тип метаданных, например, Документ.РеализацияТоваровУслуг. Если же целью является получение данных из табличной части, путь должен быть еще более детальным.

Рассмотрим правильный синтаксис обращения к табличной части:


|ВЫБРАТЬ
|   РеализацияТовары.Номенклатура КАК Номенклатура,
|   РеализацияТовары.Цена КАК Цена
|ИЗ
|   Документ.РеализацияТоваровУслуг.Товары КАК РеализацияТовары
|ГДЕ
|   РеализацияТовары.Ссылка В (&МассивДокументов)

Устранение антипаттерна "Запрос в цикле"

Одной из самых серьезных архитектурных ошибок является размещение конструкции Новый Запрос внутри цикла обхода документов. Рассмотрим, почему это критично. Если в вашем списке 1000 документов, система выполнит 1000 отдельных обращений к серверу базы данных. Это создает колоссальную нагрузку и замедляет работу программы.

Разберем правильный алгоритм решения задачи по шагам:

  1. Сбор параметров: Сначала подготовим массив ссылок на документы, которые нам нужно обработать.
  2. Создание запроса вне цикла: Инициализируем объект Запрос один раз.
  3. Передача массива в параметры: Используем условие В (&МассивДокументов) в тексте запроса.
  4. Выполнение и обработка: Получаем результат запроса один раз и обходим его в цикле для обработки данных.

Посмотрим на пример реализации правильного подхода:


// 1. Подготавливаем массив ссылок
МассивСсылок = Новый Массив;
Для Каждого Док Из СписокДокументов Цикл
    МассивСсылок.Добавить(Док.Ссылка);
КонецЦикла;

// 2. Создаем запрос один раз
Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |	ДокТовары.Номенклатура КАК Номенклатура,
    |	ДокТовары.Цена КАК Цена
    |ИЗ
    |	Документ.РеализацияТоваровУслуг.Товары КАК ДокТовары
    |ГДЕ
    |	ДокТовары.Ссылка В (&МассивСсылок)";

Запрос.УстановитьПараметр("МассивСсылок", МассивСсылок);

// 3. Выполняем запрос
РезультатЗапроса = Запрос.Выполнить();
Выборка = РезультатЗапроса.Выбрать();

Пока Выборка.Следующий() Цикл
    // Обработка данных
    Сообщить("Номенклатура: " + Выборка.Номенклатура + ", Цена: " + Выборка.Цена);
КонецЦикла;

Как правильно получать остатки товаров?

Проанализируем ситуацию, упомянутую в сообщении 38: поиск "последней номенклатуры на остатках" через перебор документов. В системе 1С для получения остатков категорически не рекомендуется использовать документы. Информация об остатках хранится в Регистрах накопления.

Для решения подобных задач следует обращаться к виртуальным таблицам регистра. Например, если нам нужны актуальные остатки на складах, мы воспользуемся таблицей Остатки регистра накопления ТоварыНаСкладах. Это позволит получить готовый результат мгновенно, без суммирования ссылок и сложного перебора истории движений.

Рассмотрим пример запроса к регистру накопления:


Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |	ТоварыНаСкладахОстатки.Номенклатура,
    |	ТоварыНаСкладахОстатки.КоличествоОстаток
    |ИЗ
    |	РегистрНакопления.ТоварыНаСкладах.Остатки(&Период, ) КАК ТоварыНаСкладахОстатки";

Запрос.УстановитьПараметр("Период", ТекущаяДата());
Результат = Запрос.Выполнить();

Важный момент: Если вам действительно нужно найти последний созданный документ, ориентируйтесь на поле Дата (или МоментВремени для учета позиции внутри секунды), а не на Код или Номер, так как нумерация может быть сбита или содержать префиксы, что сделает сортировку по ним некорректной.

Используйте встроенный инструмент Конструктор запроса. Он поможет избежать опечаток в именах таблиц и автоматически сформирует правильную структуру кода, включая установку параметров и обход выборки. Это сэкономит ваше время и убережет от элементарных синтаксических ошибок.

← На главную