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