gifts2017

Неиспользуемые поля в конечных запросах построителя отчетов и СКД

Опубликовал Матвей Москальцов (Matveymc) в раздел Программирование - Практика программирования

Оказывается, если в конечном запросе построителя (или СКД) не используются какие-то поля, то они вырезаются и из верхней подчиненной таблицы, что в некоторых случаях может привести к некорректным результатам

Работая с конфигурацией "Консолидация", вплотную столкнулся с одним механизмом работы построителя отчетов (т.к. в этой конфигурации все завязано на построителе).

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

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

Изображение

Запрос будет выглядеть следующим образом:

 

 

ВЫБРАТЬ
            Подразделения.ГоловноеПодразделение,
            Подразделения.Ссылка КАК Подразделение,
            1 КАК Количество
ПОМЕСТИТЬ Подр
ИЗ
            Справочник.Подразделения КАК Подразделения
ГДЕ
            НЕ Подразделения.ГоловноеПодразделение=ЗНАЧЕНИЕ(Справочник.Подразделения.ПустаяСсылка)
 
СГРУППИРОВАТЬ ПО
            Подразделения.ГоловноеПодразделение,
            Подразделения.Ссылка
;
ВЫБРАТЬ
            Подр.ГоловноеПодразделение КАК ГоловноеПодразделение,
            СУММА(Подр.Количество) КАК КоличествоГоловного
ИЗ
            Подр КАК Подр
 
СГРУППИРОВАТЬ ПО
            Подр.ГоловноеПодразделение

 

 

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

Изображение

Возникает резонный вопрос: «Что за … ?». Давайте проанализируем итоговый текст запроса, который формирует сам построитель. Мы увидим, что текст запроса будет следующим:

 

ВЫБРАТЬ
   Подразделения.ГоловноеПодразделение КАК ГоловноеПодразделение,
   1 КАК Количество
ПОМЕСТИТЬ Подр
ИЗ
   Справочник.Подразделения КАК Подразделения
ГДЕ
   НЕ Подразделения.ГоловноеПодразделение=ЗНАЧЕНИЕ(Справочник.Подразделения.ПустаяСсылка)
 
СГРУППИРОВАТЬ ПО
   Подразделения.ГоловноеПодразделение
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
   Подр.ГоловноеПодразделение КАК ГоловноеПодразделение,
   СУММА(Подр.Количество) КАК КоличествоГоловного
ИЗ
   Подр КАК Подр
 
СГРУППИРОВАТЬ ПО
   Подр.ГоловноеПодразделение

 

 

Т.е. построитель, неиспользуемое поле «Подразделение» дополнительно убрал и из временной таблицы (видимо в целях оптимизации). Осталось выяснить, для всех ли временных таблиц такое происходит. Добавим в запрос промежуточную временную таблицу, в которой просто выберем результат предыдущей:

 

ВЫБРАТЬ
            Подразделения.ГоловноеПодразделение,
            Подразделения.Ссылка КАК Подразделение,
            1 КАК Количество
ПОМЕСТИТЬ Подр1
ИЗ
            Справочник.Подразделения КАК Подразделения
ГДЕ
            НЕ Подразделения.ГоловноеПодразделение=ЗНАЧЕНИЕ(Справочник.Подразделения.ПустаяСсылка)
 
СГРУППИРОВАТЬ ПО
            Подразделения.ГоловноеПодразделение,
            Подразделения.Ссылка
;
 
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
            Подр1.ГоловноеПодразделение,
            Подр1.Подразделение,
            Подр1.Количество
ПОМЕСТИТЬ Подр
ИЗ
            Подр1 КАК Подр1
;
 
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
            Подр.ГоловноеПодразделение КАК ГоловноеПодразделение,
            СУММА(Подр.Количество) КАК КоличествоГоловного
ИЗ
            Подр КАК Подр
 
СГРУППИРОВАТЬ ПО
            Подр.ГоловноеПодразделение

 

 

Выполнив запрос, мы получим результат:

Изображение

Т.е. мы получили верные логические результаты. Давайте посмотрим на запрос, который формирует построитель:

 

ВЫБРАТЬ
   Подразделения.ГоловноеПодразделение КАК ГоловноеПодразделение,
   Подразделения.Ссылка КАК Подразделение,
   1 КАК Количество
ПОМЕСТИТЬ Подр1
ИЗ
   Справочник.Подразделения КАК Подразделения
ГДЕ
   НЕ Подразделения.ГоловноеПодразделение=ЗНАЧЕНИЕ(Справочник.Подразделения.ПустаяСсылка)
 
СГРУППИРОВАТЬ ПО
   Подразделения.ГоловноеПодразделение,
   Подразделения.Ссылка
;
 
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
   Подр1.ГоловноеПодразделение КАК ГоловноеПодразделение,
   Подр1.Количество КАК Количество
