Как в СКД наложить отбор по складу только на одну часть запроса при объединении?

Программист 1С v8.3 (Управляемые формы) 1С:Управление торговлей Управленческий учет Торговля и дистрибуция
← На главную

При разработке отчетов в Системе компоновки данных (СКД) программисты часто сталкиваются с ситуацией, когда необходимо объединить данные из разных источников — например, текущие остатки товаров и обороты продаж. Типичная проблема возникает при попытке наложить отбор: пользователь выбирает в настройках конкретный склад, и СКД автоматически применяет этот фильтр ко всем частям запроса, объединенным через ОБЪЕДИНИТЬ ВСЕ. Это происходит из-за механизмов оптимизации компоновщика макета, который «поднимает» условия на самый верхний уровень.

В этой статье мы подробно разберем, почему так происходит, и рассмотрим несколько эффективных способов решения задачи, от простых «хитростей» с именованием полей до архитектурно правильных подходов с использованием расширений языка запросов СКД.

Суть проблемы: почему отбор «протекает» во все таблицы?

Рассмотрим ситуацию на примере запроса из конфигурации «Управление торговлей 11.5». У нас есть первый запрос к виртуальной таблице ТоварыНаСкладах.Остатки и второй запрос к ВыручкаИСебестоимостьПродаж.Обороты. Проанализируем исходный код:


ВЫБРАТЬ
    ТоварыНаСкладахОстатки.Номенклатура КАК Номенклатура,
    ТоварыНаСкладахОстатки.Склад КАК Склад,
    ТоварыНаСкладахОстатки.ВНаличииОстаток КАК ВНаличии,
    NULL КАК СуммаВыручкиОборот
ПОМЕСТИТЬ ВР_Данные
ИЗ
    РегистрНакопления.ТоварыНаСкладах.Остатки({(&ДатаОстатков)}, ) КАК ТоварыНаСкладахОстатки

ОБЪЕДИНИТЬ ВСЕ

ВЫБРАТЬ
    ВыручкаИСебестоимостьПродажОбороты.АналитикаУчетаНоменклатуры.Номенклатура,
    NULL,
    NULL,
    ВыручкаИСебестоимостьПродажОбороты.СуммаВыручкиОборот
ИЗ
    РегистрНакопления.ВыручкаИСебестоимостьПродаж.Обороты({(&НачалоПериода)}, {(&КонецПериода)}, Авто, ) КАК ВыручкаИСебестоимостьПродажОбороты

Если в настройках компоновки данных на вкладке «Отбор» добавить поле Склад, СКД при генерации итогового SQL-запроса проанализирует все ветки объединения. Найдя поле с псевдонимом Склад, система добавит условие ГДЕ Склад = &П_Склад ко всему результату объединения. В итоге, если во второй части запроса (продажи) склад не выбран (стоит NULL), то при установке фильтра по складу все данные о продажах просто исчезнут из отчета, так как NULL не равен конкретному складу.

Способ 1. Использование расширения языка запросов (Фигурные скобки)

Это наиболее грамотный метод с точки зрения работы именно с СКД. Мы можем явно указать системе, в какое именно место запроса должен транслироваться пользовательский отбор. Для этого используются фигурные скобки {} внутри параметров виртуальной таблицы.

Давайте изменим обращение к таблице остатков. Вместо того чтобы полагаться на общие настройки, пропишем условие непосредственно в источнике:


ИЗ
    РегистрНакопления.ТоварыНаСкладах.Остатки(&Период, {Склад.* КАК Склад}) КАК ТоварыНаСкладахОстатки

В этом случае, если пользователь установит отбор по складу, СКД «поймет», что его нужно подставить в параметры виртуальной таблицы остатков (в поле Условие), а не в общую секцию ГДЕ после объединения. Продажи при этом останутся нетронутыми.

Способ 2. Разделение на разные наборы данных (Data Sets)

Если запрос становится слишком сложным, лучше отказаться от ОБЪЕДИНИТЬ ВСЕ внутри одного текстового запроса и использовать возможности СКД по работе с несколькими наборами данных. Проанализируем этот алгоритм по шагам:

  1. Создаем НаборДанныхЗапрос1 (Остатки). В нем выбираем номенклатуру, склад и остаток.
  2. Создаем НаборДанныхЗапрос2 (Продажи). В нем выбираем номенклатуру и сумму выручки. Поле склада здесь можно либо вообще не выбирать, либо назвать его иначе (например, СкладПродаж).
  3. На закладке «Связи наборов данных» связываем их по полю Номенклатура.

При таком подходе СКД работает с каждым набором изолированно. Отбор по полю Склад затронет только первый набор данных, так как во втором наборе такого поля просто нет или оно имеет другое имя. Это «чистый» способ, который исключает ошибки оптимизации и делает структуру отчета прозрачной.

Способ 3. Переименование полей (Метод «Псевдоним»)

Рассмотрим ситуацию, когда нужно быстро решить проблему без перекраивания структуры наборов данных. Выясним причину, по которой СКД объединяет отборы: она ищет совпадения имен полей. Если мы переименуем поле во второй части запроса или в итоговом выборе, автоматическая привязка может разорваться.

Как сделал автор темы: в первой части объединения поле было названо СкладОстатки. В настройках отбора пользователь теперь выбирает именно СкладОстатки. Поскольку во второй части (продажи) поля с таким именем нет, СКД не сможет наложить этот фильтр на продажи.

Однако будьте осторожны: если вы выводите эти данные в одну колонку, вам все равно придется как-то сопоставить эти поля в настройках «Поля выбора». Этот метод хорош как временная мера («костыль»), но требует внимательности при настройке визуальной части отчета.

Способ 4. Управление ролями полей

Малоизвестный, но эффективный метод — настройка ролей на закладке «Наборы данных». Для каждого поля в таблице СКД есть колонка «Ограничение условия». Если мы хотим, чтобы поле Склад из таблицы продаж никогда не участвовало в фильтрации, мы можем:

  1. Найти поле склада, относящееся к продажам.
  2. Установить галочку в колонке «Ограничение условия».
  3. В колонке «Ограничение доступности» также можно поставить флаг, чтобы пользователь не видел это техническое поле.

Это заставит построитель макета игнорировать данное поле при формировании секции ГДЕ, даже если оно совпадает по имени с полем из первой таблицы.

Способ 5. Использование параметров вместо отборов

Иногда проще и надежнее использовать классические параметры запроса вместо механизмов отбора СКД. Разберем этот вариант:

  1. В тексте первого запроса (остатки) добавляем жесткое условие: ГДЕ Склад = &СкладФильтр.
  2. В настройках СКД на вкладке «Параметры» находим СкладФильтр.
  3. Включаем его в пользовательские настройки.

Поскольку параметр &СкладФильтр используется только в первой части запроса, он физически не может повлиять на вторую часть. Это гарантирует 100% предсказуемый результат, хотя и лишает пользователя гибкости (например, возможности использовать виды сравнения «В списке», если параметр не настроен как список значений).

Резюме

Выбор метода зависит от сложности вашего отчета:

Помните, что СКД — это мощный генератор запросов, и понимание того, как именно он трансформирует ваш текст в итоговый SQL-код, позволяет избегать подобных трудностей с «глобальными» отборами.

← На главную