МФ и SQL - как обойти кривую выдачу

Автор Злоп, 24 мая 2025, 20:43

« назад - далее »

Злоп

Как известно (?) штатный МФ на SQL отрабатывает криво.
Кто как это обходит (без классов желательно, штатными средствами).

По факту получается что условия МФ вида (штано)
Условие(Контрагент в глУсловие1)
приходится заменять на
Условие(глУсловие1.Принадлежит(Контрагент)=1)

Есть какие-то другие варианты?

Злоп

.. и что-то "потерялся" я в каких случаях МФ на SQL косячит.
Вроде был года в МФ условие "одно из " и в списке - всего одна группа...? Сейчас проверяю - вроде норм работает...
Когда МФ типовой на SQL косячит?

Злоп

Собственно описано здесь для Uchoice
https://infostart.ru/1c/articles/68332/

Для типового использования МФ во всяких отчетах (с закладкой МФ которые) в ГМ меняем
а процедуре глФильтрПоСправочнику
        //	Если ЕстьМФ = 1 Тогда	// есть множественный фильтр по позициям справочника
	//		Если ТипМФ=1 Тогда // принадлежит списку
	//			ТекстЗапроса = ТекстЗапроса+РазделительСтрок+"Условие("+ИмяПеремЗапроса+" в "+ИмяПоляМФ+");";
	//		Иначе     
	//			ТекстЗапроса = ТекстЗапроса+РазделительСтрок+"Условие(НЕ("+ИмяПеремЗапроса+" в "+ИмяПоляМФ+"));";
	//		КонецЕсли;
	//	КонецЕсли;
	//	
	//	Если ЕстьЕФ = 1 Тогда				// есть простой фильтр по позициям справочника
	//		ТекстЗапроса= ТекстЗапроса+РазделительСтрок+"Условие("+ИмяПеремЗапроса+" в "+ИмяПоляЕФ+");";
	//	КонецЕсли;
	// -------- заменено на: -----------------------------------------------------------------------------------------------------
	// для SQL условие в СЗ работает плохо
	Если ЕстьМФ = 1 Тогда	// есть множественный фильтр по позициям справочника
		Если ТипМФ=1 
		Тогда // принадлежит списку
			ТекстЗапроса = ТекстЗапроса+РазделительСтрок+"Условие("+ИмяПоляМФ+".Принадлежит("+ИмяПеремЗапроса+")=1);";
		Иначе // не принадлежит списку     
			ТекстЗапроса = ТекстЗапроса+РазделительСтрок+"Условие("+ИмяПоляМФ+".Принадлежит("+ИмяПеремЗапроса+")=0);";
		КонецЕсли;
	КонецЕсли;
	
	Если ЕстьЕФ = 1 Тогда	// есть простой фильтр по позициям справочника
		Если ПолеЕФ.ЭтоГруппа()=0
		Тогда // элемент справочника
			ТекстЗапроса= ТекстЗапроса+РазделительСтрок+"Условие("+ИмяПеремЗапроса+" в "+ИмяПоляЕФ+");";
		Иначе // группа справочника
			ТекстЗапроса = ТекстЗапроса+РазделительСтрок+"Условие("+ИмяПеремЗапроса+".ПринадлежитГруппе("+ИмяПоляЕФ+")=1);";
		КонецЕсли;
	КонецЕсли;

Злоп

Можно в ГМ процедуры работы не править,
а добавить еще одну процедуру, в которой перед выполнением запроса для SQL версии заменять в текстовке запроса "неправильные" условия на "правильные"...

Злоп

Но все это как-то неаккуратненько, но другого варианта, обойтись штатными возможностями, наверное, нет?

Харлампий Дымба

Цитата: Злоп от 25 мая 2025, 02:20Собственно описано здесь для Uchoice
https://infostart.ru/1c/articles/68332/
Что-то не доверяю я. Запрос действительно не работает в SQL и работает в DBF.
Но вот что ошибка должна называться именно "одна группа в списке" - сомневаюсь. Потому что две группы тоже не работают :)
Просто там запрос реально кривой.
Вместо
    ТекстЗапроса = "
    |ПеремОбъект = Справочник.Контрагенты.ТекущийЭлемент;
    |Группировка ПеремОбъект Без Групп;
    |Перем1 = Справочник.Контрагенты.Родитель;
    |Условие (Перем1 В гУсл1);
    |";
