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