IE 2016

Условные условия и запросы

Опубликовал zfilin в раздел Программирование - Практика программирования

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

Например, нужно получить список всех товаров по складу, но если в качестве склада передано пустое значение, то необходимо получить список товаров по всем складам (т.е. склад не выбран).

Как правило в таких случаях модифицируют текст запроса "на лету" примерно таким образом:


Запрос.Текст =
"ВЫБРАТЬ
|   Учет.Товар,
|   Учет.Количество
|ИЗ
|   Документ.Учет КАК Учет
|" + ?(ЗначениеЗаполнено(Склад),"ГДЕ Учет.Склад = &Склад","");

Без сомнений, такой способ имеет достоинства, но у него есть и существенный недостаток. При таком "ручном" вмешательстве в текст запроса, перестает работать очень удобный инструмент - конструктор запросов. Он просто не понимает наших "посторонних" включений. Особенно ярко это проявляется когда речь идет о "монструозных" запросах на несколько страниц. Сталкиваясь с таким великаном и обнаруживая в нем включения кода 1С, я всегда думаю такие плохие вещи, что будет неловко их тут повторять.

Однако, единственный ли это способ достичь желаемого, сделать так, чтобы склад не учитывался в отборе, если он не заполнен? Не единственный! Если немного пораскинуть мозгами очень просто перенести условную конструкцию внутрь самого запроса, например вот так:

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

Никакого волшебства, всего-лишь банальное использование оператора "ИЛИ". Если склад не заполнен то и все выражение всегда будет истинным, а значит в выборку попадут все склады.

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

Что же с производительностью? Действительно, производительность в таком случае немного падает. Я сделал небольшую конфигурацию, чтобы сделать замеры. Желающие могут скачать ее и попробовать померить производительность самостоятельно (1C 8.2.10.77).

Исходные данные: 20 документов, 7 товаров, 3 склада, ~10000 вызовов запроса (5000 с пустым и 5000 с заполненным складом).

Запрос в котором условие подставляется в текст средствами языка 1С:

SpeedMod

Как видите, 10002 запроса (строка 15) выполняется за 8,2 секунды.

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

SpeedCond

Результат (59-я строка) выполнения - 11,4 секунды. То-есть 3,2 секунды на ~10000 запросов.

Можно было бы провести замеры с вложенными запросами и соединениями или с другими объемами данных, но в целом понятно что для простых случаев потеря производительности несущественная. К тому же запросы-монстры не часто вызываются по 10000 раз за один раз.

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

 

Какой из способов использовать, конечно, решать вам.

А я хочу пожелать вам хорошего дня и хорошего кода.

Спасибо за внимание.

 

P.S.: Статья получила множество отзывов и уважаемое сообщество насоветовало еще кучу способов борьбы с условиями.

 

Уважаемый alexk-is советует использовать построитель отчета:

ПостроительОтчета.Текст =
"ВЫБРАТЬ
|   Учет.Товар,
|   Учет.Количество
|ИЗ
|   Документ.Учет КАК Учет
|{ГДЕ
|   Учет.Склад.*}"
;
ПостроительОтчета.ПолучитьЗапрос().Выполнить();

Yashazz ставит комментарии, выполняет поиск и замену в тексте запроса перед выполнением, но сокрушается, что конструктор режет комментарии:

ТекстЗапроса =
"ВЫБРАТЬ
|   Учет.Товар,
|   Учет.Количество
|ИЗ
|   Документ.Учет КАК Учет
|ГДЕ
|Склад = &УсловныйСклад
|//УсловиеНаТовар//"
;
...
СтрЗаменить(ТекстЗапроса,"//УсловиеНаТовар//","И Товар = &УсловныйТовар");

Зато Alias прекрасно развивает идею и советует делать так:

Запрос.Текст =
"ВЫБРАТЬ
| Учет.Товар,
| Учет.Количество
|ИЗ
| Документ.Учет КАК Учет
|ГДЕ
| &УсловиеСклада"
;

Запрос.Текст = СтрЗаменить(Запрос.Текст, "&УсловиеСклада",?(ЗначениеЗаполнено(ВыбСклад),"Учет.Склад = &Склад","Истина"));

Без сомнения в способе куча плюсов - и конструктор не режет ничего и запрос читается нормально и тормозов нет.

4ishиспользует выбор:

Запрос.Текст =
"ВЫБРАТЬ
| Учет.Товар,
| Учет.Количество
|ИЗ
| Документ.Учет КАК Учет
|ГДЕ
|ВЫБОР
|   КОГДА &Склад <> ЗНАЧЕНИЕ(Справочник.Склады.ПустаяСсылка)
|       ТОГДА Учет.Склад = &Склад
|   ИНАЧЕ ИСТИНА
|КОНЕЦ"
;

Тоже хороший способ.

А Vit aka proger изящно применяет "в иерархии":

Запрос.Текст =
"ВЫБРАТЬ
| Учет.Товар,
| Учет.Количество
|ИЗ
| Документ.Учет КАК Учет
|ГДЕ
| Учет.Склад в иерархии( &Склад))"
;

