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