При разработке отчетов на Системе компоновки данных (СКД) программисты часто сталкиваются с ситуацией, которую называют «мистикой»: один и тот же запрос в консоли запросов выдает полные данные, а в отчете СКД некоторые поля (например, ИНН или КПП) внезапно оказываются пустыми. Особенно часто это происходит, когда значение выбирается через конструкцию ВЫБОР или получается из левых соединений. В этой статье мы подробно разберем, почему СКД ведет себя именно так, и как правильно использовать функцию ВЫРАЗИТЬ, чтобы гарантировать вывод данных.
Рассмотрим классический пример, с которым столкнулся автор темы. В конфигурации (например, «Управление торговлей 10.3») ИНН контрагента хранится как Строка длиной 12 символов. При построении отчета по алкогольной продукции необходимо выбрать ИНН производителя, причем логика выбора зависит от того, ведется ли учет по сериям. Напишем фрагмент запроса, который кажется абсолютно логичным:
ВЫБОР
КОГДА КорректировкаРеализации.Номенклатура.ВестиУчетПоСериям
ТОГДА КорректировкаРеализации.Номенклатура.Производитель.ИНН
ИНАЧЕ КорректировкаРеализации.Номенклатура.ПроизводительЕГАИС.ИНН
КОНЕЦ КАК ВозвратИННПроизводителя
В консоли запросов такой код работает идеально: все 12 символов ИНН отображаются для каждой строки. Однако в отчете СКД часть строк приходит с пустым полем ВозвратИННПроизводителя. При этом в карточках производителей ИНН точно заполнен. Выясним причину этого поведения.
Главное отличие консоли запросов от СКД заключается в том, что консоль выполняет запрос «как есть», просто отображая результат, который вернула СУБД. СКД — это мощный объектный механизм, который перед выполнением запроса проводит его глубокую трансформацию. Рассмотрим подробнее, что происходит «под капотом»:
ВЫБОР, оптимизатор может некорректно интерпретировать итоговый тип данных, особенно если поля в разных ветках ТОГДА принадлежат разным таблицам.ВЫБОР встречаются реквизиты из разных источников, или если одна из веток может вернуть NULL (из-за ЛЕВОЕ СОЕДИНЕНИЕ), СКД пытается привести результат к общему типу. В некоторых случаях этот тип определяется как «составной» или как «строка неограниченной длины».Чтобы победить «мистику» и заставить СКД выводить данные корректно, необходимо использовать явное приведение типов. Функция ВЫРАЗИТЬ сообщает системе компоновки (и СУБД), что результат данного выражения всегда должен рассматриваться как строка определенной длины. Посмотрим, как изменится наш код:
ВЫРАЗИТЬ(ВЫБОР
КОГДА КорректировкаРеализации.Номенклатура.ВестиУчетПоСериям
ТОГДА КорректировкаРеализации.Номенклатура.Производитель.ИНН
ИНАЧЕ КорректировкаРеализации.Номенклатура.ПроизводительЕГАИС.ИНН
КОНЕЦ КАК СТРОКА(12)) КАК ВозвратИННПроизводителя
Использование ВЫРАЗИТЬ( ... КАК СТРОКА(12)) решает сразу несколько задач. Во-первых, оно ограничивает длину строки, предотвращая превращение поля в NVARCHAR(MAX) на уровне SQL, что критично для корректной работы группировок в СКД. Во-вторых, это дает подсказку самому процессору компоновки данных о том, какой тип ожидать в данной колонке.
Проанализируем полный текст запроса, приведенный в обсуждении. Мы видим активное использование ЛЕВОЕ СОЕДИНЕНИЕ с таблицами корректировок и сведений об алкогольной продукции. Если для какой-то реализации нет корректировки, все поля таблицы КорректировкаРеализации примут значение NULL.
В обычном запросе NULL в строковом поле часто визуально неотличим от пустой строки. Однако для СКД это принципиально разные сущности. Если первая запись в выборке содержит NULL, а последующие — заполненные строки, СКД может ошибочно инициализировать тип колонки в наборе данных как несовместимый с выводом строковых данных. Именно поэтому в сложных отчетах крайне рекомендуется оборачивать строковые результаты в ВЫРАЗИТЬ, даже если вы уверены, что в базе данных длина строки фиксирована.
Если после правки текста запроса данные все равно не выводятся, проанализируем настройки самого набора данных в схеме компоновки:
ВозвратИННПроизводителя).Как упоминалось в обсуждении, проблема особенно остро встает при формировании специфической отчетности, такой как алкогольная декларация. Там важна точность каждого символа ИНН и КПП. Если производитель в справочнике один, а в документах ЕГАИС — другой, использование условий ВЫБОР неизбежно. Без жесткой типизации через ВЫРАЗИТЬ такие отчеты могут выгружаться с пустыми атрибутами производителей, что приведет к ошибкам при проверке в ФСРАР.
Посмотрим на еще один пример из запроса, где также необходимо приведение типа для КПП:
ВЫРАЗИТЬ(ВЫБОР
КОГДА КорректировкаРеализации.Номенклатура.ВестиУчетПоСериям
ТОГДА КорректировкаРеализации.Номенклатура.Производитель.КПП
ИНАЧЕ КорректировкаРеализации.Номенклатура.ПроизводительЕГАИС.КПП
КОНЕЦ КАК СТРОКА(9)) КАК ВозвратКПППроизводителя
Здесь мы видим аналогичную ситуацию: КПП имеет длину 9 символов. Явное указание СТРОКА(9) гарантирует, что СКД не будет пытаться оптимизировать это поле и выведет его корректно для всех строк, независимо от того, из какой таблицы (основной или ЕГАИС) пришло значение.
Подводя итог, можно сказать, что «поведение СКД» — это не ошибка системы, а следствие работы сложного алгоритма трансформации запросов. Чтобы ваши отчеты всегда показывали достоверные данные, придерживайтесь следующих правил:
ВЫРАЗИТЬ( ... КАК СТРОКА(Х)) для любых полей, которые формируются динамически через ВЫБОР или ЕСТЬNULL.ЛЕВОЕ СОЕДИНЕНИЕ помните о возможном появлении NULL и о том, как это влияет на определение типа колонки в СКД.Таким образом, мы рассмотрели проблему исчезновения данных в СКД и выяснили, что явная типизация — это лучший инструмент разработчика для создания надежных и отказоустойчивых отчетов.