Должно быть
    ТекстЗапроса = "
    |ПеремОбъект = Справочник.Контрагенты.ТекущийЭлемент;
    |Группировка ПеремОбъект Без Групп;
    |Условие (ПеремОбъект В гУсл1);
    |";
И никаких проблем с одной группой в списке - всё отрабатывает нормально. Возможно корни ошибки всё-таки не в "одна группа в списке", а именно в .Родитель. Потому что-то тот же запрос но в виде
    ТекстЗапроса = "
    |ПеремОбъект = Справочник.Контрагенты.ТекущийЭлемент;
    |Группировка ПеремОбъект Без Групп;
    |Перем1 = Справочник.Контрагенты.ОтветственныйМенеджер;
    |Условие (Перем1 В гУсл1);
где отбор идёт по группе менеджеров - нормально отрабатол в SQL.

Харлампий Дымба

Посмотри, потому что Принадлежит( и ПринадлежитГруппе( это прям серьёзное замедление относительно использования элементарного условия с "В".
Не наблюдаю проблем с использованием группы в списке ни в SQL, ни в DBF. Понятно, что в UChoice.ert мог быть неудачный код, но зачем же всё остальное работающее из-за этого ломать? REfPrint.ert тоже при некоторых комбинациях  в ошибку вываливается, но платформа тут ни при чём.


Злоп

 Требуются более детальные исследования.
Условие с переменной, которая . Родитель - достаточно искусственный пример.
.
Надо внимательнее посмотреть.
Возможно на разных SQL по разному отрабатывает.
.
Повнимательнее смотреть на полный текст запроса когда запрос не срабатывает.
.
Надо исследовать. Когда время будет.
А сейчас задача - чтобы возвращался правильный результат. Медленно или быстро - уже второй вопрос.

Харлампий Дымба

Так дело в том, что отбор по списку из одной группы работает в типовых и в SQL, и в DBF. Мифичиская "ошибка" взялась из-за единичного криво написанного запроса: попытка сделать запрос универсальным конструктором привела к корявенькому тексту запроса с .Родитель, который в SQL не отрабатывает (странно, что он вообще отрабатывает в DBF). И это исключительно в UChoice.ert (в типовой ТиС она включена под названием Обработка.ПодборОбъектов - по кнопочке <?> в множественных фильтрах отчетов). И исправление нужно только для этой обработки,  которая никаких глобальных функций не трогает. Так что это вполне сойдёт за ошибку типовой ТиС.
Я почему это всё пишу - просто когда осадочек остаётся, потом начинаешь сильно перестраховываться в тех местах, где это совсем не надо. Плюс без надобности сильно замедлять формирование запросов: если есть условия с вызовом функций языка (не элементарные), запросы будут выполняться знаааачительно медленнее. Вот только что в https://forum.dorex.pro/index.php?topic=257.15 паровоз из нескольких десятков ИЛИ в условии снаряжал, чтобы избежать НайтиЗначение и Принадлежит.
А разбираться да, некогда обычно)



Злоп

то бишь
Условие(Элемент в СЗ) - где Элемент есть переменная запроса, отработает правильно в любом варианте состава СЗ, в СЗ может быть и одна группа, и один элемент и смесь элементов и групп и много групп) - так?
а
Условие(Группа в СЗ) - где Группа есть переменная запроса - скосячит, так?

При этом
Условие(Элемент в ВыбНоменклатура) - где ВыбНоменклатура есть либо элемент, либо группа - отработает норм?
Условие(Группа в ВыбНоменклатура) - отработает норм?

Харлампий Дымба

Если речь про справочники, то:
  • Условие(Элемент в СЗ) - отрабатывает всегда нормально, у меня нет неотработавших примеров;
  • Условие(Группа в СЗ) - вообще не должно существовать в запросе см.#5;
  • Условие(Элемент в ВыбНоменклатура) - отрабатывает всегда нормально, у меня нет неотработавших примеров;
  • Условие(Группа в ВыбНоменклатура) - тоже не должно существовать;

