Имя: Пароль:
1C
 
Как избежать рваного запроса
0 golem14
 
20.07.21
06:24
Мне нужно добавить в запрос условие которое может быть включено иди выключено.

Где Документ.Валюта = &Рубли

Я сделал через динамическое построение текста запроса:

+ ДопУсловие +

ну и установка параметра

Запрос.УстановитьПараметр("Рубли", Справочники.Валюты.НайтиПоНаименованию("RUB"));

Но я не хочу чтобы запрос собирался из кусочков, это неудобно для дальнейшей разработки и отладки.
Как можно сделать это динамическое условие более удобным и понятным?
1 dubolom
 
20.07.21
06:29
Если СКД, то фигурные скобки.
Если нет, то
ГДЕ &ЕстьВалюта = ЛОЖЬ ИЛИ Документ.Валюта = &Рубли
И передаёте дополнительный параметр, включающий/выключающий условие.
2 ILM
 
модератор
20.07.21
06:32
ВЫБОР - вот ваш выбор!

Например условие в секции запроса "ГДЕ":

ГДЕ
    ВЫБОР
         КОГДА &Рубли = НЕОПРЕДЕЛЕНО
           ТОГДА ИСТИНА
     ИНАЧЕ Документ.Валюта =&Рубли
    КОНЕЦ
3 spectre1978
 
20.07.21
06:33
Внутри запроса допустим комментарий //.
Можно в тексте сделать закомментированное условие, а в случае необходимости выпонить СтрЗаменить (ТекстЗапроса, '//', ''). Добавив после // некое ключевое слово, это можно без проблем расширить на множество условий.
4 Адинэснег
 
20.07.21
06:39
(0) Схема запроса
Привет из 2018
5 ILM
 
модератор
20.07.21
06:39
(3) Это не удобно, давно в 2006 году это было нормой в УПП. Потом сделали отдельные запросы, так как при работе с конструктором запросов все комментарии удаляются.
6 Адинэснег
 
20.07.21
06:41
СхемаЗапроса = Новый СхемаЗапроса;
СхемаЗапроса.УстановитьТекстЗапроса(Запрос.Текст);
// ковыряем запрос как объект
Запрос.Текст = СхемаЗапроса.ПолучитьТекстЗапроса();
7 Адинэснег
 
20.07.21
06:45
если принципиально через запрос, то передавай параметр "... ГДЕ &НужноВключитьОтбор И Документ.Валюта = &Рубли"
Запрос.УстановитьПараметр("НужноВключитьОтбор ", ОтборВключаем);
8 golem14
 
20.07.21
06:49
сделал так:
&ТолькоРублевыеПлатежи = Ложь ИЛИ ЗнРДС.Валюта = &Рубли
9 golem14
 
20.07.21
06:49
(6) а что за схема запроса? чем это отличается от того что я просто буду править текст запроса как строку?
10 ДенисЧ
 
20.07.21
06:51
(9) Это будет стильно и модно.
11 golem14
 
20.07.21
06:55
(10) и чем оно тогда отличается от построения через СКД?
12 Адинэснег
 
20.07.21
07:06
(9) когда запрос нужно будет изменить не в 2х, а 22х местах
(11) СКД то тут причем? 🤣
13 ДедМорроз
 
20.07.21
07:08
А теперь представьте,что у вас таких условий несколько.
Поэтому,или использовать СКД с автовключением условий или строить текст запроса из частей - например - все условия,которые применяются в массив,а потом СтрСоединить.
14 Документовед
 
20.07.21
07:08
Запрос.УстановитьПараметр("спСтатейЗатратИсключений", Отчет.спСтатейЗатратИсключений);
Запрос.УстановитьПараметр("ЕстьспСтатейЗатратИсключений", Отчет.спСтатейЗатратИсключений.Количество()>0);


Запрос.УстановитьПараметр("Организация", Отчет.Организация);
Запрос.УстановитьПараметр("ЕстьОрганизация", ЗначениеЗаполнено(Отчет.Организация));



                  |                ВЫБОР
                  |                    КОГДА &ЕстьОрганизация
                  |                        ТОГДА Организация = &Организация
                  |                    ИНАЧЕ ИСТИНА
                  |                КОНЕЦ,

                  |                    И ВЫБОР
                  |                        КОГДА &ЕстьспСтатейЗатратИсключений
                  |                            ТОГДА НЕ Субконто2 В ИЕРАРХИИ (&спСтатейЗатратИсключений)
                  |                        ИНАЧЕ ИСТИНА
                  |                    КОНЕЦ,
