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