1с запрос параметр через точку
На днях писал запрос и наткнулся на интересную особенность при использовании параметров. Если передать параметры ссылочных типов, то к ним можно обращаться как к объектам конфигурации - через оператор "точка". Например: нам необходимо выбрать документы "исполнительные листы" по какой-либо организации. Причем если в качестве параметра передается организация с кодом "01", нам нужно выбрать документы относящееся к организациям с кодами "01", "02", "03", иначе выбрать документы по переданной организации:
В этом запросе мы обращаемся к параметру ссылочного типа "&Организация", мы можем извлечь из этого параметра любую информацию, например: наименование (&Организация.Наименование) или ИНН (&Организация.ИНН), словом все те реквизиты, которые есть в справочнике "Организации". При попытке открыть этот запрос в конструкторе запросов будет выдаваться ошибка, т.к. конструктор считает, что к параметру нельзя так обращаться, но на самом деле запрос РАБОТАЕТ!
Специальные предложения
(0), Интересная находка, но все же предпочитаю, чтобы конструктор запроса не выдавал ошибок о невозможности чтения текста запроса.
О_о. Прикольно. И иногда (насколько часто?) полезно. Сам тоже предпочитаю конструкторопригодный запрос, так что согласен с (2). Но на заметку возьму!
(2) Конструктор иногда сам, например, сгенерит текст, и сам же его открыть не может. Так что в (5) правильно сказано - всякими строковыми играми можно его обмануть и выкрутиться.
(11) 7OH, Какова судьба параметра &другаяОрганизация ?
Еще пример: есть справочник, у него в реквизитах хранятся 2 даты - начало и конец периода (за который предполагается провести некую оценку). Так вот предложенный в (8) приём позволит передать всего один параметр, и спокойно работать с его реквизитами.
Использование лишней временной таблицы, соединение, и все сопутствующие навороты навряд ли добавит читаемости запросу, и, сдается мне, негативно скажется на времени выполнения запроса.
А по поводу Вашего "ну или": в (0) вопрос ставился именно о том, чтобы передавать параметр и обращаться к его реквизитам. В (8) было предложено как при этом сделать запрос пригодным для редактирования конструктором (да и на глаз он сильно страдает). В предложенном Вами варианте нет обращения к реквизитам параметра. В чем "дополнительная возможность использования параметра"? В варианте с "левым соединением" аналогично не будет обращения к реквизитам параметра, да еще и усложнение запроса убавит его читаемости и добавит узких мест (в том смысле, что на лишнем соединении больше шансов накосячить). Кстати: если в том месте, где появится это самое "лишнее" соединение и без того уже есть соединение (нужное, не лишнее), то вероятность накосячить в соединениях многократно возрастает. А обращение к реквизитам параметра позволит спокойно описать все нужные условия или связи.
Хотя могу и заступиться за Ваш способ с соединением: реквизиты параметра (из которого получается таблица из целой одной записи) доступны конструктором. При простом обращении к реквизитам параметра придется писать реквизиты руками, а конструктор будет лишь ругаться, что не нашел такого при неправильном написании, не предлагая правильных вариантов.
(12) ShantinTD, учитывайте, что при каждом обращении через точку, будет еще одна (и одну ли?) временная таблица.
Использование лишней временной таблицы, соединение, и все сопутствующие навороты навряд ли добавит читаемости запросу, и, сдается мне, негативно скажется на времени выполнения запроса.
использование временной таблице скажется хорошо на времени выполнения запроса. Как минимум 1С не придется самой дописывать в запрос эту временную таблицу (а она любит несколько подзапросов строить, для вытаскивания всех данных). К тому же эти подзапросы будут построены на каждое такое обращение.
Еще пример: есть справочник, у него в реквизитах хранятся 2 даты - начало и конец периода (за который предполагается провести некую оценку). Так вот предложенный в (8) приём позволит передать всего один параметр, и спокойно работать с его реквизитами.
Только передаваемый параметр у вас и так в кеше есть, и его реквизиты уже прочитаны в тот момент, когда вы его передаете.
Интересная вещь, не знаю, запомню ли, т.к. для применения они вряд ли будет часто нужна. Но применять может, к сожалению, только в простых запросах, которые легко читать глазами и вручную (без конструктора) исправлять, что, кстати, для программистом с ещё не большим опытом тяжело.
Для возможности редактирования запроса с применением такого приема могу предложить комбинировать его с приемом замены текста.
Поясню: в приведенном в (0) запросе можно написать &Организация_Код, и запрос можно будет открыть редактором. Если произвести в тексте запроса замену (самым простым СтрЗаменить(. )) на &Организация.Код, то получим запрос "с хитростью". А можно и не подменять ничего, а просто передать в запрос несколько "лишних" параметров. Для новичков это должно быть проще, чем редактировать запрос "руками".
А если запрос уже отлажен, "вылизан", и редактировать его больше не предполагается, то можно смело заменить непосредственно в тексте запроса "лишние" параметры так, как предложено в (0).
Сама по себе идея отбора по реквизиту "через точку" - лишнее соединение. Причем справочник "Организации", как правило, невелик, а значит, читаться будет scan'ом.
В то же время когда мы передаем в параметр массив ссылок, соединения с таблицей справочника Организации не будет вообще.
boln; Nuobu; the1; Рамзес; echo77; Puk2; loy; wolfsoft; BigB; serg_gres; Yimaida; bird21; ShantinTD; vde69; + 14 – Ответить
рекомендую использовать (8) так как (0) грозит запросом к метаданным строк этак на 500.
Вообще любые нетипизированые вещи в запросе - зло, именно по этому рекомендуется использовать типизированые ТЗ в качестве параметров.
Кто-нибудь делал замер подобной конструкции по сравнению со стандартным запросом? Подход любопытный, но как это влияет на производительность и какой результирующий запрос будет к SQL-серверу?
Книга "Язык запросов 1С:Предприятие 8" от Хрусталевой и Радченко (2013 год) в разделе про оптимизацию запросов настоятельно рекомендует воздержаться от применения каких-либо функций к передаваемым в запрос параметрам. Лучше все необходимое вычислить снаружи и передать в запрос уже константы.
Даже банальное "НАЧАЛОПЕРИОДА(&ДатаОстатков,ДЕНЬ)" не советуют использовать в тексте запроса.
(14) Damian, это общая рекомендация. На самом деле так делать можно, если понимаешь, что делаешь и сколько раз будет выполнено вычисление значения.
По хорошему такие запросы нужно писать так.
Способ 1. Получаем нужные данные в коде, а не в запросе.
|ВЫБОР
| КОГДА &Организация = &ОсобаяОрганизация
| ТОГДА ИсполнительныйЛист.Организация В (&МассивОгранизаций)
| ИНАЧЕ
| ИсполнительныйЛист.Организация = &Организация
|КОНЕЦ
Запрос.УстановитьПараметр("Организация", Документ.Огранизация);
Запрос.УстановитьПараметр("ОсобаяОрганизация", Справочник.Организации.НайтиПоКоду("01")); // А лучше здесь завести константу или обращаться к регистру сведений.
Запрос.УстановитьПараметр("МассивОгранизаций", СписокОгранизаций);
Способ 2. Избавляемся от сложной конструкции в условии ГДЕ (для СУБД так будет легче).
|ГДЕ
| ИсполнительныйЛист.Организация В (&МассивОгранизаций)
Способ 3. Для тех, случаев, когда избежать обращения через точку не удается.
|ВЫБОР
| КОГДА
| ВЫРАЗИТЬ (&Организация КАК Справочник.Организации).ИНН ПОДОБНО "68465_"
|КОНЕЦ
Хотя, я, наверное, излишне помешан на оптимизации. Работа такая. Приношу извинения.
Применение ВЫРАЗИТЬ здесь никакой смысловой нагрузки не несет, т.к. платформа определяет тип параметра, и он у нас в данном случае простой.
ВЫРАЗИТЬ применяется к полю составного типа для ограничения типов (а следовательно, количества соединений) данных, которые требуют обращения через точку.
Грубо говоря, если у нас есть поле составного типа Регистратор
и мы пишем "ВЫБРАТЬ Регистратор.Дата" то запрос будет состоять из двух соединений:
1) Наша исходная таблица с таблицей Документ.Поступление по равенству поля Ссылка
1) Наша исходная таблица с таблицей Документ.Реализация по равенству поля Ссылка
А если мы напишем "ВЫБРАТЬ ВЫРАЗИТЬ(Регистратор КАК Документ.Реализация).Дата",
то соединение будет только одно:
Наша исходная таблица с таблицей Документ.Реализация по равенству поля Ссылка
второе соединение будет отфильтровано именно применением оператора ВЫРАЗИТЬ
(16), ВЫРАЗИТЬ здесь имеет смысл потому, что я привожу параметр к определенному типу и гарантированно не получу ошибки в запросе при обращении к реквизиту объекта. Кроме того, запрос в конструкторе нормально открывается (автору это, кажется, было важно).
Если вы предпочитаете такую конструкцию
,
то должны в полной мере понимать что это за собой может повлечь.
Про составной тип я не стал грузить, хотя в этом случае приведение к типу для получения значения реквизита стоит использовать почти всегда.
(14), и правильно пишут, причем? не только они. Здесь , под заголовком "Эффективные планы запросов", как раз такой пример и приводится. Хотя, кого это интересует? Лучше ж "на коленке" написать и не думать о последствиях! Если у разработчика база с тремя пользователями, то такое, конечно же, прокатит, и он не заметит разницы.
Интересный момент. По кэшу: на сколько помню, получение ссылки не означает чтение реквизитов. В связи с этим, нужно смотреть контекст выполнения запроса. Если до выполнения реквизиты прочитаны, то смысла изгаляться подобным образом нет. Вред один. А вот если не прочитаны, то потенциально можно получить даже увеличение производительности. Поправьте, если не прав.
(20) omut, насколько помню при получении ссылки в кеш сразу считываются кэшируемые показатели, будем считать, что эти два не кэшируемые. В этом случае в кеш будет считаны все реквизиты ссылки при обращении к первому реквизиту (максимум один запрос в любом случаее). Второй будет считан из кеша. При передачи одного параметра в запрос, при каждом обращении через точку будет добавлен подзапрос. То минимум будет два дополнительных запроса (на каждый реквизит) + столько запросов, сколько раз вы к этим реквизитам обратитесь в запросе.
однако ни "(&СсылкаДокумент).Дата" ни "ВЫРАЗИТЬ(&СсылкаДокумент КАК Документ.КакоНибудь).Дата" не годится для указания в параметре виртуальной таблицы, например. и чо делать. а ведь бывает надо и нередко.
Часто при внедрении программ «1С: Предприятие 8» возникают ситуации, в которых простые запросы работают достаточно медленно.
Покажем варианты оптимизации таких запросов.
Для примера рассмотрим запрос из реального проекта (в базе клиента он выполнялся более 6 секунд)
МЕСЯЦ(ДенежныеСредстваКПоступлениюБезналичныеОбороты.Период) КАК Месяц,
ГОД(ДенежныеСредстваКПоступлениюБезналичныеОбороты.Период) КАК Год,
СУММА(ДенежныеСредстваКПоступлениюБезналичныеОбороты.СуммаПриход) КАК СуммаПриход
РегистрНакопления.ДенежныеСредстваКПоступлениюБезналичные.Обороты(, , Месяц, Документ.Контрагент.Партнер = &Партнер)
C первого взгляда все хорошо, но опытный программист увидит неоптимальный код в запросе.
Источником проблем выступает параметр виртуальной таблицы, а точнее – обращение через «две точки» в фильтре .
В общем случае такой подход допустим, но есть одна проблема: поле «Документ» имеет составной тип, и при получении реквизитов данного поля выполняется соединение с каждой таблицей, входящей в составной тип этого поля .
Самым первым вариантом решения в голову приходит использовать конструкцию языка запросов «ВЫРАЗИТЬ», чтобы привести поле «Документ» к некоторому определенному типу. Это позволит избежать соединений с лишними таблицами. Но по ряду ограничений данный вариант не подходит:
- Нам нужны все документы, содержащиеся в составном типе. Таковы условия постановки задачи. Получается, что необходимо фильтровать все типы документов, входящие в составной тип.
- Даже если бы не было предыдущего ограничения, то обращение через «две точки» никуда не делось.
- Если бы можно было использовать «ВЫРАЗИТЬ», то это не спасало бы ситуацию: в параметрах виртуальной таблицы «ВЫРАЗИТЬ» не дает прироста производительности.
Оптимизация
Исходя из вышесказанного, прежде всего необходимо избавиться от обращения через «две точки» и при этом не испортить саму логику нашего запроса.
Из нескольких способов решения задачи предлагаем два следующих варианта:
Вариант 1
В регистр «ДенежныеСредстваКПоступлениюБезналичные» добавить новое измерение «Партнер», заполняя его при записи движений документов. Ввиду использования условия по данному измерению его необходимо проиндексировать.
После внесенных нами изменений у нас достаточно легко получится наложение фильтра на новое измерение в параметрах виртуальной таблицы:
РегистрНакопления.ДенежныеСредстваКПоступлениюБезналичные.Обороты(, , Месяц, Партнер = &Партнер) КАК
Что мы видим? Этот запрос начинает работать моментально. И это, к сожалению, единственный положительный момент, минусов наблюдается существенно больше. Главный минус – изменение структуры конфигурации, возникают проблемы при последующих обновлениях, использовании типовых обменов и т.д. К тому же у нас хранится дублируемая информация, что приводит к увеличению размера таблицы, а установка признака индексирования повышает скорость чтения, но при этом замедляет запись в регистр. Поэтому рассмотрим второй вариант.
Вариант 2
Можно попробовать изменить запрос так, чтобы фильтр по полю «Документ» накладывался примерно следующим образом:
РегистрНакопления.ДенежныеСредстваКПоступлениюБезналичные.Обороты(, , Месяц, Документ В (ВЫБРАТЬ Ссылка ИЗ
ВТ_ДокументыСПартнером)) КАК ДенежныеСредстваКПоступлениюБезналичныеОбороты
Что необходимо сделать, чтобы наш запрос пришел к подобному виду? Вначале соберем все документы, входящие в составной тип поля «Документы». Для них должно соблюдаться условие:
В нашем составном типе определены 5 документов, причем искомый реквизит «Контрагент» присутствует только в документах:
- ПоступлениеБезналичныхДенежныхСредств
- СписаниеБезналичныхДенежныхСредств
- РасходныйКассовыйОрдер
- ОперацияПоПлатежнойКарте
Далее сформируем временную таблицу для фильтрации. В ней будут документы, у которых реквизит «Партнер» равен нужному значению. Применим полученный фильтр по документам в нашем запросе:
ИЗ Документ.ОперацияПоПлатежнойКарте КАК ОперацияПоПлатежнойКарте
ГДЕ ОперацияПоПлатежнойКарте.Контрагент.Партнер = &Партнер
ИЗ Документ.ПоступлениеБезналичныхДенежныхСредств КАК ПоступлениеБезналичныхДенежныхСредств
ГДЕ ПоступлениеБезналичныхДенежныхСредств.Контрагент.Партнер = &Партнер
ИЗ Документ.РасходныйКассовыйОрдер КАК РасходныйКассовыйОрдер
ГДЕ РасходныйКассовыйОрдер.Контрагент.Партнер = &Партнер
ИЗ Документ.СписаниеБезналичныхДенежныхСредств КАК СписаниеБезналичныхДенежныхСредств
ГДЕ СписаниеБезналичныхДенежныхСредств.Контрагент.Партнер = &Партнер
МЕСЯЦ(ДенежныеСредстваКПоступлениюБезналичныеОбороты.Период) КАК Месяц,
ГОД(ДенежныеСредстваКПоступлениюБезналичныеОбороты.Период) КАК Год,
ДенежныеСредстваКПоступлениюБезналичныеОбороты.СуммаПриход КАК СуммаПриход
РегистрНакопления.ДенежныеСредстваКПоступлениюБезналичные.Обороты(,, Месяц, Документ В
ВТ_ДокументыСПартнером)) КАК ДенежныеСредстваКПоступлениюБезналичныеОбороты
С другой стороны, можно сначала получить контрагентов с данным партнером и затем искать документы с фильтром по контрагенту, но особой разницы в скорости не наблюдается.
После проведенной оптимизации запрос стал выполняться менее одной секунды! Да, при этом он стал сложнее, но нет необходимости в изменении структуры метаданных, как в первом варианте.
Резюме
Вам представлен вариант решения оптимизации достаточно простого запроса, при котором не возникло необходимости в перестройке метаданных, создании дополнительных индексов.
Рекомендуем оптимизировать запросы посредством изменения текста самого запроса.
Анализ плана выполнения запроса с помощью консоли запросов
В этом видео показан наиболее простой способ получения плана выполнения запроса на СУБД – для этого используется официальная консоль запросов от фирмы «1С».
С помощью этого инструмента можно быстро оценить эффективность выполнения запроса и необходимость его оптимизации.
Получение полей через "точку" в запросе
В тестовой конфигурации, в которой будетм реализовывать все примеры в статье, создадим документ "Продажа" и три справочника: "Номенклатура", "ЕдиницыИзмерения" и "БазовыеЕдиницы". Справочник "ЕдиницыИзмерения" подчинен справочнику "Номенклатура". В документе продажи три реквизита: "Номенклатура", "ЕдиницаИзмерения" и "Количество". Первые два ссылаются на элемент соответствующего справочника, "Количество" - числовое поле.
Чтобы проанализировать действия платформы напишем два простых запроса. Первый запрос будет производить выборку ссылки, а также поля "Номенклатура" и "ЕдиницаИзмерения" из документа "Продажи":
Второй запрос будет использовать возможности платформы для выборки полей через "точку" в запросе. Чтобы усложнить пример, сделаем выборку в несколько уровней. В качестве результатирующих полей выборки сделаем ссылку на документ и следующие поля: "Номенклатура", "ЕдиницаИзмерения", "БазоваяЕдиница", "НаименованиеБазовойЕдиницы", "КодБазовойЕдиницы". Текст запроса будет выглядить слеюущим образом:
Результаты выполнения обоих запросов в соответствии с тестовыми данными выглядят следующим образом:
Как мы видим, оба запроса отлично работают. Теперь рассмотрим поведение платформы 1С:Предприятие 8.x, а именно формирование SQL-запроса к СУБД при использовании обращения к полям через "точку" в запросе.
Что делает платформа?
При выполнении первого запроса, 1С:Предприятие формирует достаточно простой SQL-запрос:
В запросе все необходимые данные получаются из одного запроса, поэтому нет необходимости формировать выборки из других таблиц. Если же мы взгяленм на сформированный SQL-запрос для второго примера, картина будет совсем иной:
Как мы видим из приведенного выше текста запроса, каждое обращение через точку в запросе 1С:Предприятия платформа определяет как левое соединение к соответствующей таблице. При этом, если обращение через точку к полям таблицы осуществляется для нескольких полей, то левое соединение выполняется только один раз (что логично). В качестве условий для соединения таблиц используются сравнения по ссылкам.
Плюсы и минусы
Возможности платформы 1С:Предприятия 8.x по построению выборки в запросах через "точку" позволяют упростить построение запросов к базе данных для разработчиков, причем весьма значительно. Согласитель, легче написать в тексте поле через точку от ссылочного типа, чем добавлять, хоть и конструктором, новую таблицу в запрос и прописывать условия соединения. К тому же, это возможность позволяет значительно расширить возможности при настройке отчетов, выводимых полей и прочего. В этом и заключается огромный плюс.
Но есть и другая сторона. Избыточное использование подобной возможности в запросах может значительно повысить нагрузку на сервер СУБД. Все будет зависеть от конкретного запроса. Можно лишь сказать, что нужно стремиться получать выборки данных более оптимальным образом из меньшего количества таблиц.
Небольшой итог
Подведем небольшой итог. Во-первых, использование обращений через "точку" в запросе обрабатываются более оптимально, чем подобные обращения для объектной модели работы с данными. Ранее я писал об этом в одной из статей . Во-вторых, использование подобной возможности значительно ускоряет процесс написания запросов и расширяет возможности настройки отчетов в пользовательском режиме.
При умелом обращении с данным механизмом отрицательное влияние на производительность будет сводиться к нулю. Поэтому не использовать его будет просто не рациональным шагом.
По ссылке Вы можете скачать конфигурацию со всеми примерами из статьи.
Параметры запроса в 1С 8.3 необходимы для оптимизации кода запроса. Параметры бывают простых типов, ссылочных типов, списочных типов, в виде таблиц значений. Чтобы объявить параметра в языке запроса используется символ "&" и название параметра, Например: &ДатаДокумента. Для вставки параметра в запрос, используется функция УстановитьПараметр().
&НаСервере
Процедура ПередачаПараметровПростыхТиповВЗапросе ()
// Создание отбора по поступлению материала за 2020 год
Запрос = Новый Запрос ( "ВЫБРАТЬ
| Ссылка
|ИЗ
| Документ.ПоступлениеМатериалов
|ГДЕ
| Дата МЕЖДУ &НачДата И &КонДата
|УПОРЯДОЧИТЬ ПО
| Дата ВОЗР" );
Запрос . УстановитьПараметр ( "НачДата" , '20200101000000' );
Запрос . УстановитьПараметр ( "КонДата" , '20201231235959' );
РезультатЗапроса = Запрос . Выполнить (); Записи = РезультатЗапроса . Выбрать ();
Пока Записи . Следующий () Цикл
// Обход результата запроса по каждой записи в полученной выборке
КонецЦикла;
&НаСервере
Процедура ПередачаПараметровСсылочныхТиповВЗапросе ()
// Создание отбора по материалам с единицей измерения "Куб.см."
Запрос = Новый Запрос ( "ВЫБРАТЬ
| Наименование,
| ЕдиницаИзмерения
|ИЗ
| Справочник.Материалы
|ГДЕ
| ЕдиницаИзмерения = &ЕдинИзмер" );
Запрос . УстановитьПараметр ( "ЕдинИзмер" , Справочники . ЕдиницыИзмерения . НайтиПоНаименованию ( "Куб.см." ));
РезультатЗапроса = Запрос . Выполнить (); Записи = РезультатЗапроса . Выбрать ();
Пока Записи . Следующий () Цикл
// Обход результата запроса по каждой записи в полученной выборке
КонецЦикла;
&НаСервере
Процедура ПередачаПараметровСписочногоТипаВЗапросе ()
// Создание отбора по материалам, единицы измерения входят в переданный список
Запрос = Новый Запрос ( "ВЫБРАТЬ
| Наименование,
| ЕдиницаИзмерения
|ИЗ
| Справочник.Материалы
|ГДЕ
| ЕдиницаИзмерения В (&СписокЕдиницИзмерения)" );
СписокЕИ = Новый Массив ;
СписокЕИ . Добавить ( Справочники . ЕдиницыИзмерения . НайтиПоНаименованию ( "Куб.см." ));
СписокЕИ . Добавить ( Справочники . ЕдиницыИзмерения . НайтиПоНаименованию ( "Куб.дм." ));
СписокЕИ . Добавить ( Справочники . ЕдиницыИзмерения . НайтиПоНаименованию ( "Куб.м." ));
Запрос . УстановитьПараметр ( "СписокЕдиницИзмерения" , СписокЕИ );
РезультатЗапроса = Запрос . Выполнить (); Записи = РезультатЗапроса . Выбрать ();
Пока Записи . Следующий () Цикл
// Обход результата запроса по каждой записи в полученной выборке
КонецЦикла;
&НаСервере
Процедура ПередачаПараметраВВидеТаблицыЗначенийВЗапросе ()
// Создание отбора по материалам в соответствии с параметром в виде
// комбинированной таблицы значений: "Срок Использования" и "Производитель"
ТЗ_СрокИсп_Произв = новый ТаблицаЗначений ;
ТЗ_СрокИсп_Произв . Колонки . Добавить ( "СрокИспользования" , Новый ОписаниеТипов ( "СправочникСсылка.КлассификаторСроковПИ" ));
ТЗ_СрокИсп_Произв . Колонки . Добавить ( "Производитель" , Новый ОписаниеТипов ( "СправочникСсылка.Контрагенты" ));
// "12 месяцев" + "Гомелькабель"
СтрокаТЗ = ТЗ_СрокИсп_Произв . Добавить ();
СтрокаТЗ . СрокИспользования = Справочники . КлассификаторСроковПИ . НайтиПоНаименованию ( "12 месяцев" );
СтрокаТЗ . Производитель = Справочники . Контрагенты . НайтиПоНаименованию ( "Гомелькабель" );
// "18 месяцев" + "Гомельстекло"
СтрокаТЗ = ТЗ_СрокИсп_Произв . Добавить ();
СтрокаТЗ . СрокИспользования = Справочники . КлассификаторСроковПИ . НайтиПоНаименованию ( "18 месяцев" );
СтрокаТЗ . Производитель = Справочники . Контрагенты . НайтиПоНаименованию ( "Гомельстекло" );
Запрос = Новый Запрос ( "ВЫБРАТЬ
| Наименование,
| СрокИспользования,
| Производитель
|ИЗ
| Справочник.Материалы
|ГДЕ
| (СрокИспользования, Производитель) В (&СписокСочетаний)" );
Запрос . УстановитьПараметр ( "СписокСочетаний" , ТЗ_СрокИсп_Произв );
РезультатЗапроса = Запрос . Выполнить (); Записи = РезультатЗапроса . Выбрать ();
Пока Записи . Следующий () Цикл
// Обход результата запроса по каждой записи в полученной выборке
КонецЦикла;
&НаСервере
Процедура ИспользованиеТаблицыЗначенийПереданнойВЗапросКакПараметр ()
// Программное создание Таблицы Значений и передача её в запрос
ДрагМеталл = новый ТаблицаЗначений ;
ДрагМеталл . Колонки . Добавить ( "Название" , Новый ОписаниеТипов ( "Строка" ));
ДрагМеталл . Колонки . Добавить ( "РынЦена" , Новый ОписаниеТипов ( "Число" ));
НоваяСтрока = ДрагМеталл . Добавить ();
НоваяСтрока . Название = "Золото" ;
НоваяСтрока . РынЦена = 127.29 ;
НоваяСтрока = ДрагМеталл . Добавить ();
НоваяСтрока . Название = "Серебро" ;
НоваяСтрока . РынЦена = 1.30 ;
НоваяСтрока = ДрагМеталл . Добавить ();
НоваяСтрока . Название = "Платина" ;
НоваяСтрока . РынЦена = 62. 00 ;
НоваяСтрока = ДрагМеталл . Добавить ();
НоваяСтрока . Название = "Родий" ;
НоваяСтрока . РынЦена = 568.27 ;
// Сперва выбираем данные во временную таблицу, а потом работаем как с обычной таблицей
Запрос = Новый Запрос ( "ВЫБРАТЬ
| Название,
| РынЦена
|ПОМЕСТИТЬ
| ВременнаяТаблица
|ИЗ
| &ТаблицаДрагМеталлов КАК ДрагМеталлы
|;
|ВЫБРАТЬ
| Название,
| РынЦена
|ИЗ
| ВременнаяТаблица
|УПОРЯДОЧИТЬ ПО
| РынЦена УБЫВ" );
Запрос . УстановитьПараметр ( "ТаблицаДрагМеталлов" , ДрагМеталл );
РезультатЗапроса = Запрос . Выполнить (); Записи = РезультатЗапроса . Выбрать ();
Пока Записи . Следующий () Цикл
// Обход результата запроса по каждой записи в полученной выборке
КонецЦикла;
Войдите как ученик, чтобы получить доступ к материалам школы
Язык запросов 1С 8.3 для начинающих программистов: функции и операторы для работы с типами (ТИПЗНАЧЕНИЯ, ТИП, ССЫЛКА, ЕСТЬNULL, ВЫРАЗИТЬ)
Автор уроков и преподаватель школы: Владимир Милькин
Давайте вспомним, что каждый реквизит (свойство, поле) справочника, документа или любого другого прикладного объекта имеет свой тип . И этот тип мы можем посмотреть в конфигураторе:
В языке запросов существует целый класс функций и операторов для работы с типами реквизитов. Давайте рассмотрим их.
Функция ТИПЗНАЧЕНИЯ
Эта функция принимает один параметр (значение) и возвращает его тип. Для описанного на картинке (выше) реквизита Вкус справочника Еда вернётся следующее:
Если мы запросим тип поля Наименование, то, как и ожидается, получим Строка:
А теперь давайте рассмотрим реквизит ОтличительныйПризнак у справочника Города:
Вы видите, что этот реквизит может иметь один из нескольких типов: Строка, Справочник.Вкусы, Справочник.Цвета. Такой тип реквизитов называется СОСТАВНЫМ .
Если мы попытаемся заполнить значение такого реквизита в режиме 1С:Предприятие, то система спросит нас, какого типа будет вводимое значение:
И только после нашего выбора позволит ввести значение выбранного типа.
Таким образом, элементы справочника одного вида (Справочник.Города) смогут хранить в одном и том же реквизите (ОтличительныйПризнак) значения разных типов (Строка, Цвета или Вкусы).
Вы можете убедиться в этом сами пощёлкав по элементам справочника Города в режиме 1С:Предприятие. Вы читаете ознакомительную версию урока, полноценные уроки находятся здесь.
Здесь значение отличительного признака является элементом справочника Вкусы:
А здесь вообще элементом справочника Цвета:
Вот какие возможности открывает перед нами составной тип данных!
Интересно, как поведёт себя функция ТИПЗНАЧЕНИЯ на реквизите ОтличительныйПризнак, имеющий составной тип данных:
Это уже очень интересно. Давайте разбираться с каждой строкой в отдельности.
Тип значения отличительного признака для элемента Россия равен NULL. Мы впервые сталкиваемся с этим типом. Значения данного типа используются исключительно для определения отсутствующего значения при работе с базой данных.
Так и есть, ведь элемент Россия является группой, а не обычным элементом справочника Города, поэтому у него отсутствует поле ОтличительныйПризнак. А тип у отсутствующего значения, как мы прочитали выше, всегда равен NULL.
Тип значения отличительного признака для Перми равен Вкусы. Так и есть, ведь значение отличительного признака забитое в базе для города Пермь является ссылкой на элемент справочника Вкусы.
Для Красноярска тип признака равен Цвета, потому что значение выбранное в базе является ссылкой на элемент справочника Цвета.
Для Воронежа тип признака равен Строка, потому что значение введенное в базе является обычной строкой.
Индия снова группа, поэтому значение отсутствует. А тип у отсутствующего значения, как мы помним, равен NULL.
Далее всё аналогично, кроме Сан-Паулу. Это не группа, а обычный элемент справочника (город), но тип его значения пустой. Как так?
А дело вот в чём. Если вы зайдёте в элемент справочника Города с наименованием Сан-Паулу, то увидите, что поле ОтличительныйПризнак совершенно никак не заполнено. Оно пустое. А все незаполненные поля составного типа имеют специальное значение НЕОПРЕДЕЛЕНО .
С НЕОПРЕДЕЛЕНО мы также сталкиваемся впервые.
Значение НЕОПРЕДЕЛЕНО применяется, когда необходимо использовать пустое значение, не принадлежащее ни к одному другому типу. Это как раз наша ситуация.
А тип для значения, которое не принадлежит ни к одному из типов, как вы уже наверное догадались отсутствует.
Функция ТИП
Она принимает всего один параметр - имя примитивного типа (СТРОКА, ЧИСЛО, ДАТА, БУЛЕВО), либо имя таблицы, тип ссылки которой нужно получить.
Результатом данной конструкции будет значение типа Тип для указанного типа.
Звучит туманно, не правда ли?
Давайте рассмотрим применение данной конструкции и всё сразу станет на свои места.
Пусть нам требуется отобрать все записи справочника Города, у которых составной реквизит ОтличительныйПризнак имеет значение типа СТРОКА:
Теперь давайте отберём все записи, у которых значения реквизита ОтличительныйПризнак являются ссылками на элементы справочника Цвета (таблица Справочник.Цвета):
Отступление
Как вы помните, некоторые элементы справочника Города не имеют реквизита ОтличительныйПризнак. Функция ТИПЗНАЧЕНИЯ для таких элементов выдаёт NULL.
Как можно сделать отбор таких элементов в запросе? Для этого предусмотрен специальный логический оператор ЕСТЬ NULL (не путать с функцией ЕСТЬNULL, которую мы рассмотрим ниже). Вы читаете ознакомительную версию урока, полноценные уроки находятся здесь.
Вот пример его использования:
Но есть и такие элементы (Сан-Паулу), у которых реквизит ОтличительныйПризнак (составного типа) просто не заполнен и равен специальному значению НЕОПРЕДЕЛЕНО.
Чтобы отобрать такие записи следует использовать другую конструкцию:
Но сравнение с НЕОПРЕДЕЛЕНО для определения пустых (не заполненных) реквизитов будет работать только для составных типов.
Кстати, у логического оператора ЕСТЬ NULL форма отрицания выглядит следующим образом:
Логический оператор ССЫЛКА
Оператор ССЫЛКА позволяет проверить, является ли значение выражения, указанного слева от него, ссылкой на таблицу , указанную справа.
К примеру, давайте выберем из справочника Города только те записи, у которых значение составного реквизита ОтличительныйПризнак являются ссылкой на элемент справочника Вкусы:
Как вы помните, эту же задачу мы могли бы решить используя ТИПЗНАЧЕНИЯ и ТИП:
Функция ЕСТЬNULL
Функция предназначена для замены значения NULL на другое значение.
Мы помним, что значение NULL возвращается в том случае, если запрашиваемый реквизит (поле, свойство) не существует.
Как например, реквизит ОтличительныйПризнак для групп справочника Города:
Функция ЕСТЬNULL поможет нам вывести другое значение в том случае, если это значение равно NULL. Вы читаете ознакомительную версию урока, полноценные уроки находятся здесь. Пусть в данном случае это будет строка "Такого реквизита нет!":
Получается, что если первый параметр функции ЕСТЬNULL не равен NULL, то возвращается он. Если же он равен NULL, то возвращается второй параметр.
Функция ВЫРАЗИТЬ
Эта функция предназначена только для полей , имеющих составной тип . Отличным примером такого поля является свойство ОтличительныйПризнак у элементов справочника Города.
Как мы помним, составные поля могут быть одного из нескольких типов, указанных в конфигураторе.
Для поля ОтличительныйПризнак такими допустимыми типами являются СТРОКА, Справочник.Цвета и Справочник.Вкусы.
Иногда возникает необходимость привести значения составного поля к какому-либо определенному типу.
Давайте приведём все значения поля ОтличительныйПризнак к типу Справочник.Цвета:
В результате, все значения элементов, которые имели тип Справочник.Цвета, остались заполненными и оказались приведенными к указанному типу. Все значения других типов (СТРОКА, Справочник.Вкусы) теперь стали равны NULL. В этом состоит особенность приведения типа при помощи функции ВЫРАЗИТЬ.
Приводить тип можно или к примитивному типу (БУЛЕВО, ЧИСЛО, СТРОКА, ДАТА) или к ссылочному типу. Вы читаете ознакомительную версию урока, полноценные уроки находятся здесь. Но тип, к которому делается приведение, обязательно должен входить в список типов для данного составного поля, иначе система выдаст ошибку.
Пройдите тест
Не все реквизиты справочников или документов имеют свой тип, но те что имеют можно посмотреть в конфигураторе
Не все реквизиты справочников или документов имеют свой тип, но те что имеют можно посмотреть в режиме 1С:Предприятие
Каждый реквизит справочника или документа имеет свой тип, который можно посмотреть в режиме 1С:Предприятие
Читайте также: