Работа с запросами

Печать (Ctrl+P)

Типичные случаи программной модификации текста запроса

Изменение имени поля выборки или таблицы

Неправильно

ТекстЗапроса = "ВЫБРАТЬ
| Номенклатура.Наименование  КАК Наименование ,
| Номенклатура. " + ИмяПоляКод + " КАК КодАртикул
|ИЗ
| Справочник.Номенклатура КАК Номенклатура";

Правильно

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

или аналогично для имени таблицы

ТекстЗапроса = "ВЫБРАТЬ
| ТаблицаСправочника.Наименование  КАК Наименование,
| ТаблицаСправочника.Код  КАК Код 
|ИЗ
| &ТаблицаСправочника КАК ТаблицаСправочника";
ТекстЗапроса = СтрЗаменить(ТекстЗапроса , "&ТаблицаСправочника", "Справочник." + ИмяСправочника);

или еще один вариант для имени таблицы

 ТекстЗапроса = "ВЫБРАТЬ
| Номенклатура.Наименование  КАК НаименованиеТовара ,
| ЕСТЬNULL(ТаблицаОстатков.ВНаличииОстаток,0) КАК ОстатокТовара
|ИЗ
| Справочник.Номенклатура КАК Номенклатура
| ЛЕВОЕ СОЕДИНЕНИЕ #ТаблицаОстатков КАК ТаблицаОстатков
| ПО Номенклатура.Ссылка= ТаблицаОстатков.Номенклатура";

Если ИспользуетсяАдресноеХранение Тогда
 ТекстЗапроса = СтрЗаменить(ТекстЗапроса , "#ТаблицаОстатков", "РегистрНакопления.ТоварыВЯчейках.Остатки");
Иначе
 ТекстЗапроса = СтрЗаменить(ТекстЗапроса , "#ТаблицаОстатков", "РегистрНакопления.ТоварыНаСкладах.Остатки");
КонецЕсли;

Конкатенация нескольких текстов запросов в пакет

Неправильно

ТекстЗапроса = " ";
Если ИспользоватьУпаковки Тогда
ТекстЗапроса =
"ВЫБРАТЬ
| Упаковки.Ссылка КАК Ссылка
|ИЗ
| Справочник.Упаковки КАК Упаковки;
|/////////////////////////////////////////////////////////////
|";
КонецЕсли;
ТекстЗапроса = ТекстЗапроса +
"ВЫБРАТЬ
| Номенклатура.Ссылка КАК Ссылка
|ИЗ
| Справочник. Номенклатура КАК Номенклатура";

Правильно

ТекстЗапроса = " ";
Если ИспользоватьУпаковки Тогда
ТекстЗапроса =
"ВЫБРАТЬ
| Упаковки.Ссылка КАК Ссылка
|ИЗ
| Справочник.Упаковки КАК Упаковки";
ТекстЗапроса = ТекстЗапроса +
"
|;
|/////////////////////////////////////////////////////////////
|";
КонецЕсли;
ТекстЗапроса = ТекстЗапроса +
"ВЫБРАТЬ
| Номенклатура.Ссылка КАК Ссылка
|ИЗ
| Справочник.Номенклатура КАК Номенклатура";

Или

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

Многократное выполнение однотипных запросов

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

Правильно:

// БанкиДляОбработки - содержит массив банков, счета в которых необходимо обработать 

ОбщийЗапрос = Новый Запрос(" 
  |ВЫБРАТЬ 
  | БанковскиеСчета.Ссылка КАК Счет 
  |ИЗ 
  | Справочник.БанковскиеСчета КАК БанковскиеСчета 
  |ГДЕ 
  | БанковскиеСчета.Банк В(&БанкиДляОбработки)"); 

ОбщийЗапрос.УстановитьПараметр("БанкиДляОбработки", БанкиДляОбработки); 
ВыборкаСчетов = ОбщийЗапрос.Выполнить().Выбрать(); 
Пока ВыборкаСчетов.Следующий() Цикл 
  ОбработатьСчетаВБанке(ВыборкаСчетов.Счет); 
КонецЦикла;

Неправильно:

// БанкиДляОбработки - содержит массив банков, счета в которых необходимо обработать 

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

Для каждого Банк Из БанкиДляОбработки Цикл 
  ЧастныйЗапрос.УстановитьПараметр("Банк", Банк); 
  ВыборкаСчетов = ЧастныйЗапрос.Выполнить().Выбрать(); 
  Пока ВыборкаСчетов.Следующий() Цикл 
    ОбработатьСчетаВБанке(ВыборкаСчетов.Счет); 
  КонецЦикла; 
КонецЦикла;

Проверка на пустой результат выполнения запроса

1. Проверку того, что результат выполнения запроса не содержит строк следует выполнять с помощью метода Пустой. Поскольку на получение выборки из результата запроса (выгрузка его в таблицу значений) будет затрачиваться дополнительное время. 

Неправильно:

Выборка = Запрос.Выполнить().Выбрать(); 
Если Выборка.Следующий() Тогда 
  Возврат Истина; 
Иначе 
  Возврат Ложь; 
КонецЕсли;

Правильно:

Вврат НЕ Запрос.Выполнить().Пустой()

2. В то же время если требуется выбрать (или выгрузить) результат запроса, то предварительный вызов метода Пустой не требуется.
Например, вместо:


РезультатЗапроса = Запрос.Выполнить(); 
Если НЕ РезультатЗапроса.Пустой() Тогда // избыточный вызов
  Выборка = РезультатЗапроса.Выбрать(); 
  Пока Выборка.Следующий() Цикл
........

  правильно:

Выборка = Запрос.Выполнить().Выбрать(); 
Пока Выборка.Следующий() Цикл
...

Ограничение на использование конструкции “ПОЛНОЕ ВНЕШНЕЕ СОЕДИНЕНИЕ” в запросах

1.1. При разработке текстов запросов следует иметь в виду, что при работе в клиент-серверном варианте, когда в качестве СУБД используется PostgreSQL, производительность выполнения запросов с конструкцией ПОЛНОЕ ВНЕШНЕЕ СОЕДИНЕНИЕ значительно снижается. В особенности это касается случаев, когда в запросе встречаются две и более таких конструкций.Поэтому в общем случае не рекомендуется использовать конструкцию ПОЛНОЕ ВНЕШНЕЕ СОЕДИНЕНИЕ в запросах. И в тех случаях, где это возможно, рекомендуется переписать текст исходного запроса без использования этой конструкции.Например, следующий запрос:

 ВЫБРАТЬ
 ЕСТЬNULL(ПланПродаж.Номенклатура, ФактическиеПродажи.Номенклатура) КАК Номенклатура,
 ЕСТЬNULL(ПланПродаж.Сумма, 0) КАК СуммаПлан,
 ЕСТЬNULL(ФактическиеПродажи.Сумма, 0) КАК СуммаФакт
ИЗ
 ПланПродаж КАК ПланПродаж
  ПОЛНОЕ СОЕДИНЕНИЕ ФактическиеПродажи КАК ФактическиеПродажи
  ПО ПланПродаж.Номенклатура = ФактическиеПродажи.Номенклатура

Может быть реализован без конструкции  ПОЛНОЕ [ВНЕШНЕЕ] СОЕДИНЕНИЕ следующим образом

ВЫБРАТЬ
 ПланФактПродаж.Номенклатура КАК Номенклатура,
 СУММА(ПланФактПродаж.СуммаПлан) КАК СуммаПлан,
 СУММА(ПланФактПродаж.СуммаФакт) КАК СуммаФакт
ИЗ
 (ВЫБРАТЬ
  ПланПродаж.Номенклатура КАК Номенклатура,
  ПланПродаж.Сумма КАК СуммаПлан,
  0 КАК СуммаФакт
 ИЗ
  ПланПродаж КАК ПланПродаж
  ОБЪЕДИНИТЬ ВСЕ
  ВЫБРАТЬ
  ФактическиеПродажи.Номенклатура,
  0,
  ФактическиеПродажи.Сумма
 ИЗ
  ФактическиеПродажи КАК ФактическиеПродажи) КАК ПланФактПродажСГРУППИРОВАТЬ ПО
 ПланФактПродаж.Номенклатура

1.2. Исключение составляют случаи, когда текст исходного запроса не может быть переписан без использования конструкции ПОЛНОЕ ВНЕШНЕЕ СОЕДИНЕНИЕ по объективным причинам. Следует иметь в виду, что при выполнении данной конструкции на СУБД PostgreSQL она автоматически заменяется платформой 1С:Предприятие на эквивалентную, которая может быть исполнена в СУБД PostgreSQL. При этом сохраняются все атрибуты запроса, такие как модификаторы ПЕРВЫЕРАЗЛИЧНЫЕ, а также УПОРЯДОЧИТЬ ПО. В таких случаях не следует “механически” заменять конструкцию ПОЛНОЕ ВНЕШНЕЕ СОЕДИНЕНИЕ только с той целью, чтобы от нее избавиться в тексте запроса.

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

Правильно:

2. Не допускается одновременно использовать конструкцию ПОЛНОЕ СОЕДИНЕНИЕ и обращение к табличным частям из раздела ВЫБРАТЬ.

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

Использование ключевых слов “ОБЪЕДИНИТЬ” и “ОБЪЕДИНИТЬ ВСЕ” в запросах

В общем случае, при объединении в запросе результатов нескольких запросов следует использовать конструкцию ОБЪЕДИНИТЬ ВСЕ, а не ОБЪЕДИНИТЬ. Поскольку во втором варианте, при объединении запросов полностью одинаковые строки заменяются одной, на что затрачивается дополнительное время, даже в случаях, когда одинаковых строк в запросах заведомо быть не может.

ВЫБРАТЬ 
ПоступлениеТоваровУслуг.Ссылка 
ИЗ 
Документ.ПоступлениеТоваровУслуг КАК ПоступлениеТоваровУслуг 
ОБЪЕДИНИТЬ ВСЕ 
ВЫБРАТЬ 
РеализацияТоваровУслуг.Ссылка 
ИЗ 
Документ.РеализацияТоваровУслуг КАК РеализацияТоваровУслуг

Неправильно:

ВЫБРАТЬ 
ПоступлениеТоваровУслуг.Ссылка 
ИЗ 
Документ.ПоступлениеТоваровУслуг КАК ПоступлениеТоваровУслуг 
ОБЪЕДИНИТЬ 
ВЫБРАТЬ 
РеализацияТоваровУслуг.Ссылка 
ИЗ 
Документ.РеализацияТоваровУслуг КАК РеализацияТоваровУслуг

Упорядочивание результатов запроса

1.1. Если алгоритм обработки результатов запроса зависит от порядка записей в запросе или если результат обработки запроса в той или иной форме представляется пользователю, то в тексте запроса следует использовать предложение УПОРЯДОЧИТЬ ПО. В отсутствие выражения УПОРЯДОЧИТЬ ПО невозможно сделать никаких предположений о том, в каком порядке будут представлены записи в результатах запроса.

Типичные примеры проблем, которые могут возникать (даже при работе на одной и той же СУБД в непредсказуемые моменты времени):

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

Вероятность возникновения разных результатов при выполнении одинаковых действий повышается 

  • при переносе информационной базы на другую СУБД
  • при смене версии СУБД
  • при изменении параметров СУБД

* Примечание: упорядочивание результатов запросов, по которым формируются движения, оправдано только в том случае, если упорядочивание является частью алгоритма формирования движений (например, списание остатков партий товаров по FIFO). В остальных случаях упорядочивать записи не следует, так как дополнительное упорядочивание будет создавать избыточную нагрузку на СУБД.

1.2. При сортировке по полю запроса, которое может потенциально содержать NULL, следует учитывать, что в разных СУБД порядок сортировки по этому полю может отличаться.

Неправильно:

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

Правильно:

ВЫБРАТЬ
  СправочникНоменклатура.Ссылка КАК НоменклатураСсылка,
  ЕСТЬNULL(ЗапасыОстатки.КоличествоОстаток, 0) КАК КоличествоОстаток
ИЗ
  Справочник.Номенклатура КАК СправочникНоменклатура
    ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.Запасы.Остатки КАК ЗапасыОстатки
    ПО (ЗапасыОстатки.Номенклатура = СправочникНоменклатура.Ссылка)
УПОРЯДОЧИТЬ ПО
  КоличествоОстаток

1.3. Если результаты запроса должны тем или иным образом отображаться пользователю, то

  • упорядочивать результаты таких запросов необходимо по полям примитивных типов;
  • упорядочивание по полям ссылочных типов нужно заменять на упорядочивание по строковым представлениям этих полей.

В противном случае порядок следования строк будет выглядеть для пользователя случайным (необъяснимым).

1.4. Отсутствие предложения УПОРЯДОЧИТЬ ПО оправдано только в тех случаях, когда

  • алгоритм обработки результатов запроса не рассчитывает на определенный порядок записей
  • результат обработки выполненного запроса не показывается пользователю
  • результат запроса – заведомо одна запись

В таких случаях рекомендуется не добавлять предложение УПОРЯДОЧИТЬ ПО в текст запроса, так как это приводит к дополнительным затратам времени при выполнении запроса.

Совместное использование с конструкцией РАЗЛИЧНЫЕ

2. Если в запросе используется конструкция РАЗЛИЧНЫЕ, упорядочивание следует выполнять только по полям, включенным в выборку (в секции ВЫБРАТЬ). 

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

Ограничения на использование конструкции АВТОУПОРЯДОЧИВАНИЕ

3. Использование конструкции ПЕРВЫЕ совместно с конструкцией АВТОУПОРЯДОЧИВАНИЕ запрещено.

В остальных случаях конструкцию АВТОУПОРЯДОЧИВАНИЕ также не рекомендуется использовать, так как разработчик не контролирует, какие именно поля будут использованы для упорядочивания. Применение такой конструкции оправдано только в тех случаях, когда получаемый порядок записей не важен, но при этом он должен быть одинаковым в не зависимости от применяемой СУБД. 

Причины использования конструкции АВТОУПОРЯДОЧИВАНИЕ следует указывать в комментарии, размещенном непосредственно перед текстом запроса. 

Округление результатов арифметических операций в запросах

Методическая рекомендация (полезный совет)1. Если в операции деления заранее известны порядки числителя и знаменателя, то следует по возможности избегать выполнения деления числа заведомого маленького порядка на число заведомо большого порядка. Например, вместо:0.02 / 28346 * 9287492правильно:0.02 * 9287492 / 283462. При выполнении арифметических операций в запросах к базе данных платформа 1С:Предприятия поддерживает точность вычислений до 8 разрядов дробной части. Однако, из-за особенностей работы различных СУБД в некоторых ситуациях точность результатов может отличаться от 8. Более подробно о вычислении разрядности результатов можно почитать в статье ИТС Разрядность результатов выражений и агрегатных функций в языке запросов.Если точность результата выполнения запроса к базе данных, содержащегоарифметические операции деления,агрегатные функции СРЕДНЕЕ,арифметические операции умножения, если каждый из множителей может иметь дробную часть,различается на различных СУБД, то рекомендуется к операндам и/ или результатам этих операций применять оператор явного приведения разрядности и точности числовых данных:ВЫРАЗИТЬ(… КАК Число(m, n))Оператор ВЫРАЗИТЬ следует применять к операндам, если на какой-нибудь СУБД точность получаемого результата недостаточна. Например, требуется 10 разрядов после запятой, а получается 6.При этом указанная общая разрядность операндов должна быть минимальной, но не меньше той, которая достаточна для представления значений каждого из операндов. Неоправданное завышение разрядности может привести к потере точности последующих вычислений и несколько снизить скорость выполнения запроса.Важно иметь в виду, что на разных СУБД имеются различные ограничения на максимальную разрядность десятичных чисел. Самое жесткое ограничение – это 31 разряд в целой и дробной частях. Чем меньшее значение разрядности будет указано для операндов, тем выше сможет быть точность результата. Например, если в результате требуется не менее 10 разрядов дробной части, первый операнд заведомо помещается в 15 разрядов целой части, а второй операнд заведомо помещается в 5 знаков целой части, то выражение может быть записано так:ВЫБРАТЬ
ВЫРАЗИТЬ(Таблица.Множитель * Таблица.Числитель КАК Число(25,10)) / ВЫРАЗИТЬ(Таблица.Знаменатель КАК Число(15,10)) КАК Результат 
ИЗ Таблица КАК ТаблицаОператор ВЫРАЗИТЬ следует применять к результату, если точность вычислений на всех СУБД достаточна, но на некоторых она больше, а на других меньше. При этом указанная общая разрядность результата должна быть минимальной, но не меньше той, которая достаточна для представления значений результата. Если в приведенном примере известно, что Знаменатель не может быть меньше 0.00001, то для представления результата достаточно 20 разрядов целой части. В этом случае выражение может быть записано так:ВЫБРАТЬ
ВЫРАЗИТЬ(Таблица.Множитель * Таблица.Числитель / Таблица.Знаменатель КАК Число(30,10)) КАК Результат
ИЗ Таблица КАК ТаблицаИногда может быть целесообразно выполнить приведения к требуемой точности как операндов, так и результата. Например:ВЫБРАТЬ
ВЫРАЗИТЬ(ВЫРАЗИТЬ(Таблица.Множитель * Таблица.Числитель КАК Число(25,10)) / ВЫРАЗИТЬ(Таблица.Знаменатель КАК Число(15,10)) КАК Число(30,10)) КАК Результат
ИЗ Таблица КАК Таблица

Особенности использования в запросах оператора ПОДОБНО

1. При использовании в тексте запроса оператора ПОДОБНО допустимо использовать только константные строковые литералы или параметры запроса. Запрещается формировать строку шаблона при помощи вычислений, использовать конкатенацию строк средствами языка запросов. Например:

Допустимо:

Реквизит ПОДОБНО "123%"

Недопустимо:

Реквизит ПОДОБНО "123" + "%"
Реквизит ПОДОБНО Таблица.Шаблон

2. Запросы, в которых управляющие символы шаблона оператора ПОДОБНО находятся в полях запроса или в вычисляемых выражениях, по-разному интерпретируются на различных СУБД. Запрос, успешно выполняющийся, например, при работе с файловой базой, может возвращать неверные результаты при работе в режиме клиент-сервера. Подобные выражения необходимо переформулировать.

Например, вместо:

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

Необходимо использовать:

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

Данное требование продиктовано необходимостью переносимости прикладных решений на различные СУБД.

Псевдонимы источников данных в запросах

1. Псевдоним источника данных должен быть осмысленным, чтобы было понятным его назначение. Требования к псевдонимам источников схожи с требованиями к именам переменных в коде.

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

Неправильно:

ВЫБРАТЬ
  Таблица1.Ссылка КАК Товар,
  ЕстьNULL(Таблица2.КоличествоОстаток, 0) КАК Остаток
ИЗ
  Справочник.Номенклатура КАК Таблица1
    ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.ТоварыНаСкладах.Остатки КАК Таблица2
    ПО Таблица1.Ссылка = Таблица2.Номенклатура

Правильно:

ВЫБРАТЬ
  ВсяНоменклатура.Ссылка КАК Товар,
  ЕстьNULL(ОстаткиНаСкладах.КоличествоОстаток, 0) КАК Остаток
ИЗ
  Справочник.Номенклатура КАК ВсяНоменклатура
    ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.ТоварыНаСкладах.Остатки КАК ОстаткиНаСкладах
    ПО ВсяНоменклатура.Ссылка = ОстаткиНаСкладах.Номенклатура

В частности не рекомендуется использовать имена классов объектов метаданных (“Справочник”, “Документ” и т.д.), т.к. обычно такой псевдоним не будет описывать назначение источника в конкретном запросе. Кроме того, соблюдение данной рекомендации уменьшит количество ложных срабатываний при автоматизированном контроле конфигурации на наличие обращений к несуществующим в конфигурации метаданным.

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

Пример:

"ВЫБРАТЬ
  Таблица.Наименование КАК Наименование
  Таблица.Код КАК Код
ИЗ
  &Таблица КАК Таблица";

ТекстЗапроса = СтрЗаменить(ТекстЗапроса , "&Таблица", "Справочник." + ИмяСправочника);
Previous Article
Next Article

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Этот сайт использует Akismet для борьбы со спамом. Узнайте, как обрабатываются ваши данные комментариев.