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