Serj1С иногда использует:

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

 

Всем спасибо за замечательные подсказки, я обязательно возьму кое-что себе на вооружение.

Ну, и, конечно обсуждение еще продолжается.

 

Оригинал в блоге автора

Файлы

Наименование Файл Версия Размер Кол. Скачив.
УсловияИЗапросы
.zip 22,93Kb
19.10.10
132
.zip 22,93Kb 132 Скачать

См. также

Лучшие комментарии

16. Minotavrik 20.10.2010 10:51
Есть хороший способ отлаживать большие и страшные, текст которых изменен в конфигураторе различными операторами.

Я делаю так:

Нахожу строчку Запрос.выполнить(). Ставлю точку останова и перехожу в отладку. Когда точка срабатывает, делаю следующее:
Нажимаю на кнопку "Вычислить выражение";
в поле пишу Запрос.Текст (если через построитель то ПостроительОтчета.ПолучитьЗапрос().Текст);
Копирую текст запроса и отлаживаю его в консоли.
Ответили: (19) (21) (22)
# Ответить
1. alexk-is 19.10.2010 05:27
Может так?

ПостроительОтчета.Текст =
"ВЫБРАТЬ
| Учет.Товар,
| Учет.Количество
|ИЗ
| Документ.Учет КАК Учет
|{ГДЕ
| Учет.Склад.*}"
;
ПостроительОтчета.ПолучитьЗапрос()).Выполнить();


Посмотреть как это работает, ну, и другие варианты оптимизации запросов можно здесь http://www.infostart.ru/public/69707/

И еще "Учет.Склад.Ссылка = " плохое условие, правильнее будет "Учет.Склад = "
Ответили: (2) (5) (8) (9) (30)
# Ответить
15. Alias 19.10.2010 17:27
(6) А я пишу так. Конструктор отрабатывает без проблем, ничего не теряется... и сама строка "&УсловиеСклада" выглядит понятнее чем какие-то сложные условия. И выполнение запроса (это важно!) при этом не тормозит. И конструктор ничего не режет. Короче, сплошные плюсы :)

Запрос.Текст =
"ВЫБРАТЬ
| Учет.Товар,
| Учет.Количество
|ИЗ
| Документ.Учет КАК Учет
|ГДЕ
| &УсловиеСклада";

Запрос.Текст = СтрЗаменить(Запрос.Текст, "&УсловиеСклада",?(ЗначениеЗаполнено(ВыбСклад),"Учет.Склад.Ссылка = &Склад",""));
Ответили: (18) (30)
# Ответить

Комментарии

1. alexk-is 19.10.2010 05:27
Может так?

ПостроительОтчета.Текст =
"ВЫБРАТЬ
| Учет.Товар,
| Учет.Количество
|ИЗ
| Документ.Учет КАК Учет
|{ГДЕ
| Учет.Склад.*}"
;
ПостроительОтчета.ПолучитьЗапрос()).Выполнить();


Посмотреть как это работает, ну, и другие варианты оптимизации запросов можно здесь http://www.infostart.ru/public/69707/

И еще "Учет.Склад.Ссылка = " плохое условие, правильнее будет "Учет.Склад = "
Ответили: (2) (5) (8) (9) (30)
# Ответить
2. Serj1C 19.10.2010 07:31
(1) +1 за использование построителя

(0) Прошлый век. На СКД также предлагаете мучаться?
# Ответить
3. vlengin 19.10.2010 09:24
Что значит "моструозных", может имелось ввиду "монстроозных"?
# Ответить
4. vlengin 19.10.2010 09:31
Точнее "монструозных".
Ответили: (5)
# Ответить
5. zfilin 19.10.2010 10:09
(4) Ага. Точно!

(1) Насчет "Учет.Склад.Ссылка = " согласен, это я "очепятался". И спасибо, что предложили еще более совершенный способ достигнуть требуемого результата. Правда, я не совсем понял при чем тут ваш замечательны журнал, но видимо какая-то связь есть...
# Ответить
6. Yashazz 19.10.2010 10:13
Я в таких случаях пишу комментарии в тексте запроса.
Например
|ГДЕ
|Склад = &УсловныйСклад
|//УсловиеНаТовар//";
и потом просто СтрЗаменить(ТекстЗапроса,"//УсловиеНаТовар//","И Товар = &УсловныйТовар")

Конечно, конструктор режет комментарии, но хоть прочитать запрос при этом может.
Ответили: (8) (52)
# Ответить
7. 4ish 19.10.2010 10:41
Еще как вариант:

|ГДЕ
|ВЫБОР
|КОГДА &Склад <> ЗНАЧЕНИЕ(Справочник.Склады.ПустаяСсылка)
|ТОГДА ПоступлениеТоваровУслугТовары.Ссылка.Склад = &Склад
|ИНАЧЕ ИСТИНА
|КОНЕЦ
Ответили: (8) (11)
+ 1 [ zfilin; ]
# Ответить
8. zfilin 19.10.2010 10:55
(7) Точно! =)

