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

Список - неотъемлемый атрибут отображения информации в любой конфигурации, созданной на платформе "1С:Предприятие 8.1". Для эффективной работы со списками, содержащими разнообразные данные, в программах на платформе "1С:Предприятие 8.1" реализованы удобные и мощные механизмы отбора и сортировки. Об особенностях их использования рассказывает В.В. Рыбалка, фирма "1С".


Рис. 1

Списки

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

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

Рис. 1

Механизм сортировки

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

Во-вторых, в платформе "1С:Предприятие 8.1" активно используется механизм быстрого поиска. Этот механизм позволяет быстро найти в каком-либо списке нужный элемент, набрав первые символы (рис. 2). Но в динамических списках (например, список элементов справочника или список документов) быстрый поиск работает только по реквизитам, по которым доступна сортировка.

Рис. 2

Посмотреть все доступные для сортировки реквизиты списка можно, открыв окно "Отбор и сортировка". Это окно, как правило, доступно на панели действий (рис. 3) либо в контекстном меню списка, открывающемся правой кнопкой мыши (рис. 4). В окне "Отбор и сортировка" нужно перейти на закладку "Сортировка", где показаны все доступные реквизиты, по которым возможна сортировка.

Рис. 3

Рис. 4

На рисунке 3 видно, что для списка документов "Реализации товаров и услуг" доступна сортировка по двум реквизитам: "Дата" и "Номер". Однако информативность окна сортировок этим не ограничивается. Здесь можно посмотреть, какая сортировка включена в данный момент (левая часть окна) и список всех доступных для сортировки реквизитов (правая часть). Тут же можно настроить нужную сортировку и ее порядок. Обратите внимание: текущий реквизит сортировки будет помечен в списке специальным символом - стрелочкой, обозначающей направление сортировки. Три примера различной сортировки (в т. ч. комбинированной) и способы ее отображения в списке показаны на рисунке 5.

Рис. 5

Заметим, что нижний пример иллюстрирует возможность использования комбинированной сортировки (одновременно по нескольким реквизитам). В нашем случае, это сортировка по дате по убыванию (самые старые даты внизу) и по номерам по возрастанию (самые большие номера внизу).

В каждом списке можно индивидуально сохранить нужную сортировку. Достаточно включить галочку "Использовать эту настройку сортировки при открытии" и нажать "ОК". Система запомнит настройку и при следующем открытии этого списка установит сохраненную сортировку.

Быстро отсортировать список по нужному реквизиту можно, щелкнув мышкой по шапке с названием этого реквизита.

Например, в нашем случае, можно щелкнуть по реквизиту "Дата" (включится сортировка дат по возрастанию, и можно будет использовать быстрый поиск по дате) или по реквизиту "Номер" (будет переключена сортировка по номерам по возрастанию, после чего можно быстро искать по номеру). Инвертировать сортировку тоже просто - достаточно повторно щелкнуть по тому же реквизиту в шапке списка.

Механизм отбора

Отбор - мощный механизм платформы "1С:Предприятие 8.1", который позволяет эффективно работать со списками, даже если в них содержится не один десяток или сотня тысяч элементов. Для начала рассмотрим работу механизма отбора в общем случае.

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

Список возможных условий для того или иного вида отбора зависит от типа элементов, используемых в нем. Например, для чисел и дат будет доступно указание диапазонов, для строк - поиск подстроки (условия "Содержит"/"Не содержит"), а для элементов справочников - заполнение списков и анализ иерархии.

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

Механизмы отбора и сортировки на примерах

Попробуем решить несколько задач в демонстрационной базе ("Бухгалтерия предприятия", редакция 1.6). Например, отобразим документы, сформированные для контрагента "Саймон и Шустер ООО" в журнале "Документы покупателей". Сразу оговоримся, что описывать будем стандартные для платформы "1С:Предприятие 8.1" правила и логику ведения отбора, без привязки к какой-либо конкретной конфигурации и дополнительным сервисным возможностям, в ней реализованным.

Итак, открываем журнал документов "Документы покупателей". В стандартном состоянии без включенного отбора на экран выводятся все документы всех покупателей (даже в демонстрационной базе это занимает не одну страницу).

Нам нужно быстро посмотреть все документы контрагента "Саймон и Шустер ООО". Реализуется задача следующим образом - открывается окно отбора, в элементе "Контрагент" выбирается контрагент "Саймон и Шустер ООО" из справочника (рис. 6) и нажимается "ОК". Задача решена (рис. 7).

Рис. 6

Рис. 7

Для быстрого использования нужного отбора достаточно сразу приступать к выбору нужного критерия. Ставить галочку напротив используемого отбора не нужно. Программа сделает это сама после того, как будет указан необходимый критерий. Быстро применить настроенные критерии отбора можно, нажав комбинацию клавиш Ctrl+Enter*.

Обратите внимание еще и на то, что при указании значений в элементах отбора (в нашем примере - контрагент "Саймон и Шустер ООО"), в большинстве случаев будет работать механизм быстрого подбора, широко распространенный в платформе "1С:Предприятие 8.1". В нашем примере достаточно было набрать первые символы названия контрагента или его код прямо в поле значения отбора, нажать Enter или Tab и система автоматически бы "угадала" нужный нам элемент справочника.

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

Теперь отобразим список номенклатуры, в наименованиях которых содержится слово "Чайник". Для этого открываем справочник "Номенклатура", вызываем окно отбора, в элементе "Наименование" выбираем условие сравнения "Содержит" и указываем требуемое слово (рис. 8).

Рис. 8

Вид сравнения "Содержит" выбран не случайно. Именно он позволяет найти нужное слово (или его часть) в любом месте наименования номенклатуры. Если оставить вид сравнения "Равно", в списке будут отображены только такие элементы номенклатуры, которые называются точно так, как написан запрос. А таких в нашей демобазе нет (то есть не было бы отображено ни одного элемента).

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

Если искать не по наименованию, а по полному наименованию, галочку использования отбора по наименованию лучше снять. Иначе отбор будет использован и по наименованию, и по полному наименованию, что не всегда может оказаться необходимым (рис. 9).

Рис. 9

Для удобства работы с элементами справочника при использовании отборов лучше на время отключать отображение иерархии (рис. 10).

Рис. 10

В качестве третьей задачи просмотрим в журнале документов "Документы покупателей" только документы "Реализация товаров и услуг". Решение этой задачи продемонстрирует особенность одного из видов отбора, доступного только в журналах документов.

Открываем журнал "Документы покупателей" и указываем в элементе отбора "Вид документа" документ "Реализация товаров и услуг". Программа сама предоставляет возможность выбора определенного вида документа из тех, которые включены в данный журнал. Для этого есть и персональная кнопочка на панели действий (рис. 11).

Рис. 11

Аналогично отбору по виду документов платформа автоматически предложит элемент отбора "Структура подчиненности", если в конфигурации настроены взаимосвязи между документами.

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

