…и каких проблем без него можно избежать

Александр, разработчик 1С, исследовал подвохи флага «Автозаполнение» в СКД и рассказывает, как их обойти.

 

О чем речь

Речь пойдет о флаге «Автозаполнение» в наборе данных Запрос Системы компоновки данных (СКД). Сразу хочу отметить, что флаг «Автозаполнение» доступен только в наборе данных-Запрос.

 

Что делает автозаполнение

Флаг «Автозаполнение» добавляет все выбранные поля последнего пакета запроса, а также поля измерений виртуальных таблиц из всех пакетов запроса. Всегда создает параметры периода в СКД для всех виртуальных таблиц (Обороты и ОстаткиИОбороты – &НачалоПериода, &КонецПериода, Остатки, СрезПервый, СрезПоследних – &Период). Другими словами, эта настройка облегчает процесс составления схемы.

 

В чем подвох?

Иногда возникает ситуация, при которой автозаполнение устанавливает параметры и приводит к наложению отборов в тех местах, где это не требуется.

 

Пример 1

Создадим схему, выбирающую объединением двух запросов обороты за текущий и за прошлый период:

ВЫБРАТЬ
    "Этот период" КАК Раздел,
    ДвиженияДенежныхСредствОбороты.ПриходРасход,
    ДвиженияДенежныхСредствОбороты.СуммаОборот
ИЗ
    РегистрНакопления.ДвиженияДенежныхСредств.Обороты КАК ДвиженияДенежныхСредствОбороты

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

ВЫБРАТЬ
    "Прошлый период",
    ДвиженияДенежныхСредствОбороты.ПриходРасход,
    ДвиженияДенежныхСредствОбороты.СуммаОборот
ИЗ

    РегистрНакопления.ДвиженияДенежныхСредств.Обороты(&НачалоПрошлогоПериода, &КонецПрошлогоПериода, , ) КАК ДвиженияДенежныхСредствОбороты

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

Настройка схемы будет выглядеть следующим образом:

Но в результате выполнения схемы получим результат, в котором обороты что за текущий период, что за предыдущий показывают одно и тоже:

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

ВЫБРАТЬ
    "Этот период" КАК Раздел,
    ДвиженияДенежныхСредствОбороты.ПриходРасход КАК ПриходРасход,
    ДвиженияДенежныхСредствОбороты.СуммаОборот КАК СуммаОборот,
    ДвиженияДенежныхСредствОбороты.ПриходРасход.Порядок КАК ПриходРасходПорядок
ИЗ
    РегистрНакопления.ДвиженияДенежныхСредств.Обороты(&П, &П2, , ) КАК ДвиженияДенежныхСредствОбороты

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

ВЫБРАТЬ
    "Прошлый период",
    ДвиженияДенежныхСредствОбороты.ПриходРасход,
    ДвиженияДенежныхСредствОбороты.СуммаОборот,
    ДвиженияДенежныхСредствОбороты.ПриходРасход.Порядок
ИЗ
    РегистрНакопления.ДвиженияДенежныхСредств.Обороты(&П, &П2, , ) КАК ДвиженияДенежныхСредствОбороты

Решить можно двумя способами:

  • Не использовать параметры с именами &НачалоПериода, &КонецПериода
  • Отключить «Автозаполнение» и прописать все поля и параметры вручную

В случае с отключенным флагом «Автозаполнение» запрос в СКД будет выглядеть следующим образом:

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

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

ВЫБРАТЬ
    "Прошлый период",
    ДвиженияДенежныхСредствОбороты.ПриходРасход,
    ДвиженияДенежныхСредствОбороты.СуммаОборот
ИЗ

    РегистрНакопления.ДвиженияДенежныхСредств.Обороты(&НачалоПрошлогоПериода, &КонецПрошлогоПериода, , ) КАК ДвиженияДенежныхСредствОбороты
{ГДЕ
    ("Прошлый период") КАК Раздел,
    ДвиженияДенежныхСредствОбороты.ПриходРасход.*,
    ДвиженияДенежныхСредствОбороты.СуммаОборот}

 

Пример 2

Нам нужно получить обороты по определенным счетам и остатки по всем счетам. Создаем набор данных запрос с флагом «Автозаполнение»:

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

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

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

Получаем результат, в котором общий остаток на самом деле является остатком по счетам, указанным в отборе:

Что подтверждает запрос из компоновщика макета:

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

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

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