(6) Да, жаль что режет, так тоже способ ничего.

(1) А! Спасибо, уже оценил!
Ответили: (9)
# Ответить
9. alexk-is 19.10.2010 11:05
(8) По ссылке в (1) используется много разных запросов. Мой любимый по структуре подчиненности документов.
Ответили: (10)
# Ответить
10. zfilin 19.10.2010 11:11
(9) Ага, вот смотрю как раз. Круто, че сказать.
# Ответить
11. artbear 19.10.2010 13:39
По опыту скажу:
1. Построитель не всегда удобен :(
2. использование как (0), так и (7) не всегда удобно.
Лично я чаще юзаю сравнение не с ПустаяСсылка, а с NULL.
# Ответить
12. artbear 19.10.2010 13:49
(0) ОФФ Увидел в твоем блоге заметки про тестирование.
По опыту скажу: Сценарное тестирование долго, неудобно, негибко :(
Посмотри
Юниттестирование на восьмерке (готовый набор для тестирования, у меня постоянно в работе) http://www.1cpp.ru/forum/YaBB.pl?num=1267016427/94#94
Тестирование разработок на платформе 1С. Управление данными http://www.1cpp.ru/forum/YaBB.pl?num=1273213867/35#35 (это схемы работы с тестовыми данными и обсуждение разных схем)
.
Также можешь посмотреть мою разработку
Повышение удобства разработки в среде 1С http://infostart.ru/public/65526/
есть спец.раздел Тестирование
Ответили: (13)
# Ответить
13. zfilin 19.10.2010 14:04
(12) О! Спасибо, тестирование меня очень интересует, обязательно посмотрю.
# Ответить
14. Vit aka proger 19.10.2010 16:34
а я обычно пишу так:
Запрос.Текст =
"ВЫБРАТЬ
| Учет.Товар,
| Учет.Количество
|ИЗ
| Документ.Учет КАК Учет
|ГДЕ
| Учет.Склад в иерархии( &Склад))";
Если склад пустой, выбирается по всем имеющимся складам



Хотя я обычно делаю запрос по регистрам
|ИЗ РегистрНакопления.ТоварыНаСкладах.Остатки(&КонПериода, Склад в иерархии(&Склад))
Ответили: (30)
+ 3 [ happy_saint; zfilin; gaglo; ]
# Ответить
15. Alias 19.10.2010 17:27
(6) А я пишу так. Конструктор отрабатывает без проблем, ничего не теряется... и сама строка "&УсловиеСклада" выглядит понятнее чем какие-то сложные условия. И выполнение запроса (это важно!) при этом не тормозит. И конструктор ничего не режет. Короче, сплошные плюсы :)

Запрос.Текст =
"ВЫБРАТЬ
| Учет.Товар,
| Учет.Количество
|ИЗ
| Документ.Учет КАК Учет
|ГДЕ
| &УсловиеСклада";

Запрос.Текст = СтрЗаменить(Запрос.Текст, "&УсловиеСклада",?(ЗначениеЗаполнено(ВыбСклад),"Учет.Склад.Ссылка = &Склад",""));
Ответили: (18) (30)
# Ответить
16. Minotavrik 20.10.2010 10:51
Есть хороший способ отлаживать большие и страшные, текст которых изменен в конфигураторе различными операторами.

Я делаю так:

Нахожу строчку Запрос.выполнить(). Ставлю точку останова и перехожу в отладку. Когда точка срабатывает, делаю следующее:
Нажимаю на кнопку "Вычислить выражение";
в поле пишу Запрос.Текст (если через построитель то ПостроительОтчета.ПолучитьЗапрос().Текст);
Копирую текст запроса и отлаживаю его в консоли.
Ответили: (19) (21) (22)
# Ответить
17. zfilin 20.10.2010 14:13
О! Спасибо всем, сколько способов!
Нужно обязательно будет включить их в текст самой статьи.
# Ответить
18. gaglo 20.10.2010 14:16
(15) Тут не понял: если "&УсловиеСклада" заменить на "", то получится запрос
"ВЫБРАТЬ
...
|ГДЕ ";
- но ведь он синтаксически неверен?

Я пишу почти так же, только вместо "ГДЕ &УсловиеСклада" ставлю "ГДЕ Истина".
Выглядит не так уж понятно, и наводит на не те мысли (сравни с "Где справедливость?")
Зато можно выполнять и без всяких СтрЗаменить...
Ответили: (23)
+ 1 [ Alias; ]
# Ответить
19. zfilin 20.10.2010 14:32
(16) Спасибо за подсказку, я тоже использую такой способ для отладки. =)
Ответили: (22)
# Ответить
20. mst 20.10.2010 14:55
а я в 7ке пишу не "=" а "в" и работает независимо выбран элемент или нет... никогда не писал =, потому что при "в" в запрос попадают еще и элементы из подгрупп выбранной группы справочника.
# Ответить
21. I_G_O_R 20.10.2010 22:44
(16) Вы наверное большие запросы не видели, в ЗУПе они почему-то не помещаются :cry:
Ответили: (22)
# Ответить
22. artbear 21.10.2010 07:13
(21) Все помещается, нужно только включить выражение с текстом в табло просмотра, далее щелкнуть на тексте, и нажать лупу. откроется окошко для просмотра текста, откуда и можно скопировать текст.