У задачи существует несколько способов реализации. Рассмотрим наиболее эффективный. Открываем журнал "Документы покупателей", указываем в элементе отбора "Вид документа" документ "Счет-фактура выданный". После этого в элементе отбора "Контрагент" указываем вид сравнения "В группе". Выбираем тип значения "Контрагенты" и открываем форму выбора контрагентов. В ней выбираем группу "Покупатели" (рис. 12).

Рис. 12

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

А теперь усложним задачу: просмотрим в журнале документов "Документы покупателей" только документы "Счет-фактура", но при этом нужно просмотреть документы и для покупателей, и для поставщиков. Решаем ее аналогично предыдущей, за исключением одного накладываемого критерия отбора.

Человеческим языком задача формулируется так: "отобразить все нужные документы по всем контрагентам, находящимся в группах справочника Покупатели, Поставщики, Поставщики на реализацию". Реализуется это просто - в условии отбора "Контрагент" выбираем "В группе из списка" (рис. 13). После этого становится доступным механизм заполнения списка, в который можно добавить нужные группы (или элементы) справочника. Причем список можно заполнить вручную. По аналогии с решением предыдущей задачи, найти нужную группу и выбрать ее, повторив это для каждого нового элемента списка. Однако целесообразнее воспользоваться удобным механизмом подбора, который автоматически реализуется программой. С помощью подбора намного проще и быстрее заполнить список нужными составляющими. После того, как список заполнен, нажимаем "ОК" и активируем настроенные критерии отбора. Задача решена.

Рис. 13

Отличие условия отбора "В группе из списка" от условия "В списке" заключается в том, что в первом случае условие выполнится для всех элементов справочника, которые либо явно указаны в списке, либо находятся внутри указанных в списке групп. Второй же случай просто указывает программе сверяться со списком при отборе. То есть если вы укажете там группу, то в отбор попадет сама группа (как самостоятельный элемент справочника), а элементы, которые в нее входят, критерию отбора удовлетворять не будут. Решать задачу можно было и "в лоб" - выбрать условие "В списке" и при помощи подбора добавить туда все элементы, содержащиеся в необходимых группах.

Условия отбора "Не в списке" и "Не в группе из списка" позволяют указать нужные наборы данных, которые в отбор попадать не должны. То есть решать задачу можно было бы и от обратного - указать "Не в группе из списка" и добавить туда все группы справочника, кроме трех необходимых (Покупатели, Поставщики, Поставщики на реализацию).

И, наконец, отобразим в документе "Реализация товаров и услуг" с номером ТДН00002 в табличной части только номенклатуру, содержащую в наименованиях слово "СТИНОЛ". Эта задача, позволит увидеть универсальность самого механизма отбора, а также насколько разнообразно может быть его использование. Задача основана на реальных ситуациях, когда, например, в табличной части накладной несколько сотен (а то и тысяч) строк и надо быстро проанализировать ее состав. В нашей демобазе есть документ "Реализация товаров и услуг" с номером ТДН00002, у которого в табличной части есть несколько строк. Несмотря на то что в документе кнопок использования отборов не наблюдается, вызов отбора доступен через контекстное меню (правая кнопка мыши).

Далее накладываем критерии отбора в разрезе Номенклатуры. Тут же возникает другой вопрос - как отобрать "СТИНОЛ", если условия выбора номенклатуры довольно сильно ограничены (доступно "Равно", "Не равно", "В списке" и "Не в списке"). Решить задачу можно и при таких условиях. Выбираем условие "В списке", открываем уже знакомое окно заполнения списка, используем подбор номенклатуры (рис. 14, 1). В списке номенклатуры может быть большое количество элементов, поэтому не будем искать глазами нужные позиции. Воспользуемся отбором в списке номенклатуры, указав условие отбора "Содержит" для наименования номенклатуры (рис. 14, 2).

Рис. 14

После этого остается только добавить отобранные позиции в список отбора для документа и применить критерии отбора.

Полезные функции механизма отбора

Рассмотрим еще несколько моментов, связанных так или иначе с отборами в системе "1С:Предприятие 8.1".

В списках объектов конфигурации, где используется привязка к датам (например, списки документов), и в журналах документов можно использовать быстрый отбор по диапазону дат. Для этого достаточно нажать соответствующую кнопку "Настройка периода" на панели действий (или выбрать в контекстном меню) (рис. 15). Таким способом можно в каждом списке индивидуально регулировать критерий отображения элементов по датам.

Рис. 15

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

Рис. 16

Еще одно полезное свойство механизма отборов - ведение истории отборов (рис. 17). Программа запоминает, какие отборы были установлены, поэтому можно быстро вернуться к какому-либо из них, просто выбрав его из выпадающего списка. К слову, в окне "Отбор и сортировка" обратите внимание на кнопку "Отборы" (рис. 6). Нажав на эту кнопку, вы попадете в интерфейс, в котором можно сохранять и восстанавливать настройки отборов, чтобы в последствие можно было к ним вернуться (рис. 18).

Рис. 17

Рис. 18

И последняя функция - это отмена всех отборов (рис. 19). Нажатием кнопки "Отключить отбор" отключаются все отборы, установленные в списке. Аналогичного действия можно добиться, открыв окно "Отбор и сортировка" и сняв галочки напротив всех активных элементов.

Рис. 19

В программе также есть возможность быстрого поиска по номеру документа в списках документов или в журналах. Вызывается эта возможность кнопкой "Поиск по номеру" (рис. 20) и позволяет найти нужный документ, гибко настроив параметры поиска. Найденные документы по указанным критериям отображаются в нижней части окна этого сервиса, и можно перейти к нужному документу.

Для формирования и выполнения запросов к таблицам базы данных в платформе 1С используется специальный объект языка программирования Запрос . Создается этот объект вызовом конструкции Новый Запрос . Запрос удобно использовать, когда требуется получить сложную выборку данных, сгруппированную и отсортированную необходимым образом. Классический пример применения запроса - получение сводки по состоянию регистра накопления на определенный момент времени. Так же, механизм запросов позволяет легко получать информацию в различных временных разрезах.

Текст запроса – это инструкция, в соответствии с которой должен быть выполнен запрос. В тексте запроса описывается:

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

Язык запросов платформы 1С очень похож на синтаксис других SQL-языков, но имеются отличия. Основными преимуществами встроенного языка запросов являются: разыменование полей, наличие виртуальных таблиц, удобная работа с итогами, нетипизированные поля в запросах.

  • значения перечислений;
  • предопределенные данные:
  • справочников;
  • планов видов характеристик;
  • планов счетов;
  • планов видов расчетов;
  • пустые ссылки;
  • значения точек маршрута бизнес-процессов.
Также текст запроса может содержать значения системных перечислений, которые могут быть присвоены полям в таблицах базы данных: ВидДвиженияНакопления, ВидСчета и ВидДвиженияБухгалтерии. Обращение в запросах к предопределенным данным конфигурации и значениям системных перечислений осуществляется с помощью литерала функционального типа ЗНАЧЕНИЕ . Данный литерал позволяет повысить удобочитаемость запроса и уменьшить количество параметров запроса.

