ОФ 8,2 Как оптимизировать код? ЗАПРОС В ЦИКЛЕ!!!
Задача: У документа "ПриходнаяНакладная" при проведении алкогольной продукции ,если не заполнена колонка ТЧ.Состав - "Производитель" тогда запрет проведения.
Сделал обращение в РС "ВидыАлкогольнойПродукции" и получаеться ЗАПРОС В ЦИКЛЕ!!! как можно оптимизировать это?? чтобы не было запроса в цикле?
Я так сделал:
-В модуле док-та "ПриходнаяНакладная" в обработчике "ПередЗаписью" пишу
и соответственно сама функция
Задача: У документа "ПриходнаяНакладная" при проведении алкогольной продукции ,если не заполнена колонка ТЧ.Состав - "Производитель" тогда запрет проведения.
Сделал обращение в РС "ВидыАлкогольнойПродукции" и получаеться ЗАПРОС В ЦИКЛЕ!!! как можно оптимизировать это?? чтобы не было запроса в цикле?
Я так сделал:
-В модуле док-та "ПриходнаяНакладная" в обработчике "ПередЗаписью" пишу
Для каждого Строка из Состав Цикл
Если ПроверкаАлкогольнойПродукции(Строка.Номенклатура) Тогда //обращение у функции
Если Строка.Производитель.Пустая() тогда
Сообщить("Документ не проведен, у номенклатуры с номером №" + Строка.НомерСтроки + Строка.Номенклатура + ", не указан производитель!");
Отказ = Истина;
Возврат;
КонецЕсли;
КонецЕсли;
КонецЦикла;
Показатьи соответственно сама функция
Функция ПроверкаАлкогольнойПродукции(Номенклатура)
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ВидыАлкогольнойПродукции.Номенклатура КАК Номенклатура
|ИЗ
| РегистрСведений.ВидыАлкогольнойПродукции КАК ВидыАлкогольнойПродукции
|ГДЕ
| ВидыАлкогольнойПродукции.Номенклатура = &Номенклатура";
Запрос.УстановитьПараметр("Номенклатура", Номенклатура);
РезультатЗапроса = Запрос.Выполнить();
ВыборкаДетальныеЗаписи = РезультатЗапроса.Выбрать();
Если ВыборкаДетальныеЗаписи.Следующий() Тогда
Возврат Истина
КонецЕсли;
Возврат Ложь;
КонецФункции
ПоказатьПо теме из базы знаний
- Запрос против рекурсии или разузлование номенклатуры
- Боремся с запросами в циклах. Мой опыт рефакторинга запросов
- Штрихкодирование документов
- Как читать чужой код? Часть 1. Общие вопросы. Доработка чужого кода. Code review
- Зачем и как читать чужой код? Какой результат ожидаем получить? Основные подходы
Ответы
Подписаться на ответы
Инфостарт бот
Сортировка:
Древо развёрнутое
Свернуть все
Выгрузить колонку Номенклатура в массив.
И массив передать в запрос в качестве параметра.
То есть:
А дальше обработать результат запроса.
Номенклатура = Состав.ВыгрузитьКолонку("Номенклатура");
И массив передать в запрос в качестве параметра.
То есть:
| ВидыАлкогольнойПродукции.Номенклатура В (&Номенклатура)";
А дальше обработать результат запроса.
РезультатЗапроса = Запрос.Выполнить();
ВыборкаДетальныеЗаписи = РезультатЗапроса.Выбрать();
Если ВыборкаДетальныеЗаписи.Следующий() Тогда
Возврат Истина
КонецЕсли;
Замени на:
РезультатЗапроса = Запрос.Выполнить();
Если НЕ РезультатЗапроса.Пустой() Тогда
Возврат Истина
КонецЕсли;
Тебе выборку получать не надо если у тебя в результате запроса что то есть. Просто проверяй на пустоту результат.
Тогда так:
РезультатЗапроса = Запрос.Выполнить();
Если НЕ РезультатЗапроса.Пустой() Тогда
Выборка = РезультатЗапроса.Выбрать()
Пока Выборка.Следующий() Цикл
Сообщить("У номенклатуры "+ Выборка.Номенклатура + " что то там не указано.");
КонецЦикла;
КонецЕсли;
(6)
что то я может не догоняю, как будет результат запроса в цикле, так и остался...
что то я может не догоняю, как будет результат запроса в цикле, так и остался...
Для каждого Строка из Состав Цикл //ВОТ цикл
Если ПроверкаАлкогольнойПродукции(Строка.Номенклатура) Тогда //А здесь каждый раз проверка??
Если Строка.Производитель.Пустая() тогда
Сообщить("Документ не проведен, у номенклатуры с номером №" + Строка.НомерСтроки + Строка.Номенклатура + ", не указан производитель!");
Отказ = Истина;
Возврат;
КонецЕсли;
КонецЕсли;
КонецЦикла;
Показать
а не проще сначала выгрузить всю номенклатуру в таблицу значений а потом в цикле просто искать в этой таблице.
перед циклом делаем запрос выгружаем
перед циклом делаем запрос выгружаем
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ВидыАлкогольнойПродукции.Номенклатура КАК Номенклатура
|ИЗ
| РегистрСведений.ВидыАлкогольнойПродукции КАК ВидыАлкогольнойПродукции";
РезультатЗапроса = Запрос.Выполнить().Выгрузить();
Для каждого Строка из Состав Цикл
Если РезультатЗапроса.Найти(Строка.Номенклатура, "Номенклатура") = Неопределено Тогда
Сообщить("Документ не проведен, у номенклатуры с номером №" + Строка.НомерСтроки + Строка.Номенклатура + ", не указан производитель!");
Отказ = Истина;
Возврат;
КонецЕсли
КонецЦикла
Показать
А что такого сложного или неправильного?
1) Из всей табличной части выгружаем в таблицу значений со столбцами НомерСтроки и Номенклатура.
2) Делаем запрос, который в качестве параметра принимает нашу ТЗ, загружает во временную таблицу и индексирует по Номенклатуре.
3) Следующий запрос в том же пакете возьмёт временную таблицу и левым соединением проверит всё, что надо. На выходе получаем результат запроса со столбцом НомерСтроки, оставляя только ошибочные строки.
4) Выгружаем результат запроса в таблицу значений, оттуда выгружаем колонку НомерСтроки в массив, который скармливаем функции СтрСоединить(). Всё, у нас готова строка с перечислением ошибочных строк документа! А проверить, были ли ошибки вообще, просто: достаточно проверить не пустой ли результат запроса, или число строк в таблице значений.
Запрос выполнится на сервере, достаточно быстро и без лишних телодвижений.
1) Из всей табличной части выгружаем в таблицу значений со столбцами НомерСтроки и Номенклатура.
2) Делаем запрос, который в качестве параметра принимает нашу ТЗ, загружает во временную таблицу и индексирует по Номенклатуре.
3) Следующий запрос в том же пакете возьмёт временную таблицу и левым соединением проверит всё, что надо. На выходе получаем результат запроса со столбцом НомерСтроки, оставляя только ошибочные строки.
4) Выгружаем результат запроса в таблицу значений, оттуда выгружаем колонку НомерСтроки в массив, который скармливаем функции СтрСоединить(). Всё, у нас готова строка с перечислением ошибочных строк документа! А проверить, были ли ошибки вообще, просто: достаточно проверить не пустой ли результат запроса, или число строк в таблице значений.
Запрос выполнится на сервере, достаточно быстро и без лишних телодвижений.
(12)
Не правильно выгружать результат запроса в ТЗ без необходимости, нужно пользоваться выборкой из результата запроса.
В данной задаче грузить ТЗ в результат запроса то же наверное избыточное действие. Там довольно простая проверка. Достаточно выгрузить в массив колонку с номенклатурой, передать в запрос как параметр и в запросе сделать проверку нужных условий.
или неправильного?
Не правильно выгружать результат запроса в ТЗ без необходимости, нужно пользоваться выборкой из результата запроса.
2) Делаем запрос, который в качестве параметра принимает нашу ТЗ, загружает во временную таблицу и индексирует по Номенклатуре.
3) Следующий запрос в том же пакете возьмёт временную таблицу и левым соединением проверит всё, что надо. На выходе получаем результат запроса со столбцом НомерСтроки, оставляя только ошибочные строки.
3) Следующий запрос в том же пакете возьмёт временную таблицу и левым соединением проверит всё, что надо. На выходе получаем результат запроса со столбцом НомерСтроки, оставляя только ошибочные строки.
В данной задаче грузить ТЗ в результат запроса то же наверное избыточное действие. Там довольно простая проверка. Достаточно выгрузить в массив колонку с номенклатурой, передать в запрос как параметр и в запросе сделать проверку нужных условий.
(13) Нет, IMHO, как раз тут - лучше ТЗ.
Ваш метод быстро даст ответ, все ли строки - с заполненным Производителем. Но он не даст ответа, в каких строках ошибка. Если бы не это, было бы проще: в параметр запроса передать массив номенклатуры, потом просто
Но нам нужно получить номера ошибочных строк! Именно поэтому нужно в запрос передавать и номера строк, и Номенклатуру, а возвращать - только номера строк с ошибками.
Ваш метод быстро даст ответ, все ли строки - с заполненным Производителем. Но он не даст ответа, в каких строках ошибка. Если бы не это, было бы проще: в параметр запроса передать массив номенклатуры, потом просто
Если ПроверочныйЗапрос.Выполнить().Выбрать().Следующий() Тогда
//Сообщаем об ошибке
КонецЕсли;
Но нам нужно получить номера ошибочных строк! Именно поэтому нужно в запрос передавать и номера строк, и Номенклатуру, а возвращать - только номера строк с ошибками.
(14)Он даст ответ у какой номенклатуры не заполнено то что проверяется. Может вывести название номенклатуры будет достаточно.
К тому же можно обойти выборку в которой так же выводить номенклатуру и номер строки(если конечно его подгрузить предварительно в запрос).
тут вроде как и номенклатура то же выводится.
К тому же можно обойти выборку в которой так же выводить номенклатуру и номер строки(если конечно его подгрузить предварительно в запрос).
а возвращать - только номера строк с ошибками.
Сообщить("Документ не проведен, у номенклатуры с номером №" + Строка.НомерСтроки + Строка.Номенклатура + ", не указан производитель!");
тут вроде как и номенклатура то же выводится.
(15) Сравните Ваш подход и мой.
Ваш:
1) выгружаем колонку ТЧ в массив.
2) передаём в запрос массив номенклатуры, получаем результат.
3) делаем цикл, перебираем все строки ТЧ, чтобы убедиться, что всё нормально, или нет.
Попутно держим дополнительную переменную, куда записываем встреченные ошибки.
4) сообщаем пользователю.
Мой:
1) Выгружаем ТЧ в ТЗ.
2) передаём ТЗ в запрос, получаем результат.
3) Если результат пустой, то всё хорошо. Тогда не надо даже дальнейших действий делать!
4) Получаем результат, сворачиваем его в строчную переменную и сообщаем пользователю - всё это уложится в одну строку кода.
Мой алгоритм выполнится полностью на сервере, то есть быстрее, и потребует получение данных только в случае ошибки, то есть, отработает кратно быстрее при перепроведении заведомо корректных документов.
Ваш:
1) выгружаем колонку ТЧ в массив.
2) передаём в запрос массив номенклатуры, получаем результат.
3) делаем цикл, перебираем все строки ТЧ, чтобы убедиться, что всё нормально, или нет.
Попутно держим дополнительную переменную, куда записываем встреченные ошибки.
4) сообщаем пользователю.
Мой:
1) Выгружаем ТЧ в ТЗ.
2) передаём ТЗ в запрос, получаем результат.
3) Если результат пустой, то всё хорошо. Тогда не надо даже дальнейших действий делать!
4) Получаем результат, сворачиваем его в строчную переменную и сообщаем пользователю - всё это уложится в одну строку кода.
Мой алгоритм выполнится полностью на сервере, то есть быстрее, и потребует получение данных только в случае ошибки, то есть, отработает кратно быстрее при перепроведении заведомо корректных документов.
(17)
Ваш алгоритм подразумевает обход циклом, который делается ВСЕГДА, и НА КЛИЕНТЕ (не забывайте, у автора обычное приложение)! То есть, данные ВСЕГДА гоняются между клиентом и сервером.
Мой алгоритм выполняется ТОЛЬКО НА СЕРВЕРЕ, а на клиент данные нужно передавать ТОЛЬКО при ошибке, и ТОЛЬКО те, которые нужно сообщить, а не всю табличную часть.
Разницу Вы, вероятно, не видите, да?
Ваш бы пыл, да в рациональное русло...
Ваш алгоритм подразумевает обход циклом, который делается ВСЕГДА, и НА КЛИЕНТЕ (не забывайте, у автора обычное приложение)! То есть, данные ВСЕГДА гоняются между клиентом и сервером.
Мой алгоритм выполняется ТОЛЬКО НА СЕРВЕРЕ, а на клиент данные нужно передавать ТОЛЬКО при ошибке, и ТОЛЬКО те, которые нужно сообщить, а не всю табличную часть.
Разницу Вы, вероятно, не видите, да?
Ваш бы пыл, да в рациональное русло...
(19)
Вы написали: передавать в запрос массив номенклатуры.
Автору надо:
а) быстро ответить на вопрос, есть ли ошибки;
б) если ошибки есть, вывести пользователю номера строк с ошибками.
Для того, чтобы выполнить задачу автора, в Вашем случае придётся обходить результат запроса в цикле. Для этого на клиент надо будет передать результат запроса и табличную часть документа. В случае массового перепроведения это станет проблемой. Да, и в Вашем случае можно модифицировать запрос, чтобы в случае, когда всё хорошо, не перебирать все строки. Но от цикла при ошибках, а значит, и от передачи лишних данных от клиента в сервер и обратно, Вы не обойдётесь.
А ведь задача-то решается примитивно! Хватит уже троллить!
Вы написали: передавать в запрос массив номенклатуры.
Автору надо:
а) быстро ответить на вопрос, есть ли ошибки;
б) если ошибки есть, вывести пользователю номера строк с ошибками.
Для того, чтобы выполнить задачу автора, в Вашем случае придётся обходить результат запроса в цикле. Для этого на клиент надо будет передать результат запроса и табличную часть документа. В случае массового перепроведения это станет проблемой. Да, и в Вашем случае можно модифицировать запрос, чтобы в случае, когда всё хорошо, не перебирать все строки. Но от цикла при ошибках, а значит, и от передачи лишних данных от клиента в сервер и обратно, Вы не обойдётесь.
А ведь задача-то решается примитивно! Хватит уже троллить!
(20)
А что это какая то проблема? Если в результате запроса несколько элементов их логично надо обходить в цикле, это же не запрос в цикле, а работа с уже прочитанными данными.
Вы считаете проверять пустой запрос выборкой это правильно?
Зачем?
Так вы и так при ошибках должны передать данные что бы вывести сообщение пользователю.
Перестаньте уже делать эти выпады... Не интересует дискуссия можете просто пройти мимо.
в Вашем случае придётся обходить результат запроса в цикле.
А что это какая то проблема? Если в результате запроса несколько элементов их логично надо обходить в цикле, это же не запрос в цикле, а работа с уже прочитанными данными.
Если ПроверочныйЗапрос.Выполнить().Выбрать().Следующий() Тогда
//Сообщаем об ошибке
КонецЕсли;
Вы считаете проверять пустой запрос выборкой это правильно?
Для этого на клиент надо будет передать результат запроса и табличную часть документа.
Зачем?
Но от цикла при ошибках, а значит, и от передачи лишних данных от клиента в сервер и обратно, Вы не обойдётесь.
Так вы и так при ошибках должны передать данные что бы вывести сообщение пользователю.
Хватит уже троллить!
Перестаньте уже делать эти выпады... Не интересует дискуссия можете просто пройти мимо.
Для получения уведомлений об ответах подключите телеграм бот:
Инфостарт бот