(16) (19) Копирование текста запроса вручную неудобно, т.к. параметры придется самому ставить :(
лучше пользоваться спец.консолями, которые могут отлаживать сам запрос.
В итоге в отладчике вычисляешь код Отладить(Запрос) и в режиме Предприятия открывается консоль с полным запросом (текст, параметры, временные таблицы и т.д.)
Посмотрите мою разработку http://infostart.ru/public/65526/
В ней я описал различные фичи, в т.ч. и мощнейшие консоли.
Ответили: (28)
# Ответить
23. Alias 21.10.2010 11:54
(18) Ой, конечно, Вы абсолютно правы! Поспешил с написанием комментария. У меня просто обычно этот приём используется как часть сложного условия (то есть, например, условие на Организацию есть всегда). Тогда пустой строки никак не бывает.

В простом же случае можно писать либо "ИСТИНА ИЛИ &УсловиеСклада", либо в СтрЗаменить() включать строку с указанием ГДЕ ("ГДЕ Учет.Склад.Ссылка = &Склад")
А в комментарии смешал оба этих случая. :) спасибо что указали на неточность.

Выбор варианта зависит от удобства в конкретном случае.
# Ответить
24. Lapitskiy 22.10.2010 14:16
с выводами по скорости не согласен, если выполнять запросы в цикле, выборка идет из кэша! Надо не запрос в цикле делать, а 1 запрос по большой базе.
Ответили: (25)
# Ответить
25. zfilin 22.10.2010 14:24
(24) Согласен, я для этого и приложил конфу, чтобы можно было по-разному попробовать.
# Ответить
26. rasswet 22.10.2010 16:53
в если из ГДЕ Учет.Склад.Ссылка убрать ссылку?
Ответили: (27)
# Ответить
27. zfilin 22.10.2010 18:30
(26) Про ссылку еще в самом начале говорили, она там случайно оказалась.
Наверное, надо подредаткировать...
# Ответить
28. I_G_O_R 22.10.2010 22:58
(22) я именно так и смотрю, просто в ЗУПе есть такие большие запросы что в этом окне только часть текста (например текст запроса расчета НДФЛ, в нем около 5000 строк, а помещается где-то 3000 с лишним).
# Ответить
29. Yashazz 25.10.2010 15:00
Способ Alias'a опасен тем, что при достаточно сложной логике условия есть риск запутаться и налажать. Простыми "истина" и "ложь" тоже можно напутать - поставить, например, "Истина" в условие "И", а потом поменять где-то что-то на "Или", условие-то большое, и получить ошибку.
Ответили: (31)
# Ответить
30. Serj1C 26.10.2010 09:08
(14) "в иерархии" работает медленно!

мне больше нравится (1) и (15)
# Ответить
31. Alias 26.10.2010 09:24
(29) Не согласен. Разбивание большого и сложного условия на несколько маленьких наоборот, упростит понимание условия! Сравните, например, один из предложенных вариантов:

|ВЫБОР
| КОГДА &Склад <> ЗНАЧЕНИЕ(Справочник.Склады.ПустаяСсылка)
| ТОГДА Учет.Склад = &Склад
| ИНАЧЕ ИСТИНА
|КОНЕЦ И
|ВЫБОР
| КОГДА &Организация <> ЗНАЧЕНИЕ(Справочник.Организации.ПустаяСсылка)
| ТОГДА Учет.Организация = &Организация
| ИНАЧЕ ИСТИНА
|КОНЕЦ

и то что предлагаю я:

|&СкладПодходит И &ОрганизацияПодходит

Что из этого проще? :)
Ваш довод работает против Вас -- так как в сложном условии как раз-таки проще запутаться, чем в условии, разбитом на простые блоки.
Ответили: (32)
# Ответить
32. Serj1C 27.10.2010 09:39
Вместо (31) я использую иногда:

|ГДЕ
| &Склад В (Выборка.Склад, ЗНАЧЕНИЕ(Справочник.Склады.ПустаяСсылка))
+ 1 [ Robus; ]
# Ответить
33. romansun 21.02.2011 15:05
(0) добавлю свои пять копеек. Похоже на уже описанные тут варианты..

довольно стандартная реализация чекбокса в запросе:

|ГДЕ (&флПДК = ложь ИЛИ (&флПДК = истина И ДокументРасчетов.ПризнакДополнительногоКонтроля = истина))


вместо динамических запросов использую часто также СтрЗаменить() через примерно такие конструкции:

|ГДЕ Истина
|//секцияКонтрагент И Контрагент = &Контрагент
|//секцияДоговор И Договор = &Договор
|//секцияДокументРасчетов И ДокументРасчетов = &ДокументРасчетов