Пример использования литерала ЗНАЧЕНИЕ :
ГДЕ Город = ЗНАЧЕНИЕ(Справочник.Города.Москва)
ГДЕ Город = ЗНАЧЕНИЕ(Справочник.Города.ПустаяСсылка)
ГДЕ ТипТовара = ЗНАЧЕНИЕ(Перечисление.ВидыТоваров.Услуга)
ГДЕ ВидДвижения = ЗНАЧЕНИЕ(ВидДвиженияНакопления.Приход)
ГДЕ ТочкаМаршрута = ЗНАЧЕНИЕ(БизнесПроцесс.БизнесПроцесс1.ТочкаМаршрута.Действие1

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

Автоупорядочивание работает по следующим принципам:

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

В случае, если запрос содержит предложение ИТОГИ, каждый уровень итогов упорядочивается отдельно.

3) Что бы избежать повторного запроса к базе данных при выводе результата запроса пользователю (например, построение запроса или отображение результата запроса с помощью табличного документа) полезно использовать инструкцию ПРЕДСТАВЛЕНИЕССЫЛКИ , которая позволяет получать представление ссылочного значения.

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

4) Если в запросе имеется поле с составным типом, то для таких полей возникает необходимость привести значения поля к какому-либо определенному типу с помощью инструкции ВЫРАЗИТЬ , что позволит убрать лишние таблицы из левого соединения с полем составного типа данных и ускорить выполнение запроса.

Пример:
Имеется регистра накопления ОстаткиТоваров, у которого поле Регистратор имеет составной тип. В запросе выбираются Дата и Номер документов ПоступлениеТоваров, при этом при обращении к реквизитам документа через поле Регистратор не происходит множество левых соединений таблицы регистра накопления с таблицами документов-регистраторов.

ВЫБРАТЬ
ВЫРАЗИТЬ(ОстаткиТоваров.Регистратор КАК Документ.ПоступлениеТоваров).Номер КАК НомерПоступления,
ВЫРАЗИТЬ(ОстаткиТоваров.Регистратор КАК Документ.ПоступлениеТоваров).Дата КАК ДатаПоступления
ИЗ
РегистрНакопления.ОстаткиТоваров КАК ОстаткиТоваров

Если приведение типа считается не осуществимым, то результатом приведения типа будет значение NULL.

5) Не стоит забывать про инструкцию РАЗРЕШЕННЫЕ , которая означает, что запрос выберет только те записи, на которые у текущего пользователя есть права. Если данное слово не указать, то в случае, когда запрос выберет записи, на которые у пользователя нет прав, запрос отработает с ошибкой.

6) В случае, если в запросе используется объединение, и в некоторых частях объединения присутствуют вложенные таблицы (документ с табличной частью), а в некоторых нет, возникает необходимость дополнения списка выборки полями – пустыми вложенными таблицами. Делается это при помощи ключевого слова ПУСТАЯТАБЛИЦА , после которого в скобках указываются псевдонимы полей, из которых будет состоять вложенная таблица.

Пример:
// Выбрать поля Номер и Состав
// из виртуальной таблицы Документ.РасхНакл
ВЫБРАТЬ Ссылка.Номер, ПУСТАЯТАБЛИЦА.(Ном, Тов, Кол) КАК Состав
ИЗ Документ.РасхНакл
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ Ссылка.Номер, Состав.(НомерСтроки, Товар, Количество)
ИЗ Документ.РасхНакл Документ.РасходнаяНакладная.Состав.*
7) Что бы в результат запроса не попали повторяющиеся строки, следует использовать инструкцию РАЗЛИЧНЫЕ , потому что так нагляднее и понятнее, а инструкция СГРУППИРОВАТЬ ПО применяется для группировки с помощью агрегатных функций. Ксати, при использовании агрегатных функций предложение СГРУППИРОВАТЬ ПО может быть и не указано совсем, при этом все результаты запроса будут сгруппированы в одну единственную строку.

Пример:
// Необходимо узнать, каким вообще контрагентам
// отгружался товар за период.
Выбрать Различные
Документ.РасходнаяНакладная.Контрагент

8) Инструкция СГРУППИРОВАТЬ ПО позволяет обращаться к полям верхнего уровня, без группировки результатов по этим полям, если агрегатные функции применены к полям вложенной таблицы. Хотя в справке 1С написано, при группировке результатов запроса в списке полей выборки обязательно должны быть указаны агрегатные функции, а помимо агрегатных функций в списке полей выборки допускается указывать только поля, по которым осуществляется группировка.

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

9) Инструкция ЕСТЬNULL предназначена для замены значения NULL на другое значение, но не забываем, что второй параметр будет преобразован к типу первого в случае, если тип первого параметра является строкой или числом.

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

Пример (поиск документов, содержащих в табличной части определенный товар):
ВЫБРАТЬ
Приходная.Ссылка
ИЗ
Документ.Приходная Где Приходная.Товары.Номенклатура = &Номенклатура.

Преимущество этого запроса перед запросом к подчиненной таблице Приходная.Товары в том, что если есть дубли в документах, результат запроса вернет только уникальные документы без использования ключевого слова РАЗЛИЧНЫЕ .

11) Интересный вариант оператора В - это проверка вхождения упорядоченного набора в множество таких наборов (Поле1, Поле2, ... , ПолеN) В (Поле1, Поле2, ... , ПолеN).

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

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

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

  • Все виртуальные таблицы параметризованы, т. е. разработчику предоставляется возможность задать некоторые параметры, которые система будет использовать при формировании запроса создания виртуальной таблицы. В зависимости от того, какие параметры виртуальной таблицы указаны разработчиком, система может формировать РАЗЛИЧНЫЕ запросы для получения одной и той же виртуальной таблицы, причем они будут оптимизированы с точки зрения переданных параметров.
  • Не всегда разработчик имеет возможность получить доступ к тем данным, к которым имеет доступ система.
13) В клиент-серверном варианте работы функция ПОДСТРОКА() реализуется при помощи функции SUBSTRING() соответствующего оператора SQL, передаваемого серверу баз данных SQL Server, который вычисляет тип результата функции SUBSTRING() по сложным правилам в зависимости от типа и значений ее параметров, а так же в зависимости от контекста, в котором она используется. В большинстве случаев эти правила не оказывают влияния на выполнение запроса, но бывают случаи, когда для выполнения запроса существенна максимальная длина строки результата, вычисленная SQL Server. Важно иметь в виду, что в некоторых контекстах использования функции ПОДСТРОКА() максимальная длина ее результата может оказаться равной максимальной длине строки ограниченной длины, которая в SQL Server равна 4000 символам. Это может привести к неожиданному аварийному завершению выполнения запроса:
Microsoft OLE DB Provider for SQL Server: Warning: The query processor could not produce a query plan from the optimizer because the total length of all the columns in the GROUP BY or ORDER BY clause exceeds 8000 bytes.
HRESULT=80040E14, SQLSTATE=42000, native=8618
Чтобы избежать такой ошибки, не рекомендуют использовать функцию ПОДСТРОКА() с целью приведения строк неограниченной длины к строкам ограниченной длины. Вместо нее лучше использовать операцию приведения типа ВЫРАЗИТЬ().