15 Документовед
 
20.07.21
07:09
+ можно проще:  Организация = &Организация или не &ЕстьОрганизация

Но так хуже читается
16 Адинэснег
 
20.07.21
07:11
(14)(15) главное -  вовремя
17 Малыш Джон
 
20.07.21
07:15
(0) Или, как выше советуют, делать составное условие,

Или в тексте запроса поставить "ГДЕ &МоеУсловие", а потом в коде ТекстЗапроса = СтрЗаменить(ТекстЗапроса,"&МоеУсловие", "...то условие которое нужно...")

Плюс второго способа, что условие запроса получается проще и в конструкторе такой текст запроса тоже открывается.
18 golem14
 
20.07.21
07:36
(6) Запрос как объект это таки интересно, буду пробовать, а говорят ещё что язык 1С не объектный :-)
В типовой ERP вижу много мест где это используется, но похоже кроме писателей типовых это никому не сдалось и только запутывает.
19 golem14
 
20.07.21
07:44
схема запроса это просто
https://infostart.ru/upload/iblock/89a/shema_m.jpg
20 TormozIT
 
гуру
20.07.21
08:32
Олды в доме. Они приносят древнюю магию.
Построитель запроса для таких целей оптимален.

Допустим есть запрос

выбрать т.Регистратор из РегистрБухгалтерии.Хозрасчетный.ДвиженияССубконто как т
ГДЕ 12 <> т.ВидСубконтоДт2

И надо условно добавить условие
т.Сумма > 100

Делай
выбрать т.Регистратор из РегистрБухгалтерии.Хозрасчетный.ДвиженияССубконто как т
ГДЕ 12 <> т.ВидСубконтоДт2
{ГДЕ
    (т.Сумма > 100) КАК ТолькоБольшиеСуммы
}

Дальше в настройках построителя условно добавляешь отбор по полю ТолькоБольшиеСуммы

построитель = Новый ПостроительЗапроса;
построитель.Текст =
"выбрать т.Регистратор из РегистрБухгалтерии.Хозрасчетный.ДвиженияССубконто как т
|ГДЕ 12 <> т.ВидСубконтоДт2
|{ГДЕ
|    (т.Сумма > 100) КАК ТолькоБольшиеСуммы
|}";
построитель.ЗаполнитьНастройки();
Если 1=1 Тогда
    построитель.Отбор.Добавить("ТолькоБольшиеСуммы").Установить(Истина);
КонецЕсли;
Запрос = построитель.ПолучитьЗапрос();

и при добавленном элементе отбора получаешь запрос

ВЫБРАТЬ
    т.Регистратор КАК Регистратор
ИЗ
    РегистрБухгалтерии.Хозрасчетный.ДвиженияССубконто КАК т
ГДЕ
    12 <> т.ВидСубконтоДт2
    И т.Сумма > 100 = &Параметр1
https://i.imgur.com/pG91Urp.png

а без добавленного элемента отбора получаешь запрос

ВЫБРАТЬ
    т.Регистратор КАК Регистратор
ИЗ
    РегистрБухгалтерии.Хозрасчетный.ДвиженияССубконто КАК т
ГДЕ
    12 <> т.ВидСубконтоДт2
https://i.imgur.com/DlnlR6M.png
21 TormozIT
 
гуру
20.07.21
08:41
(20) Компоновка отработает по той же схеме и более современна, но потребует больше писать кода.
22 TormozIT
 
гуру
20.07.21
08:44
(20) Такой подход правда годится только для условий в верхней группе "И".
23 TormozIT
 
гуру
20.07.21
09:08
А самым универсальным подходом конечно является СтрЗаменить(). Вставляем в запрос нейтральный уникальный фрагмент в группу условий и к нему привязываем условные вставки динамических фрагментов
Например для группы "И" можно применять фрагмент - {И "ТочкаВставкиИ1" = "ТочкаВставкиИ1"}, а для группы "ИЛИ" - {ИЛИ "ТочкаВставкиИ1" = 0}.
При этом для повышения надежности вставки контролируем наличие опорного фрагмента.