Конструктор, конечно, срубит ремарку, но я им практически не пользуюсь. Только при первоначальном написании в консоле запросов, чтоб имена реквизитов он мне все вытащил :).
+ 1 [ Новиков; ]
# Ответить
34. max082 18.10.2011 12:57
Мне лично еще нравится следующая конструкция:

|
|Где &ВсеСклады ИЛИ Документ.Склад = &Склад
|
Ответили: (35)
# Ответить
35. zfilin 19.10.2011 21:50
(34) max082, Тоже неплохо, а &ВсеСклады это что?
# Ответить
37. Altair777 07.08.2012 14:31
Имхо, лучше все-таки модифицировать текст запроса по условию в коде.
Кстати, во всех примерах опущена установка параметров для запроса. Вот маленький пример как у меня это все объединено:

Запрос = Новый Запрос;
Запрос.Текст = "ВЫБРАТЬ
| ДоговорыКонтрагентов.ОсновнойПроект КАК ОсновнойПроект,
| ДоговорыКонтрагентов.Организация КАК Организация,
| ДоговорыКонтрагентов.Владелец КАК Арендодатель,
| ДоговорыКонтрагентов.Номер КАК НомерОсновной,
| ДоговорыКонтрагентов.Дата КАК ДатаОсновной,
| ДоговорыКонтрагентов.СуммаПлатежей КАК СуммаПлатежейОсновной,
| ДоговорыКонтрагентов.Ссылка КАК Ссылка
|ИЗ
| Справочник.ДоговорыКонтрагентов КАК ДоговорыКонтрагентов
|ГДЕ
| НЕ ДоговорыКонтрагентов.ПометкаУдаления
| И НЕ ДоговорыКонтрагентов.Ссылка В (&МассивОтобранных)
| И НЕ ДоговорыКонтрагентов.ДоговорОснование В (&МассивОтобранных)
| И ДоговорыКонтрагентов.ВидВзаиморасчетов = &ВидВзаиморасчетов
| И ДоговорыКонтрагентов.Дата МЕЖДУ &НачалоПериода И &КонецПериода
| И ДоговорыКонтрагентов.ВидДоговора = &ВидДоговора"
;

Если
ФильтрПоСрокам Тогда
Запрос.Параметры.Вставить("НачалоПериода", НачалоДня(НачалоПериода));
Запрос.Параметры.Вставить("КонецПериода", КонецДня(КонецПериода));
Иначе
Запрос.Текст = СтрЗаменить(Запрос.Текст, "И ДоговорыКонтрагентов.Дата МЕЖДУ &НачалоПериода И &КонецПериода", "");
КонецЕсли;
Запрос.Параметры.Вставить("МассивОтобранных", МассивОтобранных);
Запрос.Параметры.Вставить("ВидДоговора", ВидДоговора);
Запрос.Параметры.Вставить("ВидВзаиморасчетов", ВидВзаиморасчетов);
ТаблЗапроса2 = Запрос.Выполнить().Выгрузить();
# Ответить
38. zfilin 07.08.2012 15:15
Да, я тоже пользуюсь модификацией текста запроса.
Но я все же применил бы параметр &УсловиеПоДатеДоговора, который бы в зависимости от ситуации менял бы на строку "ДоговорыКонтрагентов.Дата МЕЖДУ &НачалоПериода И &КонецПериода" или на "Истина".

Так в конструкторе запроса, я увижу что у меня есть какое-то условие, которое в последствии будет определяться в коде модуля. А если просто убирать строчку "И ДоговорыКонтрагентов.Дата МЕЖДУ &НачалоПериода И &КонецПериода", то про то, что она в последствии может исчезнуть во время отладки запроса очень просто забыть. И думать потом - вот у меня же четко стоит отбор по датам. Почему ж оно не отбирает-то?
Ответили: (39) (41) (42)
# Ответить
39. Altair777 07.08.2012 15:31
(38) zfilin, а текст кода нормально виден? У меня что-то нет :)

P.S. Вопрос снят. Разобрался.
# Ответить
40. AlexO 07.08.2012 15:35
Непонятны восторги.
Ну да, хорошо, собрал в одном месте варианты проверок (да и то не все), - но не систематизированные, без описания применимости и раскрытия смысла.
Есть масса способов сделать условие в запросе.
Их уже множество тут накидали.
1С наделала столько всего, что оно и не нужно так много. Достаточно было сделать одно - но путное и быстрое.
Можно и ВЫБОР...КОГДА, можно и через параметр &Параметр, можно и заменой текста запроса перед выполнением.
ПостроительОтчета для выполнения запроса используют только тру-1сники.
А все же посыл статьи не раскрыт: без динамического формирования запросов во многих случаях не обойтись никак, ничем это не заменишь, и никаких инструментов в 1С для отладки нет.
# Ответить
42. Altair777 07.08.2012 15:37
(38) zfilin,

> И думать потом - вот у меня же четко стоит отбор по датам. Почему ж оно не отбирает-то?

Если это сделать системой, то думать не придется.
Логика простая - если есть параметр запроса, значит он должен заполняться.
А раз он заполняется, то есть код его заполнения.
И в том же самом месте происходит и модификация текста запроса.