14) С осторожностью используйте ИЛИ в конструкции ГДЕ, так как использование условия с ИЛИ может значительно "утяжелить" запрос. Решить проблему можно конструкцией ОБЪЕДИНИТЬ ВСЕ.

Пример:
ВЫБРАТЬ

ИЗ

ГДЕ
_ДемоКонтрагенты.Ссылка = &Ссылка1

ОБЪЕДИНИТЬ ВСЕ

ВЫБРАТЬ
_ДемоКонтрагенты.НаименованиеПолное
ИЗ
Справочник._ДемоКонтрагенты КАК _ДемоКонтрагенты
ГДЕ
_ДемоКонтрагенты.Ссылка = &Ссылка2

15) Условие НЕ В в конструкции ГДЕ увеличивает время исполнения запроса, так как это своего рода НЕ (ИЛИ1 ИЛИ2 ... ИЛИn), поэтому для больших таблиц старайтесь использовать ЛЕВОЕ СОЕДИНЕНИЕ с условием ЕСТЬ NULL.

Пример:
ВЫБРАТЬ
_ДемоКонтрагенты.Ссылка
ИЗ
Справочник._ДемоКонтрагенты КАК _ДемоКонтрагенты
ЛЕВОЕ СОЕДИНЕНИЕ Документ._ДемоЗаказПокупателя КАК _ДемоЗаказПокупателя
ПО _ДемоКонтрагенты.Ссылка = _ДемоЗаказПокупателя.Контрагент
ГДЕ
_ДемоЗаказПокупателя.Контрагент ЕСТЬ NULL

15) При использовании Временных таблиц нужно индексировать поля условий и соединений в этих таблицах, НО, при использовании индексов запрос может выполняться еще медленнее. Поэтому необходимо анализировать каждый запрос с применением индекса и без, замерять скорость выполнения запроса и принимать окончательное решение.
Если вы помещаете во временную таблицу данные, которые изначально индексированы по некоторым полям, то во временной таблице индекса по этим полям уже не будет.

16) Если вы не используете Менеджер временных таблиц , то явно удалять временную таблицу не требуется, она будет удалена после завершения выполнения пакетного запроса, иначе следует удалить временную таблицу одним из способов: командой УНИЧТОЖИТЬ в запросе, вызвать метод МенеджерВременныхТаблиц.Закрыть().

/// определенным полям в 1с 8.3, 8.2 &НаСервере Процедура КакУпорядочитьРезультатЗапросаПоПолямНаСервере() // Чтобы сортировать строки в результате запроса // используется секция УПОРЯДОЧИТЬ ПО. // Требуется вывести продукты, упорядоченные // сначала по возрастанию цвета, а затем // по убыванию калорийности. Запрос = Новый Запрос( "ВЫБРАТЬ | Наименование, | Цвет, | Калорийность |ИЗ | Справочник.Номенклатура |УПОРЯДОЧИТЬ ПО | Цвет ВОЗР, | Калорийность УБЫВ" /// Как упорядочить результат запроса по /// выражению в 1с 8.3, 8.2 &НаСервере Процедура КакУпорядочитьРезультатЗапросаПоВыражениюНаСервере() // В секции УПОРЯДОЧИТЬ ПО можно использовать // выражения. // Например, упорядочим продукты по // максимальному содержанию белков и углеводов // вместе. Запрос = Новый Запрос( "ВЫБРАТЬ | Наименование, | Белки, | Углеводы, | Жиры, | Вода |ИЗ | Справочник.Номенклатура |УПОРЯДОЧИТЬ ПО | (Белки + Углеводы) УБЫВ" ) ; ВыполнитьЗапросИВывестиНаФорму(Запрос) ; КонецПроцедуры /// Как упорядочить результат запроса по /// иерархии в 1с 8.3, 8.2 &НаСервере Процедура КакУпорядочитьРезультатЗапросаПоИерархииНаСервере() // Для таблиц, для которых задано свойство иерархичности // возможно упорядочивание в соответствии с иерархией. // К примеру, сделаем вывод элементов из // справочника "Номенклатура" в порядке // их следования в иерархии справочника. Запрос = Новый Запрос( "ВЫБРАТЬ | Наименование |ИЗ | Справочник.Вкусы КАК Вкусы |УПОРЯДОЧИТЬ ПО | Наименование Иерархия" ) ; ВыполнитьЗапросИВывестиНаФорму(Запрос) ; КонецПроцедуры /// Как упорядочить результат запроса по /// агрегатной функции группировки в 1с 8.3, 8.2 &НаСервере Процедура КакУпорядочитьРезультатЗапросаПоАгрегатнойФункцииНаСервере() // В секции УПОРЯДОЧИТЬ ПО также возможно использование // агрегатных функций, которые были использованы для // группировки результата запроса. // Для каждого цвета - выберем минимальную калорийность // продукта, имеющиего такой цвет. А затем отсортируем // результат по возрастанию этой минимальной калорийности. Запрос = Новый Запрос( "ВЫБРАТЬ | Цвет, | МИНИМУМ(Калорийность) |ИЗ | Справочник.Номенклатура |СГРУППИРОВАТЬ ПО | Цвет |УПОРЯДОЧИТЬ ПО | МИНИМУМ(Калорийность) ВОЗР" ) ; ВыполнитьЗапросИВывестиНаФорму(Запрос) ; КонецПроцедуры /// Как работает автоупорядочивание результата /// в 1с 8.3, 8.2 &НаСервере Процедура КакРаботаетАвтоупорядочиваниеНаСервере() // Предложение АВТОУПОРЯДОЧИВАНИЕ позволяет включить режим // автоматического формирования полей для упорядочивания // результата запроса. // Автоупорядочивание работает по следующим принципам: // Если в запросе было указано предложение УПОРЯДОЧИТЬ ПО, // то каждая ссылка на таблицу, находящаяся в этом предложении, // будет заменена полями, по которым по умолчанию сортируется таблица // (для справочников это код или наименование, для документов – дата // документа). Если поле для упорядочивания ссылается на иерархический справочник, // то будет применена иерархическая сортировка по этому справочнику. // Если в запросе отсутствует предложение УПОРЯДОЧИТЬ ПО, // но есть предложение ИТОГИ, тогда результат запроса будет // упорядочен по полям, присутствующим в предложении // ИТОГИ после ключевого слова ПО, в той же последовательности и, // в случае если итоги рассчитывались по полям – ссылкам, // то по полям сортировки по умолчанию таблиц, на которые были ссылки. // Если в запросе отсутствуют предложения УПОРЯДОЧИТЬ ПО и ИТОГИ, // но есть предложение СГРУППИРОВАТЬ ПО, тогда результат запроса // будет упорядочен по полям, присутствующим в предложении, // в той же последовательности и, в случае если группировка велась // по полям – ссылкам, то по полям сортировки по умолчанию таблиц, // на которые были ссылки. // В случае же, если в запросе отсутствуют предложения и // УПОРЯДОЧИТЬ ПО, ИТОГИ и СГРУППИРОВАТЬ ПО, результат будет // упорядочен по полям сортировки по умолчанию для таблиц, // из которых выбираются данные, в порядке их появления в запросе. // В случае, если запрос содержит предложение ИТОГИ, каждый уровень // итогов упорядочивается отдельно. // В примере ниже мы сортируем по полю Ссылка и используем // ключевое слово АВТОУПОРЯДОЧИВАНИЕ. Система при этом // заменит поле Ссылка в секции УПОРЯДОЧИТЬ ПО на дату документа. Запрос = Новый Запрос( "ВЫБРАТЬ | Ссылка |ИЗ | Документ.ПродажаЕды |УПОРЯДОЧИТЬ ПО | Ссылка ВОЗР |АВТОУПОРЯДОЧИВАНИЕ" ) ; ВыполнитьЗапросИВывестиНаФорму(Запрос) ; КонецПроцедуры /// Скачать и выполнить эти примеры на компьютере

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