ПОМЕСТИТЬ Подр
ИЗ
   Подр1 КАК Подр1
;
 
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
   Подр.ГоловноеПодразделение КАК ГоловноеПодразделение,
   СУММА(Подр.Количество) КАК КоличествоГоловного
ИЗ
   Подр КАК Подр
 
СГРУППИРОВАТЬ ПО
   Подр.ГоловноеПодразделение

 

 

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

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

Вывод: Оптимизация это конечно хорошо, но иногда надо быть осторожным.

См. также

Подписаться Добавить вознаграждение

Комментарии

1. Артур Аюханов (artbear) 15.04.14 19:04
2. Антон Рощин (wolfsoft) 16.04.14 09:06
А если так?
ВЫБРАТЬ
            Подразделения.ГоловноеПодразделение,
            Подразделения.Ссылка КАК Подразделение,
            МАКСИМУМ(1) КАК Количество
ПОМЕСТИТЬ Подр
ИЗ
            Справочник.Подразделения КАК Подразделения
ГДЕ
            НЕ Подразделения.ГоловноеПодразделение=ЗНАЧЕНИЕ(Справочник.Подразделения.ПустаяСсылка)
 
СГРУППИРОВАТЬ ПО
            Подразделения.ГоловноеПодразделение,
            Подразделения.Ссылка
...Показать Скрыть
3. Сергей Смирнов (andogskiy) 16.04.14 10:25
Что-то пример не совсем удачный.
Зачем тут вообще временные таблицы? Не проще ли сделать сразу такой запрос:
ВЫБРАТЬ
   Подразделения.ГоловноеПодразделение КАК ГоловноеПодразделение,
   (КОЛИЧЕСТВО РАЗЛИЧНЫХ Подразделения.Ссылка) КАК КоличествоГоловного
ИЗ
   Справочник.Подразделения КАК Подразделения
ГДЕ
   НЕ Подразделения.ГоловноеПодразделение=ЗНАЧЕНИЕ(Справочник.Подразделения.ПустаяСсылка)
 
СГРУППИРОВАТЬ ПО
   Подразделения.ГоловноеПодразделение
...Показать Скрыть
4. Матвей Москальцов (Matveymc) 16.04.14 10:39
(3) andogskiy, Конечно проще. Пример взят максимально простой, чтоб показать ошибку
5. Ден Вар (vardo) 16.04.14 10:55
В СКД можно сказать измернию что оно обязательное. Тогда будет все ок.
6. bulpi bulpi (bulpi) 16.04.14 14:49
Никогда с таким не сталкивался, но, ИМХО, это не фича, а баг :) И во всех ли релизах он есть?
7. Матвей Москальцов (Matveymc) 17.04.14 08:38
(5) vardo, В конечном запросе два поля: "ГоловноеПодразделение" и "КоличествоГоловного". Поставив обоим в роли "Обязательное" проблема не решится (проверил только что, платформа 1С:Предприятие 8.2 (8.2.18.109)). Т.к. система убирает поле Подразделения.Ссылка, которое даже не участвует в конечном запросе
8. Матвей Москальцов (Matveymc) 17.04.14 08:46
(6) bulpi, ну на последней платформе (1С:Предприятие 8.3 (8.3.4.465)) ошибка сохраняется
9. Никита Грызлов (nixel) 18.04.14 12:42
(6) bulpi, это не баг.
Построитель, как и СКД переформировывает запрос на основании схемы/настроек построителя И/ИЛИ пользовательских настроек. Понимание механизмов работы инструментов и смысла свойств-галочек позволяет избежать таких ошибок.
Большинство таких "проблем" разруливается на уровне вкладки "Построитель/Компоновка данных" в конструкторе запросов.
Ну и чтение офф. литературы помогает, да.
10. Даниил Матвеев (cargobird) 29.06.16 11:54
Первый раз в жизни занимался "кощунством" - собирал временные таблицы в запросе построителя отчета обратно во вложенные, чтобы оптимизатор не резал поля очень нужной временной таблицы первого уровня....
11. Даниил Матвеев (cargobird) 04.07.16 10:41
Рано радовался...
Попался пример, в котором под одним пользователем одно из полей считается необязательным, и его построитель "режет", а под другим - не режет.
Права и прочее одинаковое, а тексты запроса по ПостроительОтчета.ПолучитьЗапрос() разные.
12. Даниил Матвеев (cargobird) 04.07.16 12:00
(11) cargobird, причем убиралось поле из конечного запроса, в других местах запроса этого поля не было.
Оказалось, что дело было в сохраненных через форму настройках построителя отчета.
Именно в момент применения настроек ПостроительОтчета.ПолучитьЗапрос() выдавал запрос уже без требуемого поля.
Сбросил настройку - текст запроса стал формироваться как надо.
Для написания сообщения необходимо авторизоваться
Прикрепить файл
Дополнительные параметры ответа