Плюс немного экономии - раз параметр не используется, то зачем его вставлять?

ОФФ: А вообще, при отладке очень сложных запросов, текст которых может модифицироваться несколько раз и в нескольких разных местах, лучше в отладчике отловить окончательный текст прямо на стоке Запрос.Выполнить()
Ответили: (43) (46)
# Ответить
43. zfilin 07.08.2012 17:26
(42) Altair777, Ага. Ну, с этой позиции да, полностью согласен.
Но я-то исходил из того, что код могут смотреть и другие люди, которые могут не знать о такой системе и воспринимать выражение "ДоговорыКонтрагентов.Дата МЕЖДУ &НачалоПериода И &КонецПериода" однозначно - есть такое условие, полагая, что заполнение параметров это... Просто заполнение параметров! =) И там только обычное заполнение дат!
А одиночным параметром мы однозначно заставляем того, кто читает код, проверить что за условие скрывается за параметром. Естественно, к имени параметра тот кто будет писать запрос, должен выставлять требования сходные с требованиям к именованию функций. Имя этого параметра должно отражать суть условия.

Собственно, это на самом деле уже детали, и дело вкуса. Кому-то кажется понятнее одно, кому-то другое. Суть одна - модификация текста запроса.
Ответили: (44)
+ 1 [ Altair777; ]
# Ответить
44. Altair777 07.08.2012 17:49
(43) zfilin,

> Ну, с этой позиции да, полностью согласен.
Спасибо :)

Такой подход дает 2 неоспоримых преимущества - возможность использовать конструктор и ускорение выполнения запроса.

P.S. Видел я и второй подход - по условию добавлять строки в текст запроса. Но это гораздо затратнее.
Ответили: (45)
# Ответить
45. zfilin 07.08.2012 17:59
(44) Altair777, Может я не совсем понятно выразился. Сейчас покажу на вашем коде:

Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ДоговорыКонтрагентов.ОсновнойПроект КАК ОсновнойПроект,
| ДоговорыКонтрагентов.Организация КАК Организация,
| ДоговорыКонтрагентов.Владелец КАК Арендодатель,
| ДоговорыКонтрагентов.Номер КАК НомерОсновной,
| ДоговорыКонтрагентов.Дата КАК ДатаОсновной,
| ДоговорыКонтрагентов.СуммаПлатежей КАК СуммаПлатежейОсновной,
| ДоговорыКонтрагентов.Ссылка КАК Ссылка
|ИЗ
| Справочник.ДоговорыКонтрагентов КАК ДоговорыКонтрагентов
|ГДЕ
| НЕ ДоговорыКонтрагентов.ПометкаУдаления
| И НЕ ДоговорыКонтрагентов.Ссылка В (&МассивОтобранных)
| И НЕ ДоговорыКонтрагентов.ДоговорОснование В (&МассивОтобранных)
| И ДоговорыКонтрагентов.ВидВзаиморасчетов = &ВидВзаиморасчетов
| И &ФильтрПоСрокам
| И ДоговорыКонтрагентов.ВидДоговора = &ВидДоговора"
;

Если
ФильтрПоСрокам Тогда
Запрос.Текст = СтрЗаменить(Запрос.Текст, "&ФильтрПоСрокам", "ДоговорыКонтрагентов.Дата МЕЖДУ &НачалоПериода И &КонецПериода");
Запрос.Параметры.Вставить("НачалоПериода", НачалоДня(НачалоПериода));
Запрос.Параметры.Вставить("КонецПериода", КонецДня(КонецПериода));
Иначе
Запрос.Текст = СтрЗаменить(Запрос.Текст, "&ФильтрПоСрокам", "Истина");
КонецЕсли;
Запрос.Параметры.Вставить("МассивОтобранных", МассивОтобранных);
Запрос.Параметры.Вставить("ВидДоговора", ВидДоговора);
Запрос.Параметры.Вставить("ВидВзаиморасчетов", ВидВзаиморасчетов);
ТаблЗапроса2 = Запрос.Выполнить().Выгрузить();