1. Конструкция "ИЗ".

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

ВЫБРАТЬ Справочник.Банки.*

Выбирает все поля из справочника Банки. И является аналогичным запросу:

ВЫБРАТЬ Банки.* ИЗ Справочник.Банки КАК Банки

2. Упорядочивание данных по ссылочному полю

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

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

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

3.Получение текстового представления ссылочного типа. Конструкция "ПРЕДСТАВЛЕНИЕ".

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

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

4. Условие на выборку данных по шаблону.

Например, вам необходимо получить мобильные телефоны сотрудников вида (8 -123- 456-78-912). Для этого необходимо поставить такое условие в запросе:

ВЫБРАТЬ Сорудник.Наименование, Сорудник.Телефон КАК Телефон ИЗ Справочник.Сотрудники КАК Сотрудники ГДЕ Телефон ПОДОБНО "_-___-___-__-__"

Символ "_" является служебным и заменяет любой символ.

5. Одновременное использование итогов и группировок.


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

ВЫБРАТЬ ОказаниеУслуг.Организация КАК Организация, ОказаниеУслуг.Номенклатура КАК Номенклатура, СУММА(ОказаниеУслуг.СуммаДокумента) КАК СуммаДокумента ИЗ Документ.ОказаниеУслуг КАК ОказаниеУслуг СГРУППИРОВАТЬ ПО ОказаниеУслуг.Организация, ОказаниеУслуг.Номенклатура ИТОГИ ПО ОБЩИЕ, Организация, Номенклатура

В этом случае запрос вернет практически тоже самое что и такой запрос:

ВЫБРАТЬ ОказаниеУслуг.Организация КАК Организация, ОказаниеУслуг.Номенклатура КАК Номенклатура, ОказаниеУслуг.СуммаДокумента КАК СуммаДокумента ИЗ Документ.ОказаниеУслуг КАК ОказаниеУслуг ИТОГИ СУММА(СуммаДокумента) ПО ОБЩИЕ, Организация, Номенклатура

Только первый запрос свернет записи с одинаковой номенклатурой.

6. Разыменование полей.

Обращение к полям через точку называется операцией разыменования ссылочного поля. Например Оплата.Организация.АдминистративнаяЕдиница . В этом случае в ссылочном поле "Организация" документа "Оплата", ссылается на другую таблицу "Организации", в которой будет получено значение реквизита "АдминистративнаяЕдиница". Важно понимать, что при обращении к полям через точку платформа неявно создает подзапрос и соединяет эти таблицы.

Запрос:

Можно представить в виде:

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

При разыменовании ссылочных полей составного типа платформа пытается создать неявные соединения со всеми таблицами, которые входят в тип этого поля. В этом случае запрос будет неоптимален.Если четко известно, какого типа поле, необходимо ограничивать такие поля по типу конструкцией ВЫРАЗИТЬ() .

Например имеется регистр накопления "Нераспределенные оплаты", где регистратором могут выступать несколько документов. В этом случае неверно получать значения реквизитов регистратора таким образом:

ВЫБРАТЬ НераспределенныеОплаты.Регистратор.Дата, ..... ИЗ РегистрНакопления.НераспределеныеОплаты КАК НераспределенныеОплаты

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

ВЫБРАТЬ ВЫРАЗИТЬ(НераспределенныеОплаты.Регистратор КАК Документ.Оплата).Дата, ..... ИЗ РегистрНакопления.НераспределеныеОплаты КАК НераспределенныеОплаты

7. Конструкция "ГДЕ"

При левом соединении двух таблиц, когда вы накладываете условие "ГДЕ" на правую таблицу то мы получим результат аналогичный результату при внутреннем соединении таблиц.

Пример. Необходимо выбрать всех Клиентов из Справочника клиенты и для тех клиентов, у которых имеется документ оплата со значением реквизита "Организация" = &Организация вывести документ "Оплата", для тех у кого нет, не выводить.

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

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

Можно обойти это условие и другим способом. необходимо наложить условие "ГДЕ" непосредственно в связи двух таблиц. Пример:

ВЫБРАТЬ Клиенты.Ссылка, Оплата.Ссылка ИЗ Справочник.УС_Абоненты КАК УС_Абоненты ЛЕВОЕ СОЕДИНЕНИЕ Документ.Оплата КАК Оплата ПО (Клиенты.Ссылка = Оплата.Клиент И Оплата.Клиент.Наименование ПОДОБНО "Сахарный Пакет") СГРУППИРОВАТЬ ПО Клиенты.Ссылка, Оплата.Ссылка

8. Соединения с Вложенными и Виртуальными таблицами

Вложенные запросы зачастую необходимы для выборки данных по какому-либо условию. Если же потом использовать их в соединении с другими таблицами то это может критически замедлить выполнение запроса.

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

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

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

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

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

Виртуальные таблицы , позволяют получить практически готовые данные для большинства прикладных задач.(СрезПервых,СрезПоследних,Остатки,Обороты,ОстаткиИОбороты) Ключевое слово здесь виртуальные. Эти таблицы не являются физическими, а компонуются системой налету, т.е. при получении данных из виртуальных таблиц система собирает данные из итоговых таблиц регистров, компонует, группирует и выдает пользователю.

Т.е. при соединении с виртуальной таблицей происходит соединение с подзапросом. В этом случае оптимизатор СУБД может также выбрать неоптимальный план соединения. Если запрос формируется недостаточно быстро и в запросе испольуются соединения в виртуальными таблицами, то реклмендуется вынести обращение к виртуальным таблицам во временную таблицу, а затем в произвести соедининие между двумя временными таблицами. Перепишем предыдущий запрос.

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

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

Результат выполнения запроса может быть пустым, для проверки на пустые значения следует использовать конструкцию:

РезЗапроса = Запрос.Выполнить(); Если резЗапроса.Пустой() Тогда Возврат; КонецЕсли;

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

Ни для кого не является открытием то, что запросы в цикле использовать крайне нежелательно. Это может критически сказаться на времени работы той или иной функции. Очень желательно получать все данные в запросе и уже потом обрабатывать данные в цикле. Но иногда бывают случаи, когда вынести запрос за пределы цикла становится невозможным. В этом случае для оптимизации можно вынести создание запроса за пределы цикла, а в цикле подставлять необходимые параметры и выполнять запрос.

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

