Почему в типе колонки запроса 1С появляется NULL и пропадают квалификаторы точности числа при группировке?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

Каждый разработчик на платформе 1С:Предприятие рано или поздно сталкивается со странным поведением системы при анализе типов колонок в результатах запроса. Например, выбирая совершенно обычное числовое поле из табличной части документа (скажем, поле Сумма из документа РеализацияТоваровУслуг), мы обнаруживаем, что тип этой колонки в таблице значений описывается не просто как Число, а как составной тип NULL, Число. При этом в самом результате запроса может не быть ни одной строчки со значением NULL.

Другая связанная с этим проблема — внезапное исчезновение квалификаторов числа (точности и разрядности) после применения группировок или агрегатных функций вроде СУММА. Давайте подробно разберем, почему так происходит, как устроена логика платформы 1С и СУБД, и как правильно принудительно задавать типы в запросах.

Разберем причины появления типа NULL в результатах запроса

Для того чтобы понять, откуда берется тип NULL, нам нужно заглянуть во внутренние механизмы работы платформы 1С и СУБД. Когда мы выполняем запрос и выгружаем его результат в таблицу значений, платформа формирует схему типов данных (объект ОписаниеТипов) еще до того, как СУБД вернет реальные физические строки с данными.

Платформа идет по пути универсальности и оптимизации:

  1. Отказ от сложного анализа схемы данных на лету: Чтобы точно определить, может ли СУБД вернуть NULL в конкретном поле, компилятору запросов 1С пришлось бы детально анализировать структуру таблиц, связи, условия соединений и логические конструкции. Вместо этого платформа превентивно добавляет тип NULL во все потенциально вариативные колонки.
  2. Особенности работы СУБД: В реляционных базах данных практически любое поле может вернуть значение NULL в результате левого или правого соединения (LEFT JOIN / RIGHT JOIN), при обращении к реквизитам битых ссылок или при использовании логического ветвления ВЫБОР КОГДА ... ТОГДА.
  3. Безопасность встроенного языка: Наличие NULL в описании типов защищает код встроенного языка от аварийного завершения (ошибок несоответствия типов) при чтении данных из полученной таблицы значений.

Интересное исключение составляют строковые реквизиты некоторых табличных частей. Для них СУБД на уровне физической структуры гарантирует свойство NOT NULL, а объектная модель 1С всегда записывает пустую строку "" при отсутствии значения. В этих редких случаях платформа точно "знает", что NULL там возникнуть не может, и не включает его в описание типов.

Почему пропадают квалификаторы числа при группировке СУММА()

Часто разработчики замечают, что при выгрузке результата запроса в таблицу значений у числовых колонок сбрасываются свойства Разрядность и РазрядностьДробнойЧасти (они становятся равными нулю/пустыми). Проанализируем, почему это происходит именно при группировке данных.

Это поведение напрямую связано с версией платформы 1С и режимом совместимости:

  1. В старых версиях платформы (или при активном режиме совместимости) результат агрегатных функций СУММА() или СРЕДНЕЕ() автоматически наследовал квалификаторы исходного поля метаданных.
  2. Начиная с версии платформы 8.3.9 логика изменилась. Теперь при использовании агрегатных функций СУММА() и СРЕДНЕЕ() результирующему полю всегда присваивается тип числа неограниченной длины. Платформа делает это умышленно, чтобы предотвратить возможное переполнение разрядов при суммировании огромных массивов данных (когда сумма множества чисел с точностью 15.2 выходит за рамки этих 15 знаков).

Как вернуть квалификаторы точности обратно в запросе

Если вам критически важно, чтобы выгруженная таблица значений содержала четко типизированную колонку с фиксированной разрядностью (например, для последующей передачи в другие алгоритмы или для корректного отображения в интерфейсе), необходимо явно указывать желаемый тип данных непосредственно в тексте запроса.

Для этого мы используем конструкцию ВЫРАЗИТЬ(). Давайте посмотрим на практический пример:


ВЫБРАТЬ
    Реализация.Ссылка КАК Документ,
    ВЫРАЗИТЬ(СУММА(Реализация.Товары.Сумма) КАК ЧИСЛО(15, 2)) КАК ВсегоСумма
ИЗ
    Документ.РеализацияТоваровУслуг КАК Реализация
СГРУППИРОВАТЬ ПО
    Реализация.Ссылка

При таком подходе платформа жестко зафиксирует в ОписаниеТипов колонки ВсегоСумма квалификаторы числа: допустимый знак — любой, разрядность — 15, разрядность дробной части — 2.

Особенности работы функций СУММА и КОЛИЧЕСТВО с NULL-значениями

При работе с агрегатными функциями в запросах крайне важно помнить о разнице в обработке пустых выборок функциями СУММА и КОЛИЧЕСТВО. Это убережет вас от неожиданного появления значений NULL на выходе:

  1. Функция КОЛИЧЕСТВО(): Всегда гарантированно возвращает число. Если исходная таблица пуста или не содержит записей, удовлетворяющих условию, результатом функции будет 0.
  2. Функция СУММА(): Согласно международным стандартам SQL, если исходная выборка пуста или все суммируемые строки содержат значение NULL, функция СУММА() вернет значение NULL, а не 0.

Для решения этой проблемы разработчики часто используют функцию ЕСТЬNULL(). Однако позиционирование этой функции имеет решающее значение. Рассмотрим два варианта:

Вариант 1 (Неверный для пустых таблиц):


// Если запрос не вернет строк, результатом все равно будет NULL!
ВЫБРАТЬ СУММА(ЕСТЬNULL(Таблица.Сумма, 0)) КАК ИтогоСумма

В данном случае функция ЕСТЬNULL защищает нас только от пустых значений внутри существующих строк. Но если сама таблица окажется пустой, агрегатная функция СУММА все равно вернет общий итог NULL.

Вариант 2 (Правильный и надежный):


// Гарантированно вернет 0 в любых обстоятельствах
ВЫБРАТЬ ЕСТЬNULL(СУММА(Таблица.Сумма), 0) КАК ИтогоСумма

Обернув агрегатную функцию снаружи, мы гарантируем, что даже при абсолютно пустой выборке результатом выполнения запроса станет числовой ноль (0), а тип колонки будет корректно обработан системой.

← На главную