Чем же оно гораздо затратнее получается, может, я не заметил чего?.. =(
Ответили: (47) (49)
# Ответить
46. AlexO 07.08.2012 18:22
(42) Altair777,
лучше в отладчике отловить окончательный текст ....

оо, выдал все профессиональные тайны ... :(
Ответили: (48)
# Ответить
47. Altair777 07.08.2012 18:29
(45) zfilin,
как-то так :)

Запрос = Новый Запрос;
Запрос.Текст = "ВЫБРАТЬ
| ДоговорыКонтрагентов.ОсновнойПроект КАК ОсновнойПроект,
| ДоговорыКонтрагентов.Организация КАК Организация,
| ДоговорыКонтрагентов.Владелец КАК Арендодатель,
| ДоговорыКонтрагентов.Номер КАК НомерОсновной,
| ДоговорыКонтрагентов.Дата КАК ДатаОсновной,
| ДоговорыКонтрагентов.СуммаПлатежей КАК СуммаПлатежейОсновной,
| ДоговорыКонтрагентов.Ссылка КАК Ссылка
|ИЗ
| Справочник.ДоговорыКонтрагентов КАК ДоговорыКонтрагентов
|ГДЕ
| НЕ ДоговорыКонтрагентов.ПометкаУдаления
| И НЕ ДоговорыКонтрагентов.Ссылка В ИЕРАРХИИ (&МассивОтобранных)
| И НЕ ДоговорыКонтрагентов.ДоговорОснование В ИЕРАРХИИ (&МассивОтобранных)
| И ДоговорыКонтрагентов.ВидВзаиморасчетов = &ВидВзаиморасчетов
| И ДоговорыКонтрагентов.ВидДоговора = &ВидДоговора"
;

Если
ФильтрПоСрокам Тогда
Запрос.Текст = Запрос.Текст + "
| И ДоговорыКонтрагентов.Дата МЕЖДУ &НачалоПериода И &КонецПериода"
;
Запрос.Параметры.Вставить("НачалоПериода", НачалоДня(НачалоПериода));
Запрос.Параметры.Вставить("КонецПериода", КонецДня(КонецПериода));
КонецЕсли;

Запрос.Параметры.Вставить("МассивОтобранных", МассивОтобранных);
Запрос.Параметры.Вставить("ВидДоговора", ВидДоговора);
Запрос.Параметры.Вставить("ВидВзаиморасчетов", ВидВзаиморасчетов);
ТаблЗапроса2 = Запрос.Выполнить().Выгрузить();


А если условие стоит в середине текста (вложенные запросы)? Хоть вешайся.
Ответили: (50)
# Ответить
48. Altair777 07.08.2012 18:30
(46) AlexO, да?!!! :)
Я бы мог отредактировать свой коммент чтобы не раскрывать тайну, но... все равно останется в цитате.
Ответили: (51)
# Ответить
49. Altair777 07.08.2012 18:34
(45) zfilin,

понял! А если этот текст перекинуть в консоль запросов, то как его отлаживать?
Два понятных параметра НачалоПериода И КонецПериода заменяется на нечто... совсем не понятное :)
Ответили: (50)
# Ответить
50. zfilin 07.08.2012 18:39
(47) Да, добавлением не очень удобно.
(49) Свои минусы есть. В консоли отлаживать не очень удобно, но как вы справедливо заметили для отладки лучше использовать итоговый текст из строки "Выполнить()". =) Раз уж мы тут все замешаны в выдаче страшных секретов. =)))
Ответили: (51)
# Ответить
51. AlexO 08.08.2012 10:13
(50) zfilin,
вся проблема - даже не в получить окончательный текст запроса (хотя он и будет в каждом другом случае - разный), а собрать размазанные параметры, чтобы воспроизвести в консоли именно текущий запрос.
Это проблема проблем :)
Я решаю совсем уж оригинальным способом, здесь не указанным.
(48) Altair777,
я отредактировал цитату, теперь ваша очередь :)
но вдруг уже попала в поисковую базу яндекса?!
# Ответить
52. ArtemiFD 03.03.2013 22:27
(6) Yashazz, так же пользуюсь заменой условия, но предпочитаю использовать сравнения одинаковых цифр или символов.

Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
 |   Учет.Товар,
 |   Учет.Количество
 |ИЗ
 |   Документ.Учет КАК Учет
 |ГДЕ
 | 1=1 
 | И 2=2";
СтрЗаменить(Запрос.Текст,"1=1","Товар = &УсловныйТовар");
...Показать Скрыть
Ответили: (53)
+ 2 [ N_aix; kastortroy2006; ]
# Ответить
53. Yashazz 03.03.2013 23:25
(52) Красиво! Спасибо за идею. В случае 666=666 вероятность совпадения практически нулевая, и читаться конструктором будет в большем количестве случаев. :)
# Ответить
54. ta44ik 22.05.2013 07:10
Еще необходима статья как заменить &ПустаяСсылка на ЗНАЧЕНИЕ(Документ.ПустаяСсылка) И &ПустаяДата например на Год(&Дата)=1(есть варианты.)
# Ответить
55. ekaruk 13.10.2014 13:26
Могу предложить еще вариант

СхемаЗапроса = Новый СхемаЗапроса;
СхемаЗапроса.УстановитьТекстЗапроса(Запрос.Текст);
СхемаЗапроса.ПакетЗапросов[0].Операторы[0].Отбор.Добавить("Учет.Склад = &Склад");
Запрос.Текст = СхемаЗапроса.ПолучитьТекстЗапроса();

Подробнее тут http://infostart.ru/public/307045/
Ответили: (56)
# Ответить
56. zfilin 14.10.2014 13:10
(55) ekaruk, Тоже хорошо. Жаль, что только для новых версий.
# Ответить
57. SemenovaMarinaV 28.10.2014 11:47
Очень любопытно
# Ответить
58. _Sasha_ 15.06.2015 09:05
А я как то к циферкам в качестве базы для замены привык.