Это избавит систему от синтаксической проверки запроса в цикле.

11. Конструкция "ИМЕЮЩИЕ".

Конструкция, довольно редко встречающаяся в запросах. Позволяет накладывать условия на значения агрегатные функций (СУММА, МИНИМУМ, СРЕДНЕЕ и т.д.). Например, вам необходимо выбрать только тех клиентов, у которых сумма оплат в сентябре была больше 13 000 рублей. Если использовать условие "ГДЕ", то придется сначала создавать временную таблицу или вложенный запрос, там группировать записи по сумме оплаты и потом накладывать условие. Конструкция "ИМЕЮЩИЕ" поможет этого избежать.

ВЫБРАТЬ Оплата.Клиент, СУММА(Оплата.Сумма) КАК Сумма ИЗ Документ.Оплата КАК Оплата ГДЕ МЕСЯЦ(Оплата.Дата) = 9 СГРУППИРОВАТЬ ПО Оплата.Клиент ИМЕЮЩИЕ СУММА(Оплата.Сумма) > 13000

В конструкторе для этого достаточно перейти на вкладку "Условия", добавить новое условие и поставить галочку на "Произвольное". Далее просто написать Сумма(Оплата.Сумма) > 13000


12. Значение NULL

Я не буду описывать здесь принципы трехзначной логики в БД, есть множество статей на эту тему. Просто вкратце о том как NULL может повлиять на результат запроса. Значение NULL на самом деле не значение, а факт того, что значение не определено, неизвестно. Поэтому любые операции с NULL возвращают NULL, будь то сложение, вычитание, деление или сравнение. Значение NULL не может быть сравнимо со значением NULL, потому как мы не знаем, что именно сравнивать. Т.е. оба этих сравнения: NULL = NULL, NULL<>NULL - это не Истина или не Ложь, это неизвестно.

Давайте рассмотрим пример.

Нам необходимо для тех клиентов, у которых нет оплат, вывести поле "Признак" со значением "Нет оплат". Причем мы точно знаем, что такие клиенты у нас есть. И для того, чтобы отразить суть того, что писал выше сделаем это так.

ВЫБРАТЬ "Нет оплат" КАК Признак, NULL КАК Документ ПОМЕСТИТЬ тОплаты; //////////////////////////////////////////////////////////////////////////////// ВЫБРАТЬ Клиенты.Ссылка КАК Клиент, Оплата.Ссылка КАК Оплата ПОМЕСТИТЬ тКлиентОплата ИЗ Справочник.Клиенты КАК Клиенты ЛЕВОЕ СОЕДИНЕНИЕ Документ.Оплата КАК Оплата ПО Клиенты.Ссылка = Оплата.Пайщик; //////////////////////////////////////////////////////////////////////////////// ВЫБРАТЬ тКлиентОплата.Клиент ИЗ тКлиентОплата КАК тКлиентОплата ВНУТРЕННЕЕ СОЕДИНЕНИЕ тОплаты КАК тОплаты ПО тКлиентОплата.Оплата = тОплаты.Документ

Обратите внимание на вторую временную таблицу тКлиентОплата. Левым соединением я выбираю всех клиентов и все оплаты по этим клиентам. Для тех же клиентов у которых нет оплат в поле "Оплата" будет NULL . Следуя логике, в первой временной таблице "тОплаты" я обозначил 2 поля, одно из них NULL, второе строка "Не имеет оплат". В третьей таблице я соединяю внутренним соединением таблицы "тКлиентОплата" и "тОплаты" по полям "Оплата" и "Документ". Мы знаем, что в первой таблице поле "Документ" это NULL, и во второй таблице у тех, у кого нет оплат в поле "Оплата" тоже NULL. Что же вернет нам такое соединение? А ничего не вернет. Потому как сравнение NULL = NULL не принимает значение Истина.

Для того, чтобы запрос вернул нам ожидаемый результат, перепишем его:

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

Теперь, во второй временной таблице, мы указали, что в случае, если поле "Оплата" есть NULL, тогда это поле = пустая ссылка на документ оплата. В Первой таблице мы также заменили NULL на пустую ссылку. Теперь в соединении участвуют не NULL поля и запрос вернет нам ожидаемый результат.

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

13. Недокументированная особенность конструкции "ВЫБОР КОГДА...ТОГДА....КОНЕЦ".

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

ВЫБРАТЬ ВЫБОР КОГДА Пользователи.Наименование = "Вася Пупкин" ТОГДА "Наш любимый сотрудник" ИНАЧЕ "Не знаем такого" КОНЕЦ КАК Поле1 ИЗ Справочник.Пользователи КАК Пользователи

А что делать, если, к примеру, нам надо получить название месяца в запросе? Писать огромную конструкцию в запросе некрасиво и долго, поэтому нас может выручить такая форма записи выше:

ВЫБОР МЕСЯЦ(УС_РасчетПотребления_ГрафикОбороты.ПериодРасчета) КОГДА 1 ТОГДА "Январь" КОГДА 2 ТОГДА "Февраль" КОГДА 3 ТОГДА "Март" КОГДА 4 ТОГДА "Апрель" КОГДА 5 ТОГДА "Май" КОГДА 6 ТОГДА "Июнь" КОГДА 7 ТОГДА "Июль" КОГДА 8 ТОГДА "Август" КОГДА 9 ТОГДА "Сентябрь" КОГДА 10 ТОГДА "Октябрь" КОГДА 11 ТОГДА "Ноябрь" КОГДА 12 ТОГДА "Декабрь" КОНЕЦ КАК Месяц

Теперь конструкция выглядит не такой громоздкой и легко воспринимается.

14. Пакетное выполнение запроса.


Для того, чтобы не плодить запросы, можно создать один большой запрос, разбить его на пакеты и работать уже с ним.
Например, мне нужно получить из справочника "Пользователи" поля: "ДатаРождения" и доступные роли для каждого пользователя. в выгрузить это в разные табличные части на форме. Конечно можно сделать это в одном запросе, тогда придется перебирать записи или сворачивать, а можно так:

ВЫБРАТЬ Пользователи.Ссылка КАК ФИО, Пользователи.ДатаРождения, Пользователи.Роль ПОМЕСТИТЬ втПользователи ИЗ Справочник.Пользователи КАК Пользователи; //////////////////////////////////////////////////////////////////////////////// ВЫБРАТЬ втПользователи.ФИО, втПользователи.ДатаРождения ИЗ втПользователи КАК втПользователи СГРУППИРОВАТЬ ПО втПользователи.ФИО, втПользователи.ДатаРождения; //////////////////////////////////////////////////////////////////////////////// ВЫБРАТЬ втПользователи.ФИО, втПользователи.Роль ИЗ втПользователи КАК втПользователи СГРУППИРОВАТЬ ПО втПользователи.ФИО, втПользователи.ДатаРождения

тПакет = Запрос.ВыполнитьПакет();

ТП_ДатыРождения = тПакет.Выгрузить();
ТП_Роли = тПакет.Выгрузить();

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

15. Условия в пакетном запросе

