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