IE 2017

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

Программирование - Практика программирования

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

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

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

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

Изображение

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

 

 

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

 

 

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

Изображение

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

 

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

 

 

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

 

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

 

 

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

Изображение

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

 

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

 

 

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

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

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

См. также

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