Не стоит делать так (1):
Группа = Справочник.Контрагенты.Родитель;
Условие(Группа в СписокГрупп);
И не стоит делать так (2):
Элемент = Справочник.Контрагенты.ТекущийЭлемент;
Условие(Элемент.Группа в СписокГрупп);
Стоит делать так (3):
Элемент = Справочник.Контрагенты.ТекущийЭлемент;
Условие(Элемент в СписокГруппИНеТолько);

Я просто пытался сместить фокус - проблема не в каких-то пресловутых группах в списке значений, а в использовании группы в качестве переменной запроса - а такого не должно быть в нормальном запросе.
Если есть ИТС, то можно почитать здесь: https://its.1c.ru/db/metod77#content:2147484625:hdoc . Своими словами: при обработке справочника группы справочника не обрабатываются. Они обрабатываются при постобработке уже полученных записей для построения иерархии. Запросом нельзя обработать "только группы" или "все-все элементы и группы" (группы без элементов запросом не получить, также как и группы, чьи элементы не прошли отбор по условиям).
Иллюстрация для размышления:
ТекстЗапроса = 
	"//{{ЗАПРОС(Сформировать)
	|Контрагент = Справочник.Контрагенты.ТекущийЭлемент;
	|Группировка Контрагент ;
	|Условие (Контрагент.ЭтоГруппа()=1);
	|"//}}ЗАПРОС
	;
всегда будет пустой, хотя казалось бы: должен показать группы контрагентов.

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


Злоп

Спасибо за пояснения.
Учту, переделаю, проверю.

Djelf

Ужос, нах...
Перепишите на класс ПрямойЗапрос, ну сожрет он 300мс (на трансформацию запроса в sql), это что проблема?
На мелких запросах совсем чуток, но я запросил и разработчик сделал метод получить Совсем прямой запрос (читайте мануаль), т.е. после обработки парсером, это работает значительно лучше, для запросов, которые требуют минимального отклика.

P.S.
Там все уже устарело, и в mssql и sqlite многое можно реализовать более эффективно - табличными, рекурсивными функциями и т.п.
И! Я не пользуюсь этим классом, мне вопросы типа "как ускорить" постить не надо.

Харлампий Дымба

Я не знаю, что у Злопа. Про себя я писал: основная работа: компоненты "Бухгалтерский учет" и "Расчет". Всё DBF. Никаких регистров и никаких высоконагруженных систем. Даже регистры не мог себе позволить использовать.
+2 ларька на торговле DBF не стоили того, чтобы переписывать ТиС.
+1 нормальный клиент на переписанной комплексной SQL - где-то на периферии основной работы, жужжит и не требует особого внимания.
Пока уважаемые люди ускоряли свои высоконагруженные системы  в SQL не вылезая с 1cpp.ru , я ковырял Зарплату и кадры. Ну никаким боком мне прямые запросы в моих конфах не заходили.
TurboBL- хорошая штука, зря пропустил - хорошее ускорение задаром.
Всё остальное у меня - как правило: 10% время на запрос, 90% на "ВывестиСекцию()".В лучшем случае журнал проводок не за 5 секунд будет формироваться, а за 4.8. И то не факт, что у меня в обозримом будущем получится это корректно сделать. А текущей срочной работы - как минимум на полгода вперед.

Ну и просто:
в типовой ТиС 1011 - 241  запрос, 190 ВыбратьЭлементы, 60 ВыбратьДокументы, 39 ВыбратьПодчиненныеДокументы, плюс обвязка всякая.
Наверное, Сергей со временем всё это перепишет (или уже переписал) и во все ларьки поставит SQL,  но до тех пор - пусть у него не будет ненужной заплатки, там где она не нужна. Если не использовать точку в условиях черного запроса, то может и прямые не понадобятся. ;)

Злоп

У меня как у Харлампия.
Прямые запросы - там где реально клинит.
Не имеет смысла для жабодавных клиентов тратить время на освоение прямых. Самые простенькие прямые я смогу написать.
.
Я скорее прямые освою как хобби от нечего делать чем для клиентов.