Например, у нас есть пакетный запрос, где сначало мы получаем поля: "Наименование, ДатаРождения, Код" из справочника "Пользователи" и хотим из справочника "ФизЛица" получить записи с условием по этим полям.

ВЫБРАТЬ Пользователи.ФизЛицо.Наименование КАК Наименование, Пользователи.ФизЛицо.ДатаРождения КАК ДатаРождения, Пользователи.ФизЛицо.Код КАК Код ПОМЕСТИТЬ втПользователи ИЗ Справочник.Пользователи КАК Пользователи; //////////////////////////////////////////////////////////////////////////////// ВЫБРАТЬ ФизическиеЛица.Ссылка КАК ФизЛицо ИЗ Справочник.ФизическиеЛица КАК ФизическиеЛица

Можно накложить условия таким образом:

ГДЕ ФизическиеЛица.Код В (ВЫБРАТЬ втПользователи.Код ИЗ втПользователи) И ФизическиеЛица.Наименование В (ВЫБРАТЬ втПользователи.Код ИЗ втПользователи) И ФизическиеЛица.ДатаРождения В (ВЫБРАТЬ втПользователи.ДатаРождения ИЗ втПользователи)

А Можно и так:

ГДЕ (ФизическиеЛица.Код, ФизическиеЛица.Наименование, ФизическиеЛица.ДатаРождения) В (ВЫБРАТЬ втПользователи.Код, втПользователи.Наименование, втПользователи.ДатаРождения ИЗ втПользователи)

Причем обязателено соблюдать порядок.

16. Вызов конструктора запросов для "условия" в пакетном запросе

Когда необходимо наложить условие, как в примере выше, можно забыть как то или иное поле называется в виртуальной таблице.
Например надо наложить условие на поле "ДатаРождения", а в виртуальной таблице это поле называется "ДатаРожденияДебитора", и если вы забыли название, то придется выходить из редактирования условия без сохранения и смотреть название поля. Для того, чтобы избежать этого можно воспользоватьтся следующим приемом.

Необходимо после Конструкции "В" поставить скобки и между скобками оставить пустое место(пробел), выделить это место и вызвать контруктор запросов. Контруктору будут доступны все таблицы пакетного запроса. Прием работает как на виртуальных таблицах регистров, так и для вкладки "Условия". В последнем случае необходимо поставить галочку "П(произволное условие)" и войти в режим редактирования "F4".

Запросов зачастую выдумывал на ходу и они служат просто для отображения "приемов", которые я рассматривал.

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

upd1. Пункты 11,12
upd2. Пункты 13,14,15,16

Используемая литература:
Язык запросов "1С:Предприятия 8" - Е.Ю. Хрусталева
Профессиональная разработка в системе 1С:Предприятие 8".

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

Запрос выполняется в соответствии с заданными инструкциями — текстом запроса . Текст запроса составляется в соответствии с синтаксисом и правилами языка запросов . Язык запросов 1С:Предприятие 8 основан на базе стандартного SQL , но имеет некоторые отличия и расширения.

Схема работы с запросом

Общая схема работы с запросом состоит из нескольких последовательных этапов:

  1. Создание объекта Запрос и установка текста запроса;
  2. Установка параметров запроса;
  3. Выполнение запроса и получение результата;
  4. Обход результата запроса и обработка полученных данных.

1. Объект Запрос имеет свойство Текст , которому необходимо присвоить текст запроса.

// Вариант 1
Запрос = Новый Запрос;
Запрос. Текст =
«ВЫБРАТЬ
| КурсыВалют.Период,
| КурсыВалют.Валюта,
| КурсыВалют.Курс
|ИЗ

|ГДЕ
;

// Вариант 2
Запрос = Новый Запрос («ВЫБРАТЬ
| КурсыВалют.Период,
| КурсыВалют.Валюта,
| КурсыВалют.Курс
|ИЗ
| РегистрСведений.КурсыВалют КАК КурсыВалют
|ГДЕ
| КурсыВалют.Валюта = &Валюта» );

2. Установка значений параметров осуществляется методом УстановитьПараметр(< Имя>, < Значение>) . Параметры в тексте запроса обозначаются символом «& » и обычно используются в условиях отбора (секция ГДЕ) и в параметрах виртуальных таблиц.

Запрос);

3. После присвоения текста и установки параметров запрос необходимо выполнить и получить результат выполнения. Выполнение производится методом Выполнить () , который возвращает объект РезультатЗапроса . Из результата запроса можно:

  • получить выборку с помощью метода Выбрать(< ТипОбхода>, < Группировки>, < ГруппировкиДляЗначенийГруппировок>) ;
  • выгрузить значения в таблицу значений или дерево значений с помощью метода Выгрузить(< ТипОбхода>) .

// Получение выборки

Выборка = РезультатЗапроса. Выбрать ();

// Получение таблицы значений
РезультатЗапроса = Запрос. Выполнить();
Таблица = РезультатЗапроса. Выгрузить ();

4. Обойти выборку результата запроса можно с помощью цикла:

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

Полный пример работы с запросом может выглядеть так:

// Этап 1. Создание запроса и установка текста запроса
Запрос = Новый Запрос;
Запрос. Текст =
«ВЫБРАТЬ
| КурсыВалют.Период,
| КурсыВалют.Валюта,
| КурсыВалют.Курс
|ИЗ
| РегистрСведений.КурсыВалют КАК КурсыВалют
|ГДЕ
| КурсыВалют.Валюта = &Валюта» ;

// Этап 2. Установка параметров
Запрос. УстановитьПараметр(«Валюта» , ВыбраннаяВалюта );

// Этап 3. Выполнение запроса и получение выборки
РезультатЗапроса = Запрос. Выполнить();
Выборка = РезультатЗапроса. Выбрать ();

// Обход выборки
Пока Выборка .Следующий () Цикл
Сообщить (Выборка .Курс );
КонецЦикла;

Состав текста запроса

Текст запроса состоит из нескольких секций:

  1. Описание запроса — перечень выбираемых полей и источников данных;
  2. Объединение запросов — выражения «ОБЪЕДИНИТЬ» и «ОБЪЕДИНИТЬ ВСЕ»;
  3. Упорядочивание результатов — выражение «УПОРЯДОЧИТЬ ПО …»;
  4. Автоупорядочивание — выражение «АВТОУПОРЯДОЧИВАНИЕ»;
  5. Описание итогов — выражение «ИТОГИ … ПО …».

Обязательной является только первая секция.

Временные таблицы и пакетные запросы

Язык запросов 1С поддерживает использование временных таблиц — таблиц, полученных в результате выполнения запроса и сохраненных на временной основе.

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

МенеджерВТ = Новый МенеджерВременныхТаблиц;
Запрос = Новый Запрос;
Запрос. МенеджерВременныхТаблиц = МенеджерВТ;

Запрос. Текст =
«ВЫБРАТЬ
| Валюты.Код,
| Валюты.Наименование
|ПОМЕСТИТЬ ВТВалюты
|ИЗ
| Справочник.Валюты КАК Валюты» ;

РезультатЗапроса = Запрос. Выполнить ();

