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