Решить данный кейс можно двумя способами:

  • В расширении языка запросов для поля Счет указать поле отбора, например СчетОтбор (пример описан в публикации https://infostart.ru/public/185880/)
  • Отключить флаг «Автозаполнение» и расставить поля отборов вручную.

Без использования «Автозаполнения» запрос в наборе данных будет выглядеть следующим образом:

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

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

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

А результат:

 

Плохие новости

В платформе 8.3.13 были проведены следующие доработки поведения СКД:

При добавлении отбора в запрос набора данных схемы компоновки данных, содержащего объединения, отбор обязательно добавляется во все части объединения, если отбор удалось поместить хотя бы в одну часть объединения. При этом, в тех частях объединения, в которых отбор применить не удается из-за отсутствия в них полей, использующихся в отборе, в добавляемые условия вместо отсутствующего поля проставляется выражение NULL.

В режиме совместимости с версией 8.3.12 поведение не изменилось.

Источник: http://downloads.v8.1c.ru/content//Platform/8_3_13_1513/1cv8upd_8_3_13_1513.htm#11b285ec-7857-11e8-a3f7-0050569f678a

Таким образом, если мы создаем объединение запросов по двум регистрам, в одном из которых нет определенных полей…

ВЫБРАТЬ
    "ДДС" КАК Раздел,
    ДДС.Счет КАК Счет,
    ДДС.СтатьяДвиженияДенежныхСредств КАК СтатьяДвиженияДенежныхСредств,
    ДДС.СуммаОборот КАК СуммаОборот
ИЗ
    РегистрНакопления.ДвиженияДенежныхСредств.Обороты КАК ДДС

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

ВЫБРАТЬ
    "ДС",
    ДС.Счет,
    NULL,
    ДС.СуммаОборот
ИЗ
    РегистрНакопления.ДенежныеСредства.Обороты КАК ДС

…и накладываем отбор по такому полю (СтатьяДвиженияДенежныхСредств), то компоновщик макета нам добавит условие Null = &П4, которые мы ну никак не ожидали

ВЫБРАТЬ
    "ДДС" КАК Раздел,
    ДДС.Счет КАК Счет,
    ДДС.СуммаОборот КАК СуммаОборот,
    ПРЕДСТАВЛЕНИЕССЫЛКИ(ДДС.Счет) КАК СчетПредставление,
    ДДС.Счет.Наименование КАК СчетНаименование
ИЗ
    РегистрНакопления.ДвиженияДенежныхСредств.Обороты(&П, &П2, , ) КАК ДДС
ГДЕ
    ДДС.Счет = &П3
    И ДДС.СтатьяДвиженияДенежныхСредств = &П4

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

ВЫБРАТЬ
    "ДС",
    ДС.Счет,
    ДС.СуммаОборот,
    ПРЕДСТАВЛЕНИЕССЫЛКИ(ДС.Счет),
    ДС.Счет.Наименование
ИЗ
    РегистрНакопления.ДенежныеСредства.Обороты(&П, &П2, , ) КАК ДС
ГДЕ
    ДС.Счет = &П3
    И NULL = &П4

Как побороть данную проблему? В статье https://infostart.ru/public/936863/ освещена проблема, но предложенное решение мне не удалось повторить. Пока не нашёл решение. Судя по всему данную особенность исправили в версии платформы 8.3.14

При добавлении отбора в запрос набора данных схемы компоновки данных, содержащего объединения, отбор обязательно добавляется во все части объединения, если у набора данных включено автоматическое заполнение доступных полей или поле, к которому применяется отбор, получается через точку от поля, доступного для отбора.

Кроме того, если группа элементов отбора содержала поле, которое было недоступно в одном из объединений, и другое поле, которое было доступно и при этом в другой части объединения все поля были доступными, то такой отбор будет применен и в той части, в которой он был недоступен, с заменой недоступных полей на NULL.

Если в отчете или динамическом списке используется запрос, содержащий объединения и нужно, чтобы отбор на некоторое поле помещался только в определенные части объединения, то рекомендуется отключить для набора данных автоматическое заполнение доступных полей и добавить требуемое поле только в нужные части объединения.

В режиме совместимости с версией 8.3.13 поведение не изменилось.

Источник: https://dl04.1c.ru/content/Platform/8_3_14_1779/1cv8upd_8_3_14_1779.htm#c2e40243-2915-11e9-a3f7-0050569f678a

И действительно, если отключить «Автозаполнение» и расставить поля отборов вручную, то компоновщик макета строит следующий запрос:

ВЫБРАТЬ
    "ДДС" КАК Раздел,
    ДДС.Счет КАК Счет,
    ДДС.СуммаОборот КАК СуммаОборот,
    ПРЕДСТАВЛЕНИЕССЫЛКИ(ДДС.Счет) КАК СчетПредставление,
    ДДС.Счет.Наименование КАК СчетНаименование,
    ВЫБОР
        КОГДА ДДС.Счет.Ссылка ЕСТЬ NULL
            ТОГДА 0
        ИНАЧЕ 1
    КОНЕЦ КАК СчетПолеУпорядочивания1
ИЗ
    РегистрНакопления.ДвиженияДенежныхСредств.Обороты(&П, &П2, , (Счет = &П3) И СтатьяДвиженияДенежныхСредств = &П4) КАК ДДС

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

ВЫБРАТЬ
    "ДС",
    ДС.Счет,
    ДС.СуммаОборот,
    ПРЕДСТАВЛЕНИЕССЫЛКИ(ДС.Счет),
    ДС.Счет.Наименование,
    ВЫБОР
        КОГДА ДС.Счет.Ссылка ЕСТЬ NULL
            ТОГДА 0
        ИНАЧЕ 1
    КОНЕЦ
ИЗ
    РегистрНакопления.ДенежныеСредства.Обороты(&П, &П2, , Счет = &П3) КАК ДС

УПОРЯДОЧИТЬ ПО
    Раздел,
    СчетПолеУпорядочивания1,
    СчетНаименование,
    Счет