Запрос.Текст =
"ВЫБРАТЬ РАЗРЕШЕННЫЕ
| _АСИТ_РазделкаОбороты.Разделка КАК Документ,
| _АСИТ_РазделкаОбороты.Номенклатура КАК Номенклатура,
| _АСИТ_РазделкаОбороты.НоменклатураСырье КАК НоменклатураСырье,
| _АСИТ_РазделкаОбороты.КоличествоСырьеОборот КАК Приход,
| _АСИТ_РазделкаОбороты.КоличествоПФОборот КАК Выход,
| _АСИТ_РазделкаОбороты.СуммаСырьяОборот КАК СуммаПриход,
| _АСИТ_РазделкаОбороты.СуммаПФОборот,
| _АСИТ_РазделкаОбороты.КоличествоПотериОборот КАК КоличествоПотери,
| _АСИТ_РазделкаОбороты.Потери КАК НормаПотерь
|ИЗ
| РегистрНакопления._АСИТ_Разделка.Обороты(
| &НачалоПериода,
| &КонецПериода,
| Авто,
| 1 = 1
| И 2 = 2
| И 3 = 3
| И 4 = 4) КАК _АСИТ_РазделкаОбороты
|
|УПОРЯДОЧИТЬ ПО
| Документ,
| НоменклатураСырье,
| Номенклатура
|АВТОУПОРЯДОЧИВАНИЕ";

Если ЗначениеЗаполнено(ПараметрыОтчета.Номенклатура) Тогда
Если ПараметрыОтчета.Номенклатура.ЭтоГруппа Тогда
Запрос.текст = СтрЗаменить(Запрос.Текст,"1 = 1", "Номенклатура В Иерархии(&Номенклатура)");
ОбластьМакетаШапкаНомер.Параметры.Номенклатура = "В группе " + СокрЛП(ПараметрыОтчета.Номенклатура);
Иначе
Запрос.текст = СтрЗаменить(Запрос.Текст,"1 = 1", "Номенклатура = &Номенклатура");
ОбластьМакетаШапкаНомер.Параметры.Номенклатура = ПараметрыОтчета.Номенклатура;
КонецЕсли;
Запрос.УстановитьПараметр("Номенклатура", ПараметрыОтчета.Номенклатура);

Иначе
ОбластьМакетаШапкаНомер.Параметры.Номенклатура = "По всем полуфабрикатам";
КонецЕсли;
Если ЗначениеЗаполнено(ПараметрыОтчета.НоменклатураСырье) Тогда
Если ПараметрыОтчета.НоменклатураСырье.ЭтоГруппа Тогда
Запрос.текст = СтрЗаменить(Запрос.Текст,"2 = 2", "НоменклатураСырье В Иерархии(&НоменклатураСырье)");
ОбластьМакетаШапкаНомер.Параметры.НоменклатураСырье = "В группе " + СокрЛП(ПараметрыОтчета.НоменклатураСырье);
Иначе
Запрос.текст = СтрЗаменить(Запрос.Текст,"2 = 2", "НоменклатураСырье = &НоменклатураСырье");
ОбластьМакетаШапкаНомер.Параметры.НоменклатураСырье = ПараметрыОтчета.НоменклатураСырье;
КонецЕсли;
Запрос.УстановитьПараметр("НоменклатураСырье", ПараметрыОтчета.НоменклатураСырье);

Иначе
ОбластьМакетаШапкаНомер.Параметры.НоменклатураСырье = "По всем полуфабрикатам";
КонецЕсли;
Если ЗначениеЗаполнено(ПараметрыОтчета.ЦехПроизводства) Тогда
Запрос.текст = СтрЗаменить(Запрос.Текст,"3 = 3", "ЦехПроизводства = &ЦехПроизводства");
ОбластьМакетаШапкаНомер.Параметры.ЦехПроизводства = ПараметрыОтчета.ЦехПроизводства;
Запрос.УстановитьПараметр("ЦехПроизводства", ПараметрыОтчета.ЦехПроизводства);
Иначе
ОбластьМакетаШапкаНомер.Параметры.ЦехПроизводства = "";
КонецЕсли;
Ответили: (59)
# Ответить
59. zfilin 17.06.2015 17:49
(58) _Sasha_, Циферки чем не удобно. Тем, что сидя в конструкторе запроса не понятно что за 1=1, что за 2=2. Надо идти смотреть в код.
Заменяемый параметр типа &УсловиеСклада более "говорящее" название. Можно писать что угодно, хоть &ТутСложноеУсловиеГдеПроверяетсяВходящиеНаВхождениеАИсходящи­еНаИсхождение. Синтаксису не противоречит, перед выполнением все-равно будет заменено и иллюстрирует о чем же условие.

Но и циферками, конечно тоже можно.
# Ответить
60. okulus 23.10.2015 09:43
Подскажите, как в СКД сделать условное условие "МЕЖДУ &НачалоПериода И &КонецПериода"?
# Ответить
Внимание! За постинг в данном форуме $m не начисляются.
Внимание! Для написания сообщения необходимо авторизоваться
Текст сообщения*
Прикрепить файл






IE 2016