1с как в поле запроса передать запрос
Структура кода запроса в 1С легко изучить. Начнем от простого запроса к более сложным вариантам.
Выбрать
Любой запрос имеет команду ВЫБРАТЬ, после которой могут идти дополнительные параметры выборки, которые позднее рассмотрим отдельно:
ПЕРВЫЕ <ЧИСЛОЗАПИСЕЙ>
РАЗЛИЧНЫЕ
РАЗРЕШЕННЫЕ
Далее идет список полей выборки.
Простейший запрос в 1С может иметь такой вид:
Данный запрос вернет таблицу, состоящую из одной строки и одной колонки, в которой будет числовое значение равное 1.
Усложняем запрос: добавим еще поля, разделив их запятой
ВЫБРАТЬ 1, 2, "3"
Этот запрос также вернет 1 строку, но уже с 3 колонками, две из которых содержат числа, а 3 строковое.
Поэтому в языке запросов существует специальный оператор именования КАК <ИмяПоля>, который идет после поля,
Предыдущий запрос можно представить в таком виде:
ВЫБРАТЬ 1 КАК Один, 2 КАК Два, "3" КАК ЦифраТриСтрокой
Имена полей задаются по правилам именования переменных: не могут начинаться со строки, содержать пробелы, не должны повторятся в одной выборке, а также отсутствовать (они поставятся автоматически).
Возможно опускать слово КАК, но лучше такой вариант не использовать, так как конструктор запросов это исправит:
ВЫБРАТЬ ссылка ссылка ИЗ Справочник.ФизическиеЛица
Такие простые запросы конечно имеют место в реальных условиях, как вспомогательные таблицы, но обычно требуется выборка из какого-то источника.
Для этого существует оператор ИЗ <ТаблицаДанных>, в которой источник данных может быть реальной таблицей из базы данных, а также виртуальными таблицами, которые существуют к некоторым таким таблицами или же к временным таблицам.
Пример простого запроса к реальной таблице справочника:
ВЫБРАТЬ ссылка ИЗ Справочник.Контрагенты
В таких запросах мы можем указать конкретные поля, которые нам нужны или указать *.
ВЫБРАТЬ * ИЗ Справочник.Контрагенты
Такой вариант универсальный, но избыточное количество полей замедляет и усложняет их разбор позднее.
Вложенные таблицы
Также возможно обращение к вложенной таблице:
ВЫБРАТЬ * ИЗ Справочник.Контрагенты.КонтактнаяИнформация КАК КонтактнаяИнформация
Как видите, здесь мы впервые использовали именование таблицы, которое также упрощает работу при написании запроса, это дает возможность обращения по этому имени к полям:
ВЫБРАТЬ КИ.Ссылка ИЗ Справочник.Контрагенты.КонтактнаяИнформация КАК КИ //так иногда будет короче
Особенностью запросов к вложенным таблицам является то, что возможно обращение к родительской таблице через поле ссылка через точку.
ВЫБРАТЬ Ссылка.Наименование ИЗ Справочник.Контрагенты.КонтактнаяИнформация КАК КонтактнаяИнформация
Подобная возможность используется и при обращении к реквизитам ссылочных полей: система сама неявно соединит нужные таблицы, но использование такого обращения следует использовать реже (особенно при указании условий в виртуальных таблицах или условий соединения таблиц).
ВЫБРАТЬ Ссылка, ОсновнойДоговор.Наименование КАК НазваниеДоговора ИЗ Справочник.Контрагенты
В данном случае поле ОсновнойДоговор может быть пустым, тогда обращение к его наименованию не вызовет ошибку, но значение будет NULL, поэтому рекомендуется использовать ЕстьNULL.
Дополнительно
Вернемся к запросу
ВЫБРАТЬ КИ.Ссылка ИЗ Справочник.Контрагенты.КонтактнаяИнформация КАК КИ
В данном запросе, мы не выбираем поля из самой подтаблицы КонтактнаяИнформация, и в случае если в ней несколько строк, то в выборку попадут несколько строк с одинаковым содержимым.
Чтобы избежать этого можно воспользоваться служебным словом РАЗЛИЧНЫЕ: система устранит все дубли автоматически.
ВЫБРАТЬ РАЗЛИЧНЫЕ КИ.Ссылка ИЗ Справочник.Контрагенты.КонтактнаяИнформация КАК КИ
Если мы хотим ограничить результат выборки количеством записей (например сотней) используем ПЕРВЫЕ, но использовать ее необходимо с осторожностью (иногда эта команда срабатывает раньше, чем применяются условия запросов), следует тестировать запросы основательно.
ВЫБРАТЬ ПЕРВЫЕ 100 КИ.Ссылка ИЗ Справочник.Контрагенты.КонтактнаяИнформация КАК КИ
ВЫБРАТЬ * ИЗ (ВЫБРАТЬ * ИЗ Справочник.Контрагенты) КАК ВложеннаяТаблица
Использование вложенных запросов имеет смысл в случае, если в нем данные как-либо предварительно обрабатываются, а не как в вышеуказанном примере, где это излишне.
В целом, использование временных таблиц и вложенных запросов замедляет выборку, но парадокс в том, что их использование может дать нужный сигнал оптимизатору запросов и эффект получается положительный.
При больших исходных данных, следует проверять оба варианта использования, на предмет скорости исполнения, для принятия окончательного варианта запроса.
Регистр команд, имен и полей запроса не имеет значение: Выбрать и ВыБРатЬ равносильны.
Зачастую нужно заранее сделать выборку из базы данных по некоему условию. Для этого в 1С 8.3 необходимо использовать вложенные запросы.
Но следует учитывать, что в большинстве случаев вложенные запросы в 1С бесполезны без соединения их результата с другими таблицами. Такое соединение практически в любом случае приведет к сильному замедлению выполнения запроса в целом.
Пример вложенного запроса на языке запросов
Приведу пример вложенного запроса на языке запросов 1С. Допустим, нам нужно сделать выборку суммы некоторого остатка по отдельным клиентам на определенную дату:
ВЫБРАТЬ
НераспОплатыОстатки.Заказчик,
НераспОплатыОстатки.СуммаОст
ИЗ(ВЫБРАТЬ
Заказчики.Ссылка КАК СсылкаНаСпрЗаказчики
ИЗ
Справочник.Заказчики КАК Заказчики
ГДЕ
Заказчики.Ссылка В(&Заказчики)) КАК ВложЗапросЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления. НераспОплаты.Остатки КАК НераспОплаты
ПО ВложЗапрос.СсылкаНаСпрЗаказчики = НераспОплатыОстатки.Заказчик
Когда СУБД будет выполнять такой запрос, не исключены неверные действия оптимизатора, так как трудно определиться с планом обработки запроса. Когда СУБД соединяет две таблицы, оптимизатор строит алгоритм на основе вычисления количества записей в этих таблицах.
Когда же используется вложенный запрос, вычислить количество записей, вернувшихся из вложенного запроса, очень трудно.
Как лучше?
Именно поэтому фирма 1С крайне не рекомендует использовать вложенные запросы, а вместо них разработала временные таблицы. С использованием временных таблиц наш предыдущий запрос будет выглядеть так:
// Временная таблица
ВЫБРАТЬ
Заказчики.Ссылка КАК Заказчики
ПОМЕСТИТЬ табЗаказчики
ИЗ
Справочник.Заказчики КАК Заказчики
ГДЕ Заказчики.Ссылка В (&Заказчики)
;// Основной запрос
ВЫБРАТЬ
табКлиенты.Ссылка,
НераспОплатыОстатки.СуммаОст,
ИЗ
табЗаказчики КАК табЗаказчики
ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.НераспОплаты.Остатки(
,
Заказчик В
(ВЫБРАТЬ
табЗаказчики.Заказчики
ИЗ
табЗаказчики)) КАК НераспОплатыОстатки
ПО табЗаказчики.Заказчики = НераспОплатыОстатки.Заказчики
Смотрите также видео-урок про вложенные запросы:
Если вы только начинаете программировать в 1С или просто хотите систематизировать свои знания - попробуйте Школу программирования 1С нашего друга Владимира Милькина. Пошаговые и понятные уроки даже для новичка с поддержкой учителя.
Попробуйте бесплатно по ссылке >>
Теперь оптимизатор знает заранее, сколько записей во временной таблице, и без труда оптимизирует алгоритм выполнения соединения таблиц.
Эти операторы возможно использовать во всех 4 ситуациях, но контекст (окружаемые переменные у них отличаются).
В первых двух случаях условия накладываются на поля выборки, например:
ВЫБРАТЬ Ссылка ИЗ Справочник.Контрагенты КАК СпрКонтрагенты ГДЕ СпрКонтрагенты.ИНН<>""
Обращение идет через имя таблицы (в простых запросах может опускаться, но в сложных может вызывать неоднозначность поля).
Данное условие вызывает ограничение выборки (обычно уменьшает ее)
В конструкторе запроса находятся на вкладке условия:
В произвольном варианте пишется текстом, в обычном выбирается поле, оператор сравнения и значение:
ВЫБОР КОГДА
Этот условный оператор используется для преобразования значения, ограничивает же выборку только когда расположен после служебного слова ГДЕ.
Допустимо несколько подчиненных условий. Может находится в полях выборки, полях условий ГДЕ, группировок, итогов (универсальный оператор для сложных условий)
Например, так выглядит вариант преобразования:
ВЫБРАТЬ
ВЫБОР
КОГДА 1 = 2
ТОГДА "Никогда не будет истиной"
КОГДА 1 = 1
ТОГДА "Всегда будет истиной"
ИНАЧЕ ДАТАВРЕМЯ(1, 1, 1)
КОНЕЦ КАК ПолеПредставленияЗначения
Вариант использования в условии ГДЕ, результат выборки должен возвращать булево значение либо сравниваться с чем-то еще
Пример № 1
ВЫБРАТЬ Ссылка ИЗ Справочник.Контрагенты КАК К ГДЕ ВЫБОР КОГДА К.ИНН = "" ТОГДА ЛОЖЬ ИНАЧЕ ИСТИНА КОНЕЦ
Пример № 2:
ВЫБРАТЬ Ссылка ИЗ Справочник.Контрагенты КАК К ГДЕ ВЫБОР КОГДА К.ИНН = "" ТОГДА "" ИНАЧЕ "Заполнено" КОНЕЦ = "Заполнено"
Параметры виртуальных таблиц
В данном случае оперирование идет с полями таблиц, например ресурсами, измерениями, реквизитами. В этих условиях обращение идет без точки (контекст этого не требует).
ВЫБРАТЬ * ИЗ РегистрСведений.КурсыВалют.СрезПоследних(, Валюта.Код = "RUR")
В конструкторе запроса они находятся вот здесь:
Стоит отметить, что обычно используется ограничение над измерениями, так как иначе условие отнесется к выборке для получения, а не на сам результат (на ресурсы ограничения следует наложить в операторе ГДЕ, чтобы получить ожидаемый результат).
Накладывание условия в запросе на измерения, если нет обращения через точку (как в примере выше), ускоряет выборку: на больших таблицах, это будет визуально заметно; на небольших можно использовать как удобно.
ИМЕЮЩИЕ
ВЫБРАТЬ
Контрагенты.ИНН,
КОЛИЧЕСТВО(РАЗЛИЧНЫЕ Контрагенты.Ссылка) КАК Ссылка
ИЗ
Справочник.Контрагенты КАК Контрагенты
СГРУППИРОВАТЬ ПО
Контрагенты.ИНН
ИМЕЮЩИЕ
КОЛИЧЕСТВО(РАЗЛИЧНЫЕ Контрагенты.Ссылка) > 1 И
Контрагенты.ИНН <> ""
В данную выборку попадут дубли ИНН, когда оно вообще заполнено.
В конструкторе запроса также находится на вкладке условия
Вложенным называется запрос, который является источником выборки основного запроса. Допускается произвольная вложенность таких запросов.
- Предназначен для предварительной обработке данных, либо для более удобного восприятия.
- Может использоваться в качестве параметра условия В()
Синтаксис вложенного запроса:
ВЫБРАТЬ * из (ВЫБРАТЬ 1) КАК ВложенныйЗапрос
ВЫБРАТЬ * ИЗ Справочник.Контрагенты ГДЕ Ссылка В (ВЫБРАТЬсколько с Ссылка ИЗ Справочник.Контрагенты)
ВЫБРАТЬ * ИЗ Справочник.Контрагенты ГДЕ (Ссылка,Наименование) В (ВЫБРАТЬ Ссылка,Наименование ИЗ Справочник.Контрагенты)
В конструкторе вложенный запрос создается на основной вкладке по специальной кнопке:
Иконка у таблицы вложенного запроса отличается от других таблиц:
Прочие сведения о вложенных запросах
Считается, что вложенные запросы менее оптимизированы на скорость, но с появлением платформы 8.3 данный фактор справедлив только для Postgres SQL (возможно особенность конкретной сборки).
В целом, в большинстве случаев, запросы можно переписать на использование временных таблиц, но не для запроса динамического списка управляемого интерфейса (там это запрещено на уровне платформы). Вложенный запрос же использовать в нем допустимо, если он не вызывает дублей ключевых полей (Ссылка).
Если вложенный запрос основной, то основная таблица динамического списка будет пустой, что отключит событийные команды такого списка.
(для примера выше, нельзя будет добавить новый элемент или группу).
Допускается вложенный запрос и при соединениях таблиц.
Например:
ВЫБРАТЬ * ИЗ Справочник.Контрагенты КАК Основная ЛЕВОЕ СОЕДИНЕНИЕ (ВЫБРАТЬ * ИЗ Справочник.Контрагенты ) КАК Вложенный ПО Основная.Ссылка = Вложенный.Ссылка
Примеры выше подобраны в учебных целях: максимально простого синтаксиса, а не для решения какой-либо задачи.
Зачем может потребоваться вложенный запрос в приоритетном порядке:
В случае использования результата агрегатной функции в качестве условия соединения таблиц:
- Для простого отбора можно воспользоваться конструкцией ИМЕЮЩИЕ.
Если же нам необходимо посчитать остаток в рознице + в опте (в торговле) и вывести только, те у которых общий остаток меньше 10, без вложенного запроса невозможно будет обойтись. - Условия в запросах виртуальных таблиц работают лучше и быстрее, если используется В(), вместо обращения через точку:
ВЫБРАТЬ * ИЗ РегистрСведений.КурсыВалют.СрезПоследних(, Валюта В(ВЫБРАТЬ ссылка из Справочник.Валюты. ГДЕ Наименование = "Рубль"))
ВЫБРАТЬ * ИЗ РегистрСведений.КурсыВалют.СрезПоследних(, Валюта.Наименование = "Рубль")
Большинство разработчиков 1С знают, что выполнение запроса в цикле крайне нежелательно из-за множественных серверных вызовов базы данных. Однако далеко не все из них понимают, как избежать использования этой неоптимальной конструкции. А помочь в этом разработчикам может использование таблиц значений в качестве параметра запроса 1С. Поняв суть этого решения, программист 1С никогда больше не вернется к выполнению запросов в цикле.
Пример передачи таблицы в запрос
Использование таблиц значений в запросе 1С является одним из признаков хорошего тона разработки, поэтому важно понимать его суть. Состоит она в том, что мы формируем ТЗ, передаем ее параметром в наш запрос и помещаем во временную таблицу. Имея в запросе нужные данные, можно будет сделать соединение таблиц в запросе 1С, информация из которых необходима. Такой прием сделает структуру кода более понятной и позволит использовать временную таблицу в нескольких частях запроса.
Получить ТЗ в 1С можно 2 способами:
- Выгрузить в нужный тип данных информацию;
- Программно создать внешнюю таблицу значений и заполнить ее, загрузив данные из файлов или вручную. Учтите, что при создании таблицы значений придется типизировать ее колонки с помощью описания типов.
Чтобы поместить описанную таблицу в запрос, придется загрузить ее сначала во временную таблицу, а уже потом соединять с нужными данными. Это правило работы платформы, и если проигнорировать его, то при работе кода 1С выдаст ошибку. Если система сообщает, что данные могут быть выбраны исключительно во временную таблицу, то проверяйте, помещаете ли вы ТЗ в нее.
Чтобы в запросе получилась временная таблица, открыв конструктор запросов, необходимо нажать на специальную кнопку в среднем окне. Нам нужно правильно назвать таблицу и не ошибиться в написании наименования полей. Затем помещаем результат запроса во временную таблицу и во втором запросе из пакета соединяем данные. Этим простым запросом мы добавили таблицу в запрос 1С, состоящую из 1 колонки.
Несмотря на очевидную пользу и простоту, у этой операции есть и определенные правила работы с ТЗ. Опытным путем установлено, что отладка и тестирование использования подобного приема затруднительна. Посмотреть временную таблицу в запросе возможно лишь с помощью типовых функций, заложенных в общие модули, или в консоли запросов. Вторым же правилом является необходимость типизировать колонки таблицы значений при ее объявлении, что зачастую забывают делать разработчики 1С.
Кроме вышеописанного применения программистам 1С приходится загружать таблицу в запрос 1С в сложных участках кода. Это позволяет не выполнять по нескольку раз 1 запрос – его выходной результат сохраняют в таблицу значений. А уже ее используют во всех следующих запросах в коде.
На многих собеседованиях на должность разработчика 1С в крупных компаниях проверяется именно способность грамотно использовать возможности платформы. И если вы продемонстрируете выполнение кода в цикле, а не передадите таблицу значений в запросе 1С, то это будет грубая ошибка.
Читайте также: