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