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