Текст = "выбрать т.Регистратор из РегистрБухгалтерии.Хозрасчетный.ДвиженияССубконто как т
|ГДЕ 12 <> т.ВидСубконтоДт2 Или ""ТочкаВставкиИЛИ1"" = 0 ИЛИ (11 <> т.ВидСубконтоДт2 И ""ТочкаВставкиИ1"" = ""ТочкаВставкиИ1"")";
Текст = ирОбщий.СтрЗаменитьЛкс(Текст, """ТочкаВставкиИЛИ1"" = 0", " ИЛИ Т.Сумма > 100", Истина);
Текст = ирОбщий.СтрЗаменитьЛкс(Текст, """ТочкаВставкиИ1"" = ""ТочкаВставкиИ1""", " И Т.Сумма > 200", Истина);

Функция СтрЗаменитьЛкс(Знач ГдеЗаменять, Знач ЧтоЗаменять, Знач НаЧтоЗаменять, ОставитьЧтоЗаменять = Ложь, ВыброситьИсключениеПриОтсутствии = Истина) Экспорт
    
    Если ВыброситьИсключениеПриОтсутствии И Найти(ГдеЗаменять, ЧтоЗаменять) < 1 Тогда
        ВызватьИсключение "Шаблонная строка """ + ЧтоЗаменять + """ не найдена в тексте";
    КонецЕсли;
    Если ОставитьЧтоЗаменять Тогда
        НаЧтоЗаменять = ЧтоЗаменять + НаЧтоЗаменять;
    КонецЕсли;
    Результат = СтрЗаменить(ГдеЗаменять, ЧтоЗаменять, НаЧтоЗаменять);
    Возврат Результат;

КонецФункции
24 TormozIT
 
гуру
20.07.21
09:09
(23) Ошибся. Надо
для группы "ИЛИ" - {ИЛИ "ТочкаВставкиИЛИ1" = 0}
25 Документовед
 
20.07.21
09:28
(23)

Почему вместо "{ИЛИ "ТочкаВставкиИ1" = 0}"

не вставить: "ИЛИ &ТочкаВставкиИ1"

А потом уже  Текст = ирОбщий.СтрЗаменитьЛкс(Текст, "&ТочкаВставкиИ1", " ИЛИ Т.Сумма > 100", Истина);

Не так вырвиглазно выглядит.
26 TormozIT
 
гуру
20.07.21
09:31
(25) Тогда придется в запросе еще устанавливать служебные параметры "ТочкаВставки*" с правильными значениями Истина/Ложь. Дело вкуса.
27 Галахад
 
гуру
20.07.21
09:34
(23) А что за постфик "Лкс"?
28 TormozIT
 
гуру
20.07.21
09:35
(27) "Лучший Код Старыха"
29 Галахад
 
гуру
20.07.21
09:39
(28) :-)
30 Cyberhawk
 
20.07.21
09:50
(26) В варианте из (25) в запросе не остается служебных параметров, поэтому их устанавливать не требуется
31 1CnikPetya
 
20.07.21
09:50
Мне нравится такой вариант, его и применяю:

Запрос.Текст = "ВЫБРАТЬ
...
ИЗ
Таблица
ГДЕ
&УсловиеНаВлюту";

Потом уже постобработка по тексту:

Если НуженОтборПоВалюте Тогда
СтрЗаменить(ТекстЗапроса, "&УсловиеНаВлюту", "Таблилца.Валюта = &Рубль");
Запрос.УстановитьЗначениеПараметра("Рубль", Рубль);
Иначе
СтрЗаменить(ТекстЗапроса, "&УсловиеНаВлюту", "ИСТИНА");
КонецЕсли;

В итоге запрос открывается конструктором, хорошо читаем, не передаются лишние параметры и не пишутся лишние условия.
32 TormozIT
 
гуру
20.07.21
09:57
(30) Не понял тебя. Замена же выполняется условно, т.е. может не применяться.
33 ManyakRus
 
20.07.21
09:58
(31) Текст запроса должен быть такой чтоб его легко можно было скопировать в консоль запросов.
Такой код ужасный для консоли отчётов.
Надо писать комментарии в запросе а потом заменять комментарий на текст (и не пользоваться конструктором никогда)
34 TormozIT
 
гуру
20.07.21
10:00
(33) Условие можно быть полностью динамическое, т.е. заранее не известна строка, на которую заменять будем.
35 TormozIT
 
гуру
20.07.21
10:01
(33) Ну и запрет использования конструктора - сразу минус 5 к универсальности.
36 arsik
 
гуру
20.07.21
10:02
(31) Так же делаю.
37 1CnikPetya
 
20.07.21
10:05
(33) Конструктором пользуюсь, чтобы накидать основу запроса и проверить его синтаксис. Мне не нравится форматирование конструктора, но понимаю тех, кто им пользуется. Так же удобно смотреть структуру запросов на несколько экранов.

По подстановке параметров (34) правильно сказал. А в моем варианте можно этот параметр поставить ИСТИНА и будет в консоли вариант без его учета. А дальше уже крути от потребностей.
38 TormozIT
 
гуру
20.07.21
10:05
(31) Опасность тут в том, что потом можно дописать к этому условию " ИЛИ Сумма = 0" и тогда работать итоговое условие будет не так, как ожидалось. Поэтому надо в имени точки привязки лучше обозначать ее тип (Истина/Ложь/И/Или).
39 1CnikPetya
 
20.07.21
10:16
(38) Имеешь ввиду

"ГДЕ
&УсловиеНаВлюту
ИЛИ Сумма = 0"

или

СтрЗаменить(ТекстЗапроса, "&УсловиеНаВлюту", "Таблилца.Валюта = &Рубль ИЛИ Сумма = 0")?

Немного не понимаю, в чем риск.
40 TormozIT
 
гуру
20.07.21
10:20
(39) Текст = "... ГДЕ &УсловиеНаВлюту ИЛИ Сумма = 0"
СтрЗаменить(ТекстЗапроса, "&УсловиеНаВлюту", "ИСТИНА");
41 1CnikPetya
 
20.07.21
10:28
(40) Ну, вот тут я не согласен. Просто по тексту запроса получается вполне явно: условие на валюту проверяем при ненулевой сумме документа. А какое условие на валюту - это уже отдельный вопрос.
42 DeeK
 
20.07.21
12:07
если запрос простой и нужно маленький кусочек в нем динамически вставить то проблем с отладкой не будет, а когда по 30 временных таблиц, то юзаю менеджер, там все тоже можно удобно посмотреть
43 SiAl-chel
 
20.07.21
14:44
(2) Лучше через ИЛИ, читается легче.
&Рубли = НЕОПРЕДЕЛЕНО ИЛИ Документ.Валюта = &Рубли
44 Документовед
 
20.07.21
16:02
(43) откуда там «неопределено»  там будет пустая ссылка на справочник.
45 Документовед
 
20.07.21
16:03
(43) читается проще через условие
46 Вафель
 
20.07.21
16:07
Пиши не + ДоУсловие +, а &ДопУсловие
А остальное все так же
47 OldCondom
 
20.07.21
16:15
(46) + 100. Также использую &ТекстФильтра.
48 Кирпич
 
20.07.21
16:15
Так пишу

ТекстЗапроса = "ВЫБРАТЬ %1 ИЗ Справочник.Номенклатура ГДЕ %2";

Поля = "Наименование, Код";
Условие = "Код = 123";

Запрос.Текст = СтрШаблон(ТекстЗапроса, Поля, Условие);
49 АнализДанных
 
21.07.21
10:14
(0) (20) Мне в таких ситуациях тоже нравится использовать построитель запроса. В этом случае можно использовать конструктор запросов, код более понятный становится. Ниже пример процедуры, которая сама формирует текст запроса.

ТекстЗапроса = "ВЫБРАТЬ
               |    Номенклатура.Ссылка КАК Ссылка
               |ИЗ
               |    Справочник.Номенклатура КАК Номенклатура
               |ГДЕ
               |    Номенклатура.Ссылка <> &ИсключаемаяНоменклатура
               |{ГДЕ
               |    Номенклатура.СтавкаНДС.* КАК СтавкаНДС,
               |    Номенклатура.Производитель.*,
               |    Номенклатура.Наименование}";

ДинамическиеОтборы = Новый Структура;

Если ИспользоватьОтбор_СтавкаНДС Тогда
        
    ПараметрыОтбора = Новый Структура;
    ПараметрыОтбора.Вставить("ВидСравнения", ВидСравнения.ВСписке);
    ПараметрыОтбора.Вставить("Значение",      СписокСтавокНДС);
    
    ДинамическиеОтборы.Вставить("СтавкаНДС", ПараметрыОтбора);    

КонецЕсли;

Если ИспользоватьОтбор_Производитель Тогда
    ДинамическиеОтборы.Вставить("Производитель", Производитель);
КонецЕсли;

Если ИспользоватьОтбор_Наименование Тогда
    
    ПараметрыОтбора = Новый Структура;
    ПараметрыОтбора.Вставить("ВидСравнения", ВидСравнения.НеСодержит);
    ПараметрыОтбора.Вставить("Значение",      "Поддон");

    ДинамическиеОтборы.Вставить("Наименование", ПараметрыОтбора);
    
КонецЕсли;

ФиксированныеПараметры = Новый Структура;
ФиксированныеПараметры.Вставить("ИсключаемаяНоменклатура", ИсключаемаяНоменклатура);

Запрос = СформироватьЗапросПоДинамическимУсловиям(ТекстЗапроса, ДинамическиеОтборы, ФиксированныеПараметры);




// Создает объект "запрос", используя расширение языка запроса
//
// Параметры:
//  ТекстЗапроса             - Строка         - Текст запроса, в котором может содержаться расширение языка запроса
//  ДинамическиеПараметры    - Структура     - Значение необязательных параметров запроса, где:
//    * Ключ     - Строка - Имя параметра из расширения языка запросов
//    * Значение - произвольное значение параметра или Структура, где:
//      * ВидСравнения - ВидСравнения - содержит вид сравнения
//      * Значение     - произвольное значение параметра
//  ФиксированныеПараметры - Структура      - Значение обязательных параметров запроса, где:
//    * Ключ     - Строка - Содержит имя параметра запроса
//    * Значение - Произвольное - Значение параметра
//
// Возвращаемое значение:
//   Запрос - Объект "Запрос" - Запрос с установленными параметрами и текстом запроса.
//
Функция СформироватьЗапросПоДинамическимУсловиям(ТекстЗапроса, Знач ДинамическиеПараметры = Неопределено, Знач ФиксированныеПараметры = Неопределено) Экспорт
    
    Если ДинамическиеПараметры = Неопределено Тогда
        ДинамическиеПараметры = Новый Структура;
    КонецЕсли;
    
    Если ФиксированныеПараметры = Неопределено Тогда
        ФиксированныеПараметры = Новый Структура;
    КонецЕсли;
    
    ПостроительЗапроса = Новый ПостроительЗапроса;
    ПостроительЗапроса.Текст = ТекстЗапроса;
    
    Для Каждого КлючИЗначение Из ФиксированныеПараметры Цикл
        ПостроительЗапроса.Параметры.Вставить(КлючИЗначение.Ключ, КлючИЗначение.Значение);
    КонецЦикла;
    
    ТипыСКоллекциями = Новый Массив;
    ТипыСКоллекциями.Добавить(Тип("Массив"));
    ТипыСКоллекциями.Добавить(Тип("СписокЗначений"));
    
    Для Каждого КлючИЗначение Из ДинамическиеПараметры Цикл
        
        ЭлОтбора = ПостроительЗапроса.Отбор.Добавить(КлючИЗначение.Ключ);
        ЭлОтбора.Использование = Истина;
        
        Тип_ЗначениеОтбора = ТипЗнч(КлючИЗначение.Значение);        
        
        Если Тип_ЗначениеОтбора = Тип("Структура") Тогда
            
            ПараметрыЭлОтбора = КлючИЗначение.Значение;
            
            ЭлОтбора.ВидСравнения = ПараметрыЭлОтбора.ВидСравнения;
            ЭлОтбора.Значение = ПараметрыЭлОтбора.Значение;
            
        Иначе
            
            ЗначениеОтбора = КлючИЗначение.Значение;
            
            Если ТипыСКоллекциями.Найти(Тип_ЗначениеОтбора)<>Неопределено Тогда    
                ЭлОтбора.ВидСравнения = ВидСравнения.ВСписке;                
            КонецЕсли;
            
            Если Тип_ЗначениеОтбора = Тип("Массив") Тогда
                ЗначениеОтбора = Новый СписокЗначений;
                ЗначениеОтбора.ЗагрузитьЗначения(КлючИЗначение.Значение);
            КонецЕсли;
            
            ЭлОтбора.Значение = ЗначениеОтбора;
            
        КонецЕсли;                      
        
    КонецЦикла;
    
    Запрос = ПостроительЗапроса.ПолучитьЗапрос();
    
    Возврат Запрос;
    
КонецФункции
Основная теорема систематики: Новые системы плодят новые проблемы.