Для использования временной таблицы ВТВалюты в других запросах необходимо этим запросам присвоить общий менеджер временных таблиц — МенеджерВТ.

Пакетный запрос — это запрос, в котором содержится несколько запросов, разделенных символом «;». При выполнении пакетного запроса все входящие в него запросы выполняются последовательно, причем результаты всех временных таблиц доступны всем последующим запросам. Явное присвоение менеджера временных таблиц пакетным запросам не обязательно. Если менеджер временных таблиц не присвоен, то все временные таблицы удалятся сразу после выполнения запроса.

Для пакетных запросов доступен метод ВыполнитьПакет () , который выполняет все запросы и возвращает массив результатов. Временные таблицы в пакетном запросе будут представлены таблицей с одной строкой и одной колонкой «Количество», в которой хранится количество записей. Для отладки пакетных запросов можно использовать метод ВыполнитьПакетСПромежуточнымиДанными () : он возвращает реальное содержимое временных таблиц, а не количество записей.

// Пример работы с пакетным запросом
Запрос = Новый Запрос;
Запрос. Текст =
«ВЫБРАТЬ
| Валюты.Наименование
|ИЗ
| Справочник.Валюты КАК Валюты
|;
|ВЫБРАТЬ
| Номенклатура.Наименование
|ИЗ
| Справочник.Номенклатура КАК Номенклатура» ;

РезультатПакета = Запрос. ВыполнитьПакет();

ТЗВалюты = РезультатПакета[ 0 ]. Выгрузить();
ТЗНоменклатура = РезультатПакета[ 1 ]. Выгрузить();

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

Запрос. УстановитьПараметр(«Производитель» , Производитель);

РезультатЗапроса = Запрос. Выполнить();
Выборка = РезультатЗапроса. Выбрать ();

Пока Выборка .Следующий () Цикл

КонецЦикла;

Виртуальные таблицы

Виртуальные таблицы — это таблицы, которые не хранятся в базе данных, а формируются платформой. По своей сути это вложенные запросы к одной или нескольким физическим таблицам, выполняемые платформой. Виртуальные таблицы получают информацию только из регистров и, в основном, предназначены для решения узкоспециализированных задач.

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

  • Для регистров сведений:
    • СрезПервых(<Период>, <Условие>) — наиболее ранние записи на указанную дату;
    • СрезПоследних(<Период>, <Условие>) — наиболее поздние записи на указанную дату;
  • Для регистров накопления:
    • Остатки(<Период>, <Условие>) — остатки на указанную дату;
    • Обороты(<НачалоПериода>, <КонецПериода>, <Периодичность>, <Условие>) — обороты за период;
    • ОстаткиИОбороты(<НачалоПериода>, <КонецПериода>, <Периодичность>, <МетодДополненияПериодов>, <Условие>) — остатки и обороты за период;
  • Для регистров бухгалтерии:
    • Остатки(<Период>, <УсловиеСчета>, <Субконто>, <Условие>) — остатки на указанную дату в разрезе счета, измерений и субконто;
    • Обороты(<НачалоПериода>, <КонецПериода>, <Периодичность>, <УсловиеСчета>, <Субконто>, <Условие>, <УсловиеКорСчета>, <КорСубконто>) — обороты за период в разрезе счета, измерений, кор. счета, субконто, кор. субконто;
    • ОстатковИОборотов(<НачалоПериода>, <КонецПериода>, <Периодичность>, <МетодДополненияПериодов>, <УсловиеСчета>, <Субконто>, <Условие>) — остатки и оборотов в разрезе счета, измерений и субконто;
    • ОборотыДтКт(<НачалоПериода>, <КонецПериода>, <Периодичность>, <УсловиеСчетаДт>, <СубконтоДт>, <УсловиеСчетаКт>, <СубконтоКт>, <Условие>) — обороты за период в разрезе счета Дт, счета Кт, Субконто Дт, Субконто Кт;
    • ДвиженияССубконто(<НачалоПериода>, <КонецПериода>, <Условие>, <Порядок>, <Первые>) — движения вместе со значениями субконто;
  • Для регистров расчета:
    • База(<ИзмеренияОсновногоРегистра>, <ИзмеренияБазовогоРегистра>, <Разрезы>, <Условие>) — базовые данные регистра расчета;
    • ДанныеГрафика(<Условие>) — данные графика;
    • ФактическийПериодДействия(<Условие>) — фактический период действия.

При работе с виртуальными таблицами следует накладывать отборы в параметрах виртуальных таблиц, а не в условии ГДЕ. От этого сильно зависит время выполнения запроса.

Конструктор запроса

Для ускорения ввода текстов запросов платформа имеет специальные инструменты: Конструктор запроса и Конструктор запроса с обработкой результата . Для вызова конструкторов необходимо щелкнуть правой кнопкой мыши и выбрать требуемый пункт:

Также конструкторы можно вызвать из главного меню Текст .

При помощи конструктора запроса программист может интерактивно сконструировать текст запроса. Для этого мышкой выбираются нужные таблицы и поля, устанавливаются связи, группировки, итоги и т.д. Данный подход позволяет экономить время и избавиться от возможных ошибок. В результате своей работы конструктор запроса формирует текст запроса.

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

Объект СхемаЗапроса

Платформа позволяет программно создавать и редактировать текст запроса при помощи объекта СхемаЗапроса . Объект имеет единственное свойство ПакетЗапросов , в котором объекта хранятся свойства всех запросов, редактируемых в данный момент. Объект СхемаЗапроса поддерживает следующие методы:

  • УстановитьТекстЗапроса(< Текст>) — заполняет свойство ПакетЗапросов на основании переданного текста запроса;
  • ПолучитьТекстЗапроса () — возвращает сформированный на основании свойства ПакетЗапросов текст запроса;
  • НайтиПараметры () — возвращает параметры запроса.

Рассмотрим пример работы с объектом СхемаЗапроса. Для программного формирования текста запроса

УПОРЯДОЧИТЬ ПО
Валюты.Код

Код на встроенном языке может выглядеть так:

СхемаЗапроса = Новый СхемаЗапроса;
Пакет1 = СхемаЗапроса. ПакетЗапросов[ 0 ];
Оператор1 = Пакет1. Операторы[ 0 ];
// добавление источника
ТаблицаРегистра = Оператор1. Источники. Добавить(«Справочник.Валюты» , «Валюты» );
// добавление полей
ПолеСсылка = Оператор1. ВыбираемыеПоля. Добавить(«Валюты.Ссылка» , 0 );
ПолеКод = Оператор1. ВыбираемыеПоля. Добавить(«Валюты.Код» , 1 );
// указание псевдонимов полей
Пакет1. Колонки[ 0 ]. Псевдоним = «Валюта» ;
Пакет1. Колонки[ 1 ]. Псевдоним = «Код» ;
// добавление условия
Оператор1. Отбор. Добавить(«НЕ ПометкаУдаления» );
// добавление упорядочивания
Пакет1. Порядок. Добавить(ПолеКод);
ТекстЗапроса = СхемаЗапроса. ПолучитьТекстЗапроса ();