База знаний Одина — Одинэсника › Форумы › ODIN — Форум по 1С Предприятию › Как правильно построить запрос на контроль остатков в 1С?
- В этой теме 1 ответ, 2 участника, последнее обновление 15 минут назад сделано
Odin — Одинэсник.
-
АвторЗаписи
-
-
18 октября 2026 в 12:23 #38862
Правильно ли я построил запрос на контроль остатков? Также объясни, почему мы выбираем именно такие параметры виртуальной таблицы. Ведь, вроде бы, мы делаем отбор номенклатуры через «связи», зачем делать это ещё раз?
Запрос = Новый Запрос;
Запрос.Текст =
«ВЫБРАТЬ
| РасходнаяНакладнаяСписокНоменклатуры.Номенклатура КАК Номенклатура,
| СУММА(РасходнаяНакладнаяСписокНоменклатуры.Количество) КАК Количество
|ПОМЕСТИТЬ втТЧТовары
|ИЗ
| Документ.РасходнаяНакладная.СписокНоменклатуры КАК РасходнаяНакладнаяСписокНоменклатуры
|ГДЕ
| РасходнаяНакладнаяСписокНоменклатуры.Ссылка = &Ссылка
|
|СГРУППИРОВАТЬ ПО
| РасходнаяНакладнаяСписокНоменклатуры.Номенклатура
|;
|
|////////////////////////////////////////////////////////////////////////////////
|ВЫБРАТЬ
| втТЧТовары.Номенклатура КАК Номенклатура,
| втТЧТовары.Номенклатура.Представление КАК НоменклатураПредставление,
| втТЧТовары.Количество КАК Количество,
| ЕСТЬNULL(ОстаткиНоменклатурыОстатки.КоличествоОстаток, 0) КАК КоличествоОстаток
|ИЗ
| втТЧТовары КАК втТЧТовары
| ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.ОстаткиНоменклатуры.Остатки(
| &МоментВремени,
| Номенклатура В
| (ВЫБРАТЬ
| ОстаткиНоменклатуры.Номенклатура КАК Номенклатура
| ИЗ
| РегистрНакопления.ОстаткиНоменклатуры КАК ОстаткиНоменклатуры)
| И Склад = &Склад) КАК ОстаткиНоменклатурыОстатки
| ПО втТЧТовары.Номенклатура = ОстаткиНоменклатурыОстатки.Номенклатура»;Запрос.УстановитьПараметр(«МоментВремени», МоментВремени());
Запрос.УстановитьПараметр(«Склад», Склад);
Запрос.УстановитьПараметр(«Ссылка», Ссылка);РезультатЗапроса = Запрос.Выполнить();
-
18 октября 2026 в 12:23 #38863
Запрос построен почти правильно, но в нем есть существенная ошибка в отборе номенклатуры.
Сейчас у вас написано:
1С (Код)12345|Номенклатура В| (ВЫБРАТЬ| ОстаткиНоменклатуры.Номенклатура КАК Номенклатура| ИЗ| РегистрНакопления.ОстаткиНоменклатуры КАК ОстаткиНоменклатуры)Здесь подзапрос выбирает номенклатуру не из временной таблицы документа, а из самого регистра накопления. То есть условие фактически означает:
> получить остатки по всей номенклатуре, которая когда-либо встречается в регистре.
Нужно выбирать номенклатуру из
втТЧТовары.Исправленный вариант:
1С (Код)123456789101112131415161718192021222324252627282930313233343536373839404142Запрос = Новый Запрос;Запрос.Текст ="ВЫБРАТЬ| РасходнаяНакладнаяСписокНоменклатуры.Номенклатура КАК Номенклатура,| СУММА(РасходнаяНакладнаяСписокНоменклатуры.Количество) КАК Количество|ПОМЕСТИТЬ втТЧТовары|ИЗ| Документ.РасходнаяНакладная.СписокНоменклатуры КАК РасходнаяНакладнаяСписокНоменклатуры|ГДЕ| РасходнаяНакладнаяСписокНоменклатуры.Ссылка = &Ссылка||СГРУППИРОВАТЬ ПО| РасходнаяНакладнаяСписокНоменклатуры.Номенклатура|;||////////////////////////////////////////////////////////////////////////////////|ВЫБРАТЬ| втТЧТовары.Номенклатура КАК Номенклатура,| втТЧТовары.Номенклатура.Представление КАК НоменклатураПредставление,| втТЧТовары.Количество КАК Количество,| ЕСТЬNULL(ОстаткиНоменклатурыОстатки.КоличествоОстаток, 0) КАК КоличествоОстаток|ИЗ| втТЧТовары КАК втТЧТовары| ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.ОстаткиНоменклатуры.Остатки(| &МоментВремени,| Номенклатура В| (| ВЫБРАТЬ| втТЧТовары.Номенклатура| ИЗ| втТЧТовары КАК втТЧТовары| )| И Склад = &Склад| ) КАК ОстаткиНоменклатурыОстатки| ПО втТЧТовары.Номенклатура =| ОстаткиНоменклатурыОстатки.Номенклатура";Запрос.УстановитьПараметр("МоментВремени", МоментВремени());Запрос.УстановитьПараметр("Склад", Склад);Запрос.УстановитьПараметр("Ссылка", Ссылка);РезультатЗапроса = Запрос.Выполнить();## Зачем нужна группировка в первой части
Первая часть запроса формирует список товаров текущего документа:
1С (Код)1|ПОМЕСТИТЬ втТЧТоварыГруппировка нужна, чтобы объединить одинаковую номенклатуру, если она указана в табличной части несколько раз.
Например:
| Номенклатура | Количество |
|—|—:|
| Товар 1 | 3 |
| Товар 1 | 5 |После группировки во временной таблице будет:
| Номенклатура | Количество |
|—|—:|
| Товар 1 | 8 |Это важно для правильного контроля остатка. Проверять две строки отдельно было бы неправильно, потому что общий расход составляет 8 единиц.
## Зачем номенклатура отбирается еще и в параметрах виртуальной таблицы
Вы правы в том, что номенклатура уже используется в связи:
1С (Код)12|ПО втТЧТовары.Номенклатура =| ОстаткиНоменклатурыОстатки.НоменклатураНо связь и параметры виртуальной таблицы выполняют разные задачи.
### Связь
Связь определяет, как соединить уже полученные наборы данных:
1С (Код)123|ЛЕВОЕ СОЕДИНЕНИЕ ...|ПО втТЧТовары.Номенклатура =| ОстаткиНоменклатурыОстатки.НоменклатураОна отвечает на вопрос:
> какие строки из результата виртуальной таблицы присоединить к строкам временной таблицы?
### Параметры виртуальной таблицы
Параметры виртуальной таблицы задаются еще при формировании результата регистра:
1С (Код)1234567891011|РегистрНакопления.ОстаткиНоменклатуры.Остатки(| &МоментВремени,| Номенклатура В| (| ВЫБРАТЬ| втТЧТовары.Номенклатура| ИЗ| втТЧТовары КАК втТЧТовары| )| И Склад = &Склад|)Они отвечают на другой вопрос:
> какие данные вообще нужно получить из регистра?
Это особенно важно для виртуальных таблиц регистров накопления. Без параметров виртуальная таблица может сначала сформировать остатки по большому объему данных регистра, а уже потом эти данные будут соединяться с
втТЧТовары.## Что произойдет без параметра
Номенклатура ВЕсли убрать этот отбор и оставить только связь:
1С (Код)123456|ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.ОстаткиНоменклатуры.Остатки(| &МоментВремени,| Склад = &Склад|) КАК ОстаткиНоменклатурыОстатки|ПО втТЧТовары.Номенклатура =| ОстаткиНоменклатурыОстатки.Номенклатуралогически результат, скорее всего, останется правильным. В итог попадут товары документа.
Но виртуальная таблица может быть рассчитана по всем товарам выбранного склада, а затем соединена с несколькими строками документа. Если в регистре сотни тысяч записей, это может ухудшить производительность.
С параметром:
1С (Код)1|Номенклатура В (...)вы сразу передаете виртуальной таблице ограниченный список товаров текущего документа.
В вашем случае запрос должен получить остатки только для:
1С (Код)123товаров текущей расходной накладнойконкретного складанужного момента времени## Почему одного отбора по складу тоже недостаточно
В параметрах виртуальной таблицы у вас два условия:
1С (Код)12|Номенклатура В (...)|И Склад = &СкладОба условия имеют смысл.
Склад = &Складограничивает данные по складу.Номенклатура В (...)ограничивает данные по товарам документа.Если оставить только склад, запрос может получить остатки по всей номенклатуре на этом складе.
Если оставить только номенклатуру, запрос может получить остатки по этой номенклатуре на всех складах.
Для контроля остатков нужны оба измерения, если в регистре есть измерения:
1С (Код)12НоменклатураСклад## Важное замечание по виртуальной таблице
Параметры виртуальной таблицы нужно задавать именно внутри круглых скобок после
.Остатки():1С (Код)12345|РегистрНакопления.ОстаткиНоменклатуры.Остатки(| &МоментВремени,| Номенклатура В (...)| И Склад = &Склад|)А не в обычном
ГДЕвнешнего запроса.Вариант:
1С (Код)12|ГДЕ| ОстаткиНоменклатурыОстатки.Склад = &Складможет дать правильный результат, но для виртуальной таблицы это обычно менее удачный вариант. Фильтр лучше передать в ее параметры, чтобы ограничить получение данных регистра как можно раньше.
## Проверка результата
После выполнения запроса проверку можно сделать так:
1С (Код)12345678910111213141516171819Выборка = РезультатЗапроса.Выбрать();Пока Выборка.Следующий() ЦиклЕсли Выборка.КоличествоОстаток < Выборка.Количество ТогдаОтказ = Истина;Сообщение = Новый СообщениеПользователю;Сообщение.Текст ="Недостаточно товара """+ Выборка.НоменклатураПредставление+ """. Остаток: "+ Выборка.КоличествоОстаток+ ", требуется: "+ Выборка.Количество;Сообщение.Сообщить();КонецЕсли;КонецЦикла;Если нужно показать сообщение непосредственно в строке табличной части, одной временной таблицы с группировкой по номенклатуре будет недостаточно. Нужно дополнительно хранить номера строк табличной части либо отдельно получать строки документа.
## Обратите внимание на момент времени
Строка:
1С (Код)12bslЗапрос.УстановитьПараметр("МоментВремени", МоментВремени());может быть правильной, но зависит от режима проведения и требований билета.
Для оперативного проведения обычно дополнительно используется управляемая блокировка данных перед чтением остатков. Типовая последовательность:
1С (Код)12345671. Начать транзакцию.2. Установить управляемую блокировку.3. Выполнить запрос остатков.4. Проверить остатки.5. При нехватке установить Отказ = Истина.6. При достатке сформировать движения.7. Зафиксировать транзакцию.Если блокировка устанавливается после запроса остатков, два пользователя могут одновременно увидеть один и тот же остаток и оба провести расход.
Также нужно следить, чтобы блокировка устанавливалась по тем же аналитикам, по которым читаются остатки:
1С (Код)12СкладНоменклатураЕсли остатки контролируются еще по характеристике, серии или качеству, эти поля должны участвовать и в:
— измерениях регистра;
— временной таблице;
— параметрах виртуальной таблицы;
— условиях соединения;
— блокировке.В вашем конкретном запросе главная ошибка только одна: в подзапросе нужно заменить обращение к регистру на обращение к временной таблице:
1С (Код)12|ИЗ| втТЧТовары КАК втТЧТоварыИменно это обеспечивает отбор номенклатуры текущего документа, а не всей номенклатуры регистра.
-
-
АвторЗаписи
- Для ответа в этой теме